4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isFirefox = ua.indexOf("firefox") > -1,
57 isIE = ua.indexOf("msie") > -1,
58 isIE7 = ua.indexOf("msie 7") > -1,
59 isIE11 = /trident.*rv\:11\./.test(ua),
60 isGecko = !isSafari && ua.indexOf("gecko") > -1,
61 isBorderBox = isIE && !isStrict,
62 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
63 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
64 isLinux = (ua.indexOf("linux") != -1),
65 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
66 isIOS = /iphone|ipad/.test(ua),
67 isTouch = (function() {
69 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
70 window.addEventListener('touchstart', function __set_has_touch__ () {
72 window.removeEventListener('touchstart', __set_has_touch__);
74 return false; // no touch on chrome!?
76 document.createEvent("TouchEvent");
83 // remove css image flicker
86 document.execCommand("BackgroundImageCache", false, true);
92 * True if the browser is in strict mode
97 * True if the page is running over SSL
102 * True when the document is fully initialized and ready for action
107 * Turn on debugging output (currently only the factory uses this)
114 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
117 enableGarbageCollector : true,
120 * True to automatically purge event listeners after uncaching an element (defaults to false).
121 * Note: this only happens if enableGarbageCollector is true.
124 enableListenerCollection:false,
127 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
128 * the IE insecure content warning (defaults to javascript:false).
131 SSL_SECURE_URL : "javascript:false",
134 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
135 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
138 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
140 emptyFn : function(){},
143 * Copies all the properties of config to obj if they don't already exist.
144 * @param {Object} obj The receiver of the properties
145 * @param {Object} config The source of the properties
146 * @return {Object} returns obj
148 applyIf : function(o, c){
151 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
158 * Applies event listeners to elements by selectors when the document is ready.
159 * The event name is specified with an @ suffix.
162 // add a listener for click on all anchors in element with id foo
163 '#foo a@click' : function(e, t){
167 // add the same listener to multiple selectors (separated by comma BEFORE the @)
168 '#foo a, #bar span.some-class@mouseover' : function(){
173 * @param {Object} obj The list of behaviors to apply
175 addBehaviors : function(o){
177 Roo.onReady(function(){
182 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
184 var parts = b.split('@');
185 if(parts[1]){ // for Object prototype breakers
188 cache[s] = Roo.select(s);
190 cache[s].on(parts[1], o[b]);
197 * Generates unique ids. If the element already has an id, it is unchanged
198 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
199 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
200 * @return {String} The generated Id.
202 id : function(el, prefix){
203 prefix = prefix || "roo-gen";
205 var id = prefix + (++idSeed);
206 return el ? (el.id ? el.id : (el.id = id)) : id;
211 * Extends one class with another class and optionally overrides members with the passed literal. This class
212 * also adds the function "override()" to the class that can be used to override
213 * members on an instance.
214 * @param {Object} subclass The class inheriting the functionality
215 * @param {Object} superclass The class being extended
216 * @param {Object} overrides (optional) A literal with members
221 var io = function(o){
226 return function(sb, sp, overrides){
227 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
230 sb = function(){sp.apply(this, arguments);};
232 var F = function(){}, sbp, spp = sp.prototype;
234 sbp = sb.prototype = new F();
238 if(spp.constructor == Object.prototype.constructor){
243 sb.override = function(o){
247 Roo.override(sb, overrides);
253 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
255 Roo.override(MyClass, {
256 newMethod1: function(){
259 newMethod2: function(foo){
264 * @param {Object} origclass The class to override
265 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
266 * containing one or more methods.
269 override : function(origclass, overrides){
271 var p = origclass.prototype;
272 for(var method in overrides){
273 p[method] = overrides[method];
278 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
280 Roo.namespace('Company', 'Company.data');
281 Company.Widget = function() { ... }
282 Company.data.CustomStore = function(config) { ... }
284 * @param {String} namespace1
285 * @param {String} namespace2
286 * @param {String} etc
289 namespace : function(){
290 var a=arguments, o=null, i, j, d, rt;
291 for (i=0; i<a.length; ++i) {
295 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
296 for (j=1; j<d.length; ++j) {
297 o[d[j]]=o[d[j]] || {};
303 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
305 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
306 Roo.factory(conf, Roo.data);
308 * @param {String} classname
309 * @param {String} namespace (optional)
313 factory : function(c, ns)
315 // no xtype, no ns or c.xns - or forced off by c.xns
316 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
319 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
320 if (c.constructor == ns[c.xtype]) {// already created...
324 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
325 var ret = new ns[c.xtype](c);
329 c.xns = false; // prevent recursion..
333 * Logs to console if it can.
335 * @param {String|Object} string
340 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
347 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
351 urlEncode : function(o){
357 var ov = o[key], k = Roo.encodeURIComponent(key);
358 var type = typeof ov;
359 if(type == 'undefined'){
361 }else if(type != "function" && type != "object"){
362 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
363 }else if(ov instanceof Array){
365 for(var i = 0, len = ov.length; i < len; i++) {
366 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
377 * Safe version of encodeURIComponent
378 * @param {String} data
382 encodeURIComponent : function (data)
385 return encodeURIComponent(data);
386 } catch(e) {} // should be an uri encode error.
388 if (data == '' || data == null){
391 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
392 function nibble_to_hex(nibble){
393 var chars = '0123456789ABCDEF';
394 return chars.charAt(nibble);
396 data = data.toString();
398 for(var i=0; i<data.length; i++){
399 var c = data.charCodeAt(i);
400 var bs = new Array();
403 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
404 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
405 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
406 bs[3] = 0x80 | (c & 0x3F);
407 }else if (c > 0x800){
409 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
410 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
411 bs[2] = 0x80 | (c & 0x3F);
414 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
415 bs[1] = 0x80 | (c & 0x3F);
420 for(var j=0; j<bs.length; j++){
422 var hex = nibble_to_hex((b & 0xF0) >>> 4)
423 + nibble_to_hex(b &0x0F);
432 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
433 * @param {String} string
434 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
435 * @return {Object} A literal with members
437 urlDecode : function(string, overwrite){
438 if(!string || !string.length){
442 var pairs = string.split('&');
443 var pair, name, value;
444 for(var i = 0, len = pairs.length; i < len; i++){
445 pair = pairs[i].split('=');
446 name = decodeURIComponent(pair[0]);
447 value = decodeURIComponent(pair[1]);
448 if(overwrite !== true){
449 if(typeof obj[name] == "undefined"){
451 }else if(typeof obj[name] == "string"){
452 obj[name] = [obj[name]];
453 obj[name].push(value);
455 obj[name].push(value);
465 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
466 * passed array is not really an array, your function is called once with it.
467 * The supplied function is called with (Object item, Number index, Array allItems).
468 * @param {Array/NodeList/Mixed} array
469 * @param {Function} fn
470 * @param {Object} scope
472 each : function(array, fn, scope){
473 if(typeof array.length == "undefined" || typeof array == "string"){
476 for(var i = 0, len = array.length; i < len; i++){
477 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
482 combine : function(){
483 var as = arguments, l = as.length, r = [];
484 for(var i = 0; i < l; i++){
486 if(a instanceof Array){
488 }else if(a.length !== undefined && !a.substr){
489 r = r.concat(Array.prototype.slice.call(a, 0));
498 * Escapes the passed string for use in a regular expression
499 * @param {String} str
502 escapeRe : function(s) {
503 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
507 callback : function(cb, scope, args, delay){
508 if(typeof cb == "function"){
510 cb.defer(delay, scope, args || []);
512 cb.apply(scope, args || []);
518 * Return the dom node for the passed string (id), dom node, or Roo.Element
519 * @param {String/HTMLElement/Roo.Element} el
520 * @return HTMLElement
522 getDom : function(el){
526 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
530 * Shorthand for {@link Roo.ComponentMgr#get}
532 * @return Roo.Component
534 getCmp : function(id){
535 return Roo.ComponentMgr.get(id);
538 num : function(v, defaultValue){
539 if(typeof v != 'number'){
545 destroy : function(){
546 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
550 as.removeAllListeners();
554 if(typeof as.purgeListeners == 'function'){
557 if(typeof as.destroy == 'function'){
564 // inpired by a similar function in mootools library
566 * Returns the type of object that is passed in. If the object passed in is null or undefined it
567 * return false otherwise it returns one of the following values:<ul>
568 * <li><b>string</b>: If the object passed is a string</li>
569 * <li><b>number</b>: If the object passed is a number</li>
570 * <li><b>boolean</b>: If the object passed is a boolean value</li>
571 * <li><b>function</b>: If the object passed is a function reference</li>
572 * <li><b>object</b>: If the object passed is an object</li>
573 * <li><b>array</b>: If the object passed is an array</li>
574 * <li><b>regexp</b>: If the object passed is a regular expression</li>
575 * <li><b>element</b>: If the object passed is a DOM Element</li>
576 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
577 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
578 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
579 * @param {Mixed} object
583 if(o === undefined || o === null){
590 if(t == 'object' && o.nodeName) {
592 case 1: return 'element';
593 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
596 if(t == 'object' || t == 'function') {
597 switch(o.constructor) {
598 case Array: return 'array';
599 case RegExp: return 'regexp';
601 if(typeof o.length == 'number' && typeof o.item == 'function') {
609 * Returns true if the passed value is null, undefined or an empty string (optional).
610 * @param {Mixed} value The value to test
611 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
614 isEmpty : function(v, allowBlank){
615 return v === null || v === undefined || (!allowBlank ? v === '' : false);
623 isFirefox : isFirefox,
633 isBorderBox : isBorderBox,
635 isWindows : isWindows,
646 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
647 * you may want to set this to true.
650 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
655 * Selects a single element as a Roo Element
656 * This is about as close as you can get to jQuery's $('do crazy stuff')
657 * @param {String} selector The selector/xpath query
658 * @param {Node} root (optional) The start of the query (defaults to document).
659 * @return {Roo.Element}
661 selectNode : function(selector, root)
663 var node = Roo.DomQuery.selectNode(selector,root);
664 return node ? Roo.get(node) : new Roo.Element(false);
672 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
673 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
676 "Roo.bootstrap.dash");
679 * Ext JS Library 1.1.1
680 * Copyright(c) 2006-2007, Ext JS, LLC.
682 * Originally Released Under LGPL - original licence link has changed is not relivant.
685 * <script type="text/javascript">
689 // wrappedn so fnCleanup is not in global scope...
691 function fnCleanUp() {
692 var p = Function.prototype;
693 delete p.createSequence;
695 delete p.createDelegate;
696 delete p.createCallback;
697 delete p.createInterceptor;
699 window.detachEvent("onunload", fnCleanUp);
701 window.attachEvent("onunload", fnCleanUp);
708 * These functions are available on every Function object (any JavaScript function).
710 Roo.apply(Function.prototype, {
712 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
713 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
714 * Will create a function that is bound to those 2 args.
715 * @return {Function} The new function
717 createCallback : function(/*args...*/){
718 // make args available, in function below
719 var args = arguments;
722 return method.apply(window, args);
727 * Creates a delegate (callback) that sets the scope to obj.
728 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
729 * Will create a function that is automatically scoped to this.
730 * @param {Object} obj (optional) The object for which the scope is set
731 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
732 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
733 * if a number the args are inserted at the specified position
734 * @return {Function} The new function
736 createDelegate : function(obj, args, appendArgs){
739 var callArgs = args || arguments;
740 if(appendArgs === true){
741 callArgs = Array.prototype.slice.call(arguments, 0);
742 callArgs = callArgs.concat(args);
743 }else if(typeof appendArgs == "number"){
744 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
745 var applyArgs = [appendArgs, 0].concat(args); // create method call params
746 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
748 return method.apply(obj || window, callArgs);
753 * Calls this function after the number of millseconds specified.
754 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
755 * @param {Object} obj (optional) The object for which the scope is set
756 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
757 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
758 * if a number the args are inserted at the specified position
759 * @return {Number} The timeout id that can be used with clearTimeout
761 defer : function(millis, obj, args, appendArgs){
762 var fn = this.createDelegate(obj, args, appendArgs);
764 return setTimeout(fn, millis);
770 * Create a combined function call sequence of the original function + the passed function.
771 * The resulting function returns the results of the original function.
772 * The passed fcn is called with the parameters of the original function
773 * @param {Function} fcn The function to sequence
774 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
775 * @return {Function} The new function
777 createSequence : function(fcn, scope){
778 if(typeof fcn != "function"){
783 var retval = method.apply(this || window, arguments);
784 fcn.apply(scope || this || window, arguments);
790 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
791 * The resulting function returns the results of the original function.
792 * The passed fcn is called with the parameters of the original function.
794 * @param {Function} fcn The function to call before the original
795 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
796 * @return {Function} The new function
798 createInterceptor : function(fcn, scope){
799 if(typeof fcn != "function"){
806 if(fcn.apply(scope || this || window, arguments) === false){
809 return method.apply(this || window, arguments);
815 * Ext JS Library 1.1.1
816 * Copyright(c) 2006-2007, Ext JS, LLC.
818 * Originally Released Under LGPL - original licence link has changed is not relivant.
821 * <script type="text/javascript">
824 Roo.applyIf(String, {
829 * Escapes the passed string for ' and \
830 * @param {String} string The string to escape
831 * @return {String} The escaped string
834 escape : function(string) {
835 return string.replace(/('|\\)/g, "\\$1");
839 * Pads the left side of a string with a specified character. This is especially useful
840 * for normalizing number and date strings. Example usage:
842 var s = String.leftPad('123', 5, '0');
843 // s now contains the string: '00123'
845 * @param {String} string The original string
846 * @param {Number} size The total length of the output string
847 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
848 * @return {String} The padded string
851 leftPad : function (val, size, ch) {
852 var result = new String(val);
853 if(ch === null || ch === undefined || ch === '') {
856 while (result.length < size) {
857 result = ch + result;
863 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
864 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
866 var cls = 'my-class', text = 'Some text';
867 var s = String.format('<div class="{0}">{1}</div>', cls, text);
868 // s now contains the string: '<div class="my-class">Some text</div>'
870 * @param {String} string The tokenized string to be formatted
871 * @param {String} value1 The value to replace token {0}
872 * @param {String} value2 Etc...
873 * @return {String} The formatted string
876 format : function(format){
877 var args = Array.prototype.slice.call(arguments, 1);
878 return format.replace(/\{(\d+)\}/g, function(m, i){
879 return Roo.util.Format.htmlEncode(args[i]);
885 * Utility function that allows you to easily switch a string between two alternating values. The passed value
886 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
887 * they are already different, the first value passed in is returned. Note that this method returns the new value
888 * but does not change the current string.
890 // alternate sort directions
891 sort = sort.toggle('ASC', 'DESC');
893 // instead of conditional logic:
894 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
896 * @param {String} value The value to compare to the current string
897 * @param {String} other The new value to use if the string already equals the first value passed in
898 * @return {String} The new value
901 String.prototype.toggle = function(value, other){
902 return this == value ? other : value;
905 * Ext JS Library 1.1.1
906 * Copyright(c) 2006-2007, Ext JS, LLC.
908 * Originally Released Under LGPL - original licence link has changed is not relivant.
911 * <script type="text/javascript">
917 Roo.applyIf(Number.prototype, {
919 * Checks whether or not the current number is within a desired range. If the number is already within the
920 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
921 * exceeded. Note that this method returns the constrained value but does not change the current number.
922 * @param {Number} min The minimum number in the range
923 * @param {Number} max The maximum number in the range
924 * @return {Number} The constrained value if outside the range, otherwise the current value
926 constrain : function(min, max){
927 return Math.min(Math.max(this, min), max);
931 * Ext JS Library 1.1.1
932 * Copyright(c) 2006-2007, Ext JS, LLC.
934 * Originally Released Under LGPL - original licence link has changed is not relivant.
937 * <script type="text/javascript">
942 Roo.applyIf(Array.prototype, {
945 * Checks whether or not the specified object exists in the array.
946 * @param {Object} o The object to check for
947 * @return {Number} The index of o in the array (or -1 if it is not found)
949 indexOf : function(o){
950 for (var i = 0, len = this.length; i < len; i++){
951 if(this[i] == o) { return i; }
957 * Removes the specified object from the array. If the object is not found nothing happens.
958 * @param {Object} o The object to remove
960 remove : function(o){
961 var index = this.indexOf(o);
963 this.splice(index, 1);
967 * Map (JS 1.6 compatibility)
968 * @param {Function} function to call
972 var len = this.length >>> 0;
973 if (typeof fun != "function") {
974 throw new TypeError();
976 var res = new Array(len);
977 var thisp = arguments[1];
978 for (var i = 0; i < len; i++)
981 res[i] = fun.call(thisp, this[i], i, this);
994 * Ext JS Library 1.1.1
995 * Copyright(c) 2006-2007, Ext JS, LLC.
997 * Originally Released Under LGPL - original licence link has changed is not relivant.
1000 * <script type="text/javascript">
1006 * The date parsing and format syntax is a subset of
1007 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1008 * supported will provide results equivalent to their PHP versions.
1010 * Following is the list of all currently supported formats:
1013 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1015 Format Output Description
1016 ------ ---------- --------------------------------------------------------------
1017 d 10 Day of the month, 2 digits with leading zeros
1018 D Wed A textual representation of a day, three letters
1019 j 10 Day of the month without leading zeros
1020 l Wednesday A full textual representation of the day of the week
1021 S th English ordinal day of month suffix, 2 chars (use with j)
1022 w 3 Numeric representation of the day of the week
1023 z 9 The julian date, or day of the year (0-365)
1024 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1025 F January A full textual representation of the month
1026 m 01 Numeric representation of a month, with leading zeros
1027 M Jan Month name abbreviation, three letters
1028 n 1 Numeric representation of a month, without leading zeros
1029 t 31 Number of days in the given month
1030 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1031 Y 2007 A full numeric representation of a year, 4 digits
1032 y 07 A two digit representation of a year
1033 a pm Lowercase Ante meridiem and Post meridiem
1034 A PM Uppercase Ante meridiem and Post meridiem
1035 g 3 12-hour format of an hour without leading zeros
1036 G 15 24-hour format of an hour without leading zeros
1037 h 03 12-hour format of an hour with leading zeros
1038 H 15 24-hour format of an hour with leading zeros
1039 i 05 Minutes with leading zeros
1040 s 01 Seconds, with leading zeros
1041 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1042 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1043 T CST Timezone setting of the machine running the code
1044 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1047 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1049 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1050 document.write(dt.format('Y-m-d')); //2007-01-10
1051 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1052 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1055 * Here are some standard date/time patterns that you might find helpful. They
1056 * are not part of the source of Date.js, but to use them you can simply copy this
1057 * block of code into any script that is included after Date.js and they will also become
1058 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1061 ISO8601Long:"Y-m-d H:i:s",
1062 ISO8601Short:"Y-m-d",
1064 LongDate: "l, F d, Y",
1065 FullDateTime: "l, F d, Y g:i:s A",
1068 LongTime: "g:i:s A",
1069 SortableDateTime: "Y-m-d\\TH:i:s",
1070 UniversalSortableDateTime: "Y-m-d H:i:sO",
1077 var dt = new Date();
1078 document.write(dt.format(Date.patterns.ShortDate));
1083 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1084 * They generate precompiled functions from date formats instead of parsing and
1085 * processing the pattern every time you format a date. These functions are available
1086 * on every Date object (any javascript function).
1088 * The original article and download are here:
1089 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1096 Returns the number of milliseconds between this date and date
1097 @param {Date} date (optional) Defaults to now
1098 @return {Number} The diff in milliseconds
1099 @member Date getElapsed
1101 Date.prototype.getElapsed = function(date) {
1102 return Math.abs((date || new Date()).getTime()-this.getTime());
1104 // was in date file..
1108 Date.parseFunctions = {count:0};
1110 Date.parseRegexes = [];
1112 Date.formatFunctions = {count:0};
1115 Date.prototype.dateFormat = function(format) {
1116 if (Date.formatFunctions[format] == null) {
1117 Date.createNewFormat(format);
1119 var func = Date.formatFunctions[format];
1120 return this[func]();
1125 * Formats a date given the supplied format string
1126 * @param {String} format The format string
1127 * @return {String} The formatted date
1130 Date.prototype.format = Date.prototype.dateFormat;
1133 Date.createNewFormat = function(format) {
1134 var funcName = "format" + Date.formatFunctions.count++;
1135 Date.formatFunctions[format] = funcName;
1136 var code = "Date.prototype." + funcName + " = function(){return ";
1137 var special = false;
1139 for (var i = 0; i < format.length; ++i) {
1140 ch = format.charAt(i);
1141 if (!special && ch == "\\") {
1146 code += "'" + String.escape(ch) + "' + ";
1149 code += Date.getFormatCode(ch);
1152 /** eval:var:zzzzzzzzzzzzz */
1153 eval(code.substring(0, code.length - 3) + ";}");
1157 Date.getFormatCode = function(character) {
1158 switch (character) {
1160 return "String.leftPad(this.getDate(), 2, '0') + ";
1162 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1164 return "this.getDate() + ";
1166 return "Date.dayNames[this.getDay()] + ";
1168 return "this.getSuffix() + ";
1170 return "this.getDay() + ";
1172 return "this.getDayOfYear() + ";
1174 return "this.getWeekOfYear() + ";
1176 return "Date.monthNames[this.getMonth()] + ";
1178 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1180 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1182 return "(this.getMonth() + 1) + ";
1184 return "this.getDaysInMonth() + ";
1186 return "(this.isLeapYear() ? 1 : 0) + ";
1188 return "this.getFullYear() + ";
1190 return "('' + this.getFullYear()).substring(2, 4) + ";
1192 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1194 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1196 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1198 return "this.getHours() + ";
1200 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1202 return "String.leftPad(this.getHours(), 2, '0') + ";
1204 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1206 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1208 return "this.getGMTOffset() + ";
1210 return "this.getGMTColonOffset() + ";
1212 return "this.getTimezone() + ";
1214 return "(this.getTimezoneOffset() * -60) + ";
1216 return "'" + String.escape(character) + "' + ";
1221 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1222 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1223 * the date format that is not specified will default to the current date value for that part. Time parts can also
1224 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1225 * string or the parse operation will fail.
1228 //dt = Fri May 25 2007 (current date)
1229 var dt = new Date();
1231 //dt = Thu May 25 2006 (today's month/day in 2006)
1232 dt = Date.parseDate("2006", "Y");
1234 //dt = Sun Jan 15 2006 (all date parts specified)
1235 dt = Date.parseDate("2006-1-15", "Y-m-d");
1237 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1238 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1240 * @param {String} input The unparsed date as a string
1241 * @param {String} format The format the date is in
1242 * @return {Date} The parsed date
1245 Date.parseDate = function(input, format) {
1246 if (Date.parseFunctions[format] == null) {
1247 Date.createParser(format);
1249 var func = Date.parseFunctions[format];
1250 return Date[func](input);
1256 Date.createParser = function(format) {
1257 var funcName = "parse" + Date.parseFunctions.count++;
1258 var regexNum = Date.parseRegexes.length;
1259 var currentGroup = 1;
1260 Date.parseFunctions[format] = funcName;
1262 var code = "Date." + funcName + " = function(input){\n"
1263 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1264 + "var d = new Date();\n"
1265 + "y = d.getFullYear();\n"
1266 + "m = d.getMonth();\n"
1267 + "d = d.getDate();\n"
1268 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1269 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1270 + "if (results && results.length > 0) {";
1273 var special = false;
1275 for (var i = 0; i < format.length; ++i) {
1276 ch = format.charAt(i);
1277 if (!special && ch == "\\") {
1282 regex += String.escape(ch);
1285 var obj = Date.formatCodeToRegex(ch, currentGroup);
1286 currentGroup += obj.g;
1288 if (obj.g && obj.c) {
1294 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1295 + "{v = new Date(y, m, d, h, i, s);}\n"
1296 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1297 + "{v = new Date(y, m, d, h, i);}\n"
1298 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1299 + "{v = new Date(y, m, d, h);}\n"
1300 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1301 + "{v = new Date(y, m, d);}\n"
1302 + "else if (y >= 0 && m >= 0)\n"
1303 + "{v = new Date(y, m);}\n"
1304 + "else if (y >= 0)\n"
1305 + "{v = new Date(y);}\n"
1306 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1307 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1308 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1311 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1312 /** eval:var:zzzzzzzzzzzzz */
1317 Date.formatCodeToRegex = function(character, currentGroup) {
1318 switch (character) {
1322 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1325 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1326 s:"(\\d{1,2})"}; // day of month without leading zeroes
1329 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1330 s:"(\\d{2})"}; // day of month with leading zeroes
1334 s:"(?:" + Date.dayNames.join("|") + ")"};
1338 s:"(?:st|nd|rd|th)"};
1353 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1354 s:"(" + Date.monthNames.join("|") + ")"};
1357 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1358 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1361 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1362 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1365 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1366 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1377 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1381 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1382 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1386 c:"if (results[" + currentGroup + "] == 'am') {\n"
1387 + "if (h == 12) { h = 0; }\n"
1388 + "} else { if (h < 12) { h += 12; }}",
1392 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1393 + "if (h == 12) { h = 0; }\n"
1394 + "} else { if (h < 12) { h += 12; }}",
1399 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1400 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1404 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1405 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1408 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1412 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1417 "o = results[", currentGroup, "];\n",
1418 "var sn = o.substring(0,1);\n", // get + / - sign
1419 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1420 "var mn = o.substring(3,5) % 60;\n", // get minutes
1421 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1422 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1424 s:"([+\-]\\d{2,4})"};
1430 "o = results[", currentGroup, "];\n",
1431 "var sn = o.substring(0,1);\n",
1432 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1433 "var mn = o.substring(4,6) % 60;\n",
1434 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1435 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1441 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1444 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1445 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1446 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1450 s:String.escape(character)};
1455 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1456 * @return {String} The abbreviated timezone name (e.g. 'CST')
1458 Date.prototype.getTimezone = function() {
1459 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1463 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1464 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1466 Date.prototype.getGMTOffset = function() {
1467 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1468 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1469 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1473 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1474 * @return {String} 2-characters representing hours and 2-characters representing minutes
1475 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1477 Date.prototype.getGMTColonOffset = function() {
1478 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1479 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1481 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1485 * Get the numeric day number of the year, adjusted for leap year.
1486 * @return {Number} 0 through 364 (365 in leap years)
1488 Date.prototype.getDayOfYear = function() {
1490 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1491 for (var i = 0; i < this.getMonth(); ++i) {
1492 num += Date.daysInMonth[i];
1494 return num + this.getDate() - 1;
1498 * Get the string representation of the numeric week number of the year
1499 * (equivalent to the format specifier 'W').
1500 * @return {String} '00' through '52'
1502 Date.prototype.getWeekOfYear = function() {
1503 // Skip to Thursday of this week
1504 var now = this.getDayOfYear() + (4 - this.getDay());
1505 // Find the first Thursday of the year
1506 var jan1 = new Date(this.getFullYear(), 0, 1);
1507 var then = (7 - jan1.getDay() + 4);
1508 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1512 * Whether or not the current date is in a leap year.
1513 * @return {Boolean} True if the current date is in a leap year, else false
1515 Date.prototype.isLeapYear = function() {
1516 var year = this.getFullYear();
1517 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1521 * Get the first day of the current month, adjusted for leap year. The returned value
1522 * is the numeric day index within the week (0-6) which can be used in conjunction with
1523 * the {@link #monthNames} array to retrieve the textual day name.
1526 var dt = new Date('1/10/2007');
1527 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1529 * @return {Number} The day number (0-6)
1531 Date.prototype.getFirstDayOfMonth = function() {
1532 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1533 return (day < 0) ? (day + 7) : day;
1537 * Get the last day of the current month, adjusted for leap year. The returned value
1538 * is the numeric day index within the week (0-6) which can be used in conjunction with
1539 * the {@link #monthNames} array to retrieve the textual day name.
1542 var dt = new Date('1/10/2007');
1543 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1545 * @return {Number} The day number (0-6)
1547 Date.prototype.getLastDayOfMonth = function() {
1548 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1549 return (day < 0) ? (day + 7) : day;
1554 * Get the first date of this date's month
1557 Date.prototype.getFirstDateOfMonth = function() {
1558 return new Date(this.getFullYear(), this.getMonth(), 1);
1562 * Get the last date of this date's month
1565 Date.prototype.getLastDateOfMonth = function() {
1566 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1569 * Get the number of days in the current month, adjusted for leap year.
1570 * @return {Number} The number of days in the month
1572 Date.prototype.getDaysInMonth = function() {
1573 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1574 return Date.daysInMonth[this.getMonth()];
1578 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1579 * @return {String} 'st, 'nd', 'rd' or 'th'
1581 Date.prototype.getSuffix = function() {
1582 switch (this.getDate()) {
1599 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1602 * An array of textual month names.
1603 * Override these values for international dates, for example...
1604 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1623 * An array of textual day names.
1624 * Override these values for international dates, for example...
1625 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1641 Date.monthNumbers = {
1656 * Creates and returns a new Date instance with the exact same date value as the called instance.
1657 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1658 * variable will also be changed. When the intention is to create a new variable that will not
1659 * modify the original instance, you should create a clone.
1661 * Example of correctly cloning a date:
1664 var orig = new Date('10/1/2006');
1667 document.write(orig); //returns 'Thu Oct 05 2006'!
1670 var orig = new Date('10/1/2006');
1671 var copy = orig.clone();
1673 document.write(orig); //returns 'Thu Oct 01 2006'
1675 * @return {Date} The new Date instance
1677 Date.prototype.clone = function() {
1678 return new Date(this.getTime());
1682 * Clears any time information from this date
1683 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1684 @return {Date} this or the clone
1686 Date.prototype.clearTime = function(clone){
1688 return this.clone().clearTime();
1693 this.setMilliseconds(0);
1698 // safari setMonth is broken -- check that this is only donw once...
1699 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1700 Date.brokenSetMonth = Date.prototype.setMonth;
1701 Date.prototype.setMonth = function(num){
1703 var n = Math.ceil(-num);
1704 var back_year = Math.ceil(n/12);
1705 var month = (n % 12) ? 12 - n % 12 : 0 ;
1706 this.setFullYear(this.getFullYear() - back_year);
1707 return Date.brokenSetMonth.call(this, month);
1709 return Date.brokenSetMonth.apply(this, arguments);
1714 /** Date interval constant
1718 /** Date interval constant
1722 /** Date interval constant
1726 /** Date interval constant
1730 /** Date interval constant
1734 /** Date interval constant
1738 /** Date interval constant
1744 * Provides a convenient method of performing basic date arithmetic. This method
1745 * does not modify the Date instance being called - it creates and returns
1746 * a new Date instance containing the resulting date value.
1751 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1752 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1754 //Negative values will subtract correctly:
1755 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1756 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1758 //You can even chain several calls together in one line!
1759 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1760 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1763 * @param {String} interval A valid date interval enum value
1764 * @param {Number} value The amount to add to the current date
1765 * @return {Date} The new Date instance
1767 Date.prototype.add = function(interval, value){
1768 var d = this.clone();
1769 if (!interval || value === 0) { return d; }
1770 switch(interval.toLowerCase()){
1772 d.setMilliseconds(this.getMilliseconds() + value);
1775 d.setSeconds(this.getSeconds() + value);
1778 d.setMinutes(this.getMinutes() + value);
1781 d.setHours(this.getHours() + value);
1784 d.setDate(this.getDate() + value);
1787 var day = this.getDate();
1789 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1792 d.setMonth(this.getMonth() + value);
1795 d.setFullYear(this.getFullYear() + value);
1802 * Ext JS Library 1.1.1
1803 * Copyright(c) 2006-2007, Ext JS, LLC.
1805 * Originally Released Under LGPL - original licence link has changed is not relivant.
1808 * <script type="text/javascript">
1812 * @class Roo.lib.Dom
1815 * Dom utils (from YIU afaik)
1820 * Get the view width
1821 * @param {Boolean} full True will get the full document, otherwise it's the view width
1822 * @return {Number} The width
1825 getViewWidth : function(full) {
1826 return full ? this.getDocumentWidth() : this.getViewportWidth();
1829 * Get the view height
1830 * @param {Boolean} full True will get the full document, otherwise it's the view height
1831 * @return {Number} The height
1833 getViewHeight : function(full) {
1834 return full ? this.getDocumentHeight() : this.getViewportHeight();
1837 getDocumentHeight: function() {
1838 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1839 return Math.max(scrollHeight, this.getViewportHeight());
1842 getDocumentWidth: function() {
1843 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1844 return Math.max(scrollWidth, this.getViewportWidth());
1847 getViewportHeight: function() {
1848 var height = self.innerHeight;
1849 var mode = document.compatMode;
1851 if ((mode || Roo.isIE) && !Roo.isOpera) {
1852 height = (mode == "CSS1Compat") ?
1853 document.documentElement.clientHeight :
1854 document.body.clientHeight;
1860 getViewportWidth: function() {
1861 var width = self.innerWidth;
1862 var mode = document.compatMode;
1864 if (mode || Roo.isIE) {
1865 width = (mode == "CSS1Compat") ?
1866 document.documentElement.clientWidth :
1867 document.body.clientWidth;
1872 isAncestor : function(p, c) {
1879 if (p.contains && !Roo.isSafari) {
1880 return p.contains(c);
1881 } else if (p.compareDocumentPosition) {
1882 return !!(p.compareDocumentPosition(c) & 16);
1884 var parent = c.parentNode;
1889 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1892 parent = parent.parentNode;
1898 getRegion : function(el) {
1899 return Roo.lib.Region.getRegion(el);
1902 getY : function(el) {
1903 return this.getXY(el)[1];
1906 getX : function(el) {
1907 return this.getXY(el)[0];
1910 getXY : function(el) {
1911 var p, pe, b, scroll, bd = document.body;
1912 el = Roo.getDom(el);
1913 var fly = Roo.lib.AnimBase.fly;
1914 if (el.getBoundingClientRect) {
1915 b = el.getBoundingClientRect();
1916 scroll = fly(document).getScroll();
1917 return [b.left + scroll.left, b.top + scroll.top];
1923 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1930 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1937 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1938 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1945 if (p != el && pe.getStyle('overflow') != 'visible') {
1953 if (Roo.isSafari && hasAbsolute) {
1958 if (Roo.isGecko && !hasAbsolute) {
1960 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1961 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1965 while (p && p != bd) {
1966 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1978 setXY : function(el, xy) {
1979 el = Roo.fly(el, '_setXY');
1981 var pts = el.translatePoints(xy);
1982 if (xy[0] !== false) {
1983 el.dom.style.left = pts.left + "px";
1985 if (xy[1] !== false) {
1986 el.dom.style.top = pts.top + "px";
1990 setX : function(el, x) {
1991 this.setXY(el, [x, false]);
1994 setY : function(el, y) {
1995 this.setXY(el, [false, y]);
1999 * Portions of this file are based on pieces of Yahoo User Interface Library
2000 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2001 * YUI licensed under the BSD License:
2002 * http://developer.yahoo.net/yui/license.txt
2003 * <script type="text/javascript">
2007 Roo.lib.Event = function() {
2008 var loadComplete = false;
2010 var unloadListeners = [];
2012 var onAvailStack = [];
2014 var lastError = null;
2027 startInterval: function() {
2028 if (!this._interval) {
2030 var callback = function() {
2031 self._tryPreloadAttach();
2033 this._interval = setInterval(callback, this.POLL_INTERVAL);
2038 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2039 onAvailStack.push({ id: p_id,
2042 override: p_override,
2043 checkReady: false });
2045 retryCount = this.POLL_RETRYS;
2046 this.startInterval();
2050 addListener: function(el, eventName, fn) {
2051 el = Roo.getDom(el);
2056 if ("unload" == eventName) {
2057 unloadListeners[unloadListeners.length] =
2058 [el, eventName, fn];
2062 var wrappedFn = function(e) {
2063 return fn(Roo.lib.Event.getEvent(e));
2066 var li = [el, eventName, fn, wrappedFn];
2068 var index = listeners.length;
2069 listeners[index] = li;
2071 this.doAdd(el, eventName, wrappedFn, false);
2077 removeListener: function(el, eventName, fn) {
2080 el = Roo.getDom(el);
2083 return this.purgeElement(el, false, eventName);
2087 if ("unload" == eventName) {
2089 for (i = 0,len = unloadListeners.length; i < len; i++) {
2090 var li = unloadListeners[i];
2093 li[1] == eventName &&
2095 unloadListeners.splice(i, 1);
2103 var cacheItem = null;
2106 var index = arguments[3];
2108 if ("undefined" == typeof index) {
2109 index = this._getCacheIndex(el, eventName, fn);
2113 cacheItem = listeners[index];
2116 if (!el || !cacheItem) {
2120 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2122 delete listeners[index][this.WFN];
2123 delete listeners[index][this.FN];
2124 listeners.splice(index, 1);
2131 getTarget: function(ev, resolveTextNode) {
2132 ev = ev.browserEvent || ev;
2133 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2134 var t = ev.target || ev.srcElement;
2135 return this.resolveTextNode(t);
2139 resolveTextNode: function(node) {
2140 if (Roo.isSafari && node && 3 == node.nodeType) {
2141 return node.parentNode;
2148 getPageX: function(ev) {
2149 ev = ev.browserEvent || ev;
2150 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2152 if (!x && 0 !== x) {
2153 x = ev.clientX || 0;
2156 x += this.getScroll()[1];
2164 getPageY: function(ev) {
2165 ev = ev.browserEvent || ev;
2166 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2168 if (!y && 0 !== y) {
2169 y = ev.clientY || 0;
2172 y += this.getScroll()[0];
2181 getXY: function(ev) {
2182 ev = ev.browserEvent || ev;
2183 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2184 return [this.getPageX(ev), this.getPageY(ev)];
2188 getRelatedTarget: function(ev) {
2189 ev = ev.browserEvent || ev;
2190 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2191 var t = ev.relatedTarget;
2193 if (ev.type == "mouseout") {
2195 } else if (ev.type == "mouseover") {
2200 return this.resolveTextNode(t);
2204 getTime: function(ev) {
2205 ev = ev.browserEvent || ev;
2206 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2208 var t = new Date().getTime();
2212 this.lastError = ex;
2221 stopEvent: function(ev) {
2222 this.stopPropagation(ev);
2223 this.preventDefault(ev);
2227 stopPropagation: function(ev) {
2228 ev = ev.browserEvent || ev;
2229 if (ev.stopPropagation) {
2230 ev.stopPropagation();
2232 ev.cancelBubble = true;
2237 preventDefault: function(ev) {
2238 ev = ev.browserEvent || ev;
2239 if(ev.preventDefault) {
2240 ev.preventDefault();
2242 ev.returnValue = false;
2247 getEvent: function(e) {
2248 var ev = e || window.event;
2250 var c = this.getEvent.caller;
2252 ev = c.arguments[0];
2253 if (ev && Event == ev.constructor) {
2263 getCharCode: function(ev) {
2264 ev = ev.browserEvent || ev;
2265 return ev.charCode || ev.keyCode || 0;
2269 _getCacheIndex: function(el, eventName, fn) {
2270 for (var i = 0,len = listeners.length; i < len; ++i) {
2271 var li = listeners[i];
2273 li[this.FN] == fn &&
2274 li[this.EL] == el &&
2275 li[this.TYPE] == eventName) {
2287 getEl: function(id) {
2288 return document.getElementById(id);
2292 clearCache: function() {
2296 _load: function(e) {
2297 loadComplete = true;
2298 var EU = Roo.lib.Event;
2302 EU.doRemove(window, "load", EU._load);
2307 _tryPreloadAttach: function() {
2316 var tryAgain = !loadComplete;
2318 tryAgain = (retryCount > 0);
2323 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2324 var item = onAvailStack[i];
2326 var el = this.getEl(item.id);
2329 if (!item.checkReady ||
2332 (document && document.body)) {
2335 if (item.override) {
2336 if (item.override === true) {
2339 scope = item.override;
2342 item.fn.call(scope, item.obj);
2343 onAvailStack[i] = null;
2346 notAvail.push(item);
2351 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2355 this.startInterval();
2357 clearInterval(this._interval);
2358 this._interval = null;
2361 this.locked = false;
2368 purgeElement: function(el, recurse, eventName) {
2369 var elListeners = this.getListeners(el, eventName);
2371 for (var i = 0,len = elListeners.length; i < len; ++i) {
2372 var l = elListeners[i];
2373 this.removeListener(el, l.type, l.fn);
2377 if (recurse && el && el.childNodes) {
2378 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2379 this.purgeElement(el.childNodes[i], recurse, eventName);
2385 getListeners: function(el, eventName) {
2386 var results = [], searchLists;
2388 searchLists = [listeners, unloadListeners];
2389 } else if (eventName == "unload") {
2390 searchLists = [unloadListeners];
2392 searchLists = [listeners];
2395 for (var j = 0; j < searchLists.length; ++j) {
2396 var searchList = searchLists[j];
2397 if (searchList && searchList.length > 0) {
2398 for (var i = 0,len = searchList.length; i < len; ++i) {
2399 var l = searchList[i];
2400 if (l && l[this.EL] === el &&
2401 (!eventName || eventName === l[this.TYPE])) {
2406 adjust: l[this.ADJ_SCOPE],
2414 return (results.length) ? results : null;
2418 _unload: function(e) {
2420 var EU = Roo.lib.Event, i, j, l, len, index;
2422 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2423 l = unloadListeners[i];
2426 if (l[EU.ADJ_SCOPE]) {
2427 if (l[EU.ADJ_SCOPE] === true) {
2430 scope = l[EU.ADJ_SCOPE];
2433 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2434 unloadListeners[i] = null;
2440 unloadListeners = null;
2442 if (listeners && listeners.length > 0) {
2443 j = listeners.length;
2446 l = listeners[index];
2448 EU.removeListener(l[EU.EL], l[EU.TYPE],
2458 EU.doRemove(window, "unload", EU._unload);
2463 getScroll: function() {
2464 var dd = document.documentElement, db = document.body;
2465 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2466 return [dd.scrollTop, dd.scrollLeft];
2468 return [db.scrollTop, db.scrollLeft];
2475 doAdd: function () {
2476 if (window.addEventListener) {
2477 return function(el, eventName, fn, capture) {
2478 el.addEventListener(eventName, fn, (capture));
2480 } else if (window.attachEvent) {
2481 return function(el, eventName, fn, capture) {
2482 el.attachEvent("on" + eventName, fn);
2491 doRemove: function() {
2492 if (window.removeEventListener) {
2493 return function (el, eventName, fn, capture) {
2494 el.removeEventListener(eventName, fn, (capture));
2496 } else if (window.detachEvent) {
2497 return function (el, eventName, fn) {
2498 el.detachEvent("on" + eventName, fn);
2510 var E = Roo.lib.Event;
2511 E.on = E.addListener;
2512 E.un = E.removeListener;
2514 if (document && document.body) {
2517 E.doAdd(window, "load", E._load);
2519 E.doAdd(window, "unload", E._unload);
2520 E._tryPreloadAttach();
2524 * Portions of this file are based on pieces of Yahoo User Interface Library
2525 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2526 * YUI licensed under the BSD License:
2527 * http://developer.yahoo.net/yui/license.txt
2528 * <script type="text/javascript">
2534 * @class Roo.lib.Ajax
2541 request : function(method, uri, cb, data, options) {
2543 var hs = options.headers;
2546 if(hs.hasOwnProperty(h)){
2547 this.initHeader(h, hs[h], false);
2551 if(options.xmlData){
2552 this.initHeader('Content-Type', 'text/xml', false);
2554 data = options.xmlData;
2558 return this.asyncRequest(method, uri, cb, data);
2561 serializeForm : function(form) {
2562 if(typeof form == 'string') {
2563 form = (document.getElementById(form) || document.forms[form]);
2566 var el, name, val, disabled, data = '', hasSubmit = false;
2567 for (var i = 0; i < form.elements.length; i++) {
2568 el = form.elements[i];
2569 disabled = form.elements[i].disabled;
2570 name = form.elements[i].name;
2571 val = form.elements[i].value;
2573 if (!disabled && name){
2577 case 'select-multiple':
2578 for (var j = 0; j < el.options.length; j++) {
2579 if (el.options[j].selected) {
2581 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2584 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2592 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2605 if(hasSubmit == false) {
2606 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2611 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2616 data = data.substr(0, data.length - 1);
2624 useDefaultHeader:true,
2626 defaultPostHeader:'application/x-www-form-urlencoded',
2628 useDefaultXhrHeader:true,
2630 defaultXhrHeader:'XMLHttpRequest',
2632 hasDefaultHeaders:true,
2644 setProgId:function(id)
2646 this.activeX.unshift(id);
2649 setDefaultPostHeader:function(b)
2651 this.useDefaultHeader = b;
2654 setDefaultXhrHeader:function(b)
2656 this.useDefaultXhrHeader = b;
2659 setPollingInterval:function(i)
2661 if (typeof i == 'number' && isFinite(i)) {
2662 this.pollInterval = i;
2666 createXhrObject:function(transactionId)
2672 http = new XMLHttpRequest();
2674 obj = { conn:http, tId:transactionId };
2678 for (var i = 0; i < this.activeX.length; ++i) {
2682 http = new ActiveXObject(this.activeX[i]);
2684 obj = { conn:http, tId:transactionId };
2697 getConnectionObject:function()
2700 var tId = this.transactionId;
2704 o = this.createXhrObject(tId);
2706 this.transactionId++;
2717 asyncRequest:function(method, uri, callback, postData)
2719 var o = this.getConnectionObject();
2725 o.conn.open(method, uri, true);
2727 if (this.useDefaultXhrHeader) {
2728 if (!this.defaultHeaders['X-Requested-With']) {
2729 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2733 if(postData && this.useDefaultHeader){
2734 this.initHeader('Content-Type', this.defaultPostHeader);
2737 if (this.hasDefaultHeaders || this.hasHeaders) {
2741 this.handleReadyState(o, callback);
2742 o.conn.send(postData || null);
2748 handleReadyState:function(o, callback)
2752 if (callback && callback.timeout) {
2754 this.timeout[o.tId] = window.setTimeout(function() {
2755 oConn.abort(o, callback, true);
2756 }, callback.timeout);
2759 this.poll[o.tId] = window.setInterval(
2761 if (o.conn && o.conn.readyState == 4) {
2762 window.clearInterval(oConn.poll[o.tId]);
2763 delete oConn.poll[o.tId];
2765 if(callback && callback.timeout) {
2766 window.clearTimeout(oConn.timeout[o.tId]);
2767 delete oConn.timeout[o.tId];
2770 oConn.handleTransactionResponse(o, callback);
2773 , this.pollInterval);
2776 handleTransactionResponse:function(o, callback, isAbort)
2780 this.releaseObject(o);
2784 var httpStatus, responseObject;
2788 if (o.conn.status !== undefined && o.conn.status != 0) {
2789 httpStatus = o.conn.status;
2801 if (httpStatus >= 200 && httpStatus < 300) {
2802 responseObject = this.createResponseObject(o, callback.argument);
2803 if (callback.success) {
2804 if (!callback.scope) {
2805 callback.success(responseObject);
2810 callback.success.apply(callback.scope, [responseObject]);
2815 switch (httpStatus) {
2823 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2824 if (callback.failure) {
2825 if (!callback.scope) {
2826 callback.failure(responseObject);
2829 callback.failure.apply(callback.scope, [responseObject]);
2834 responseObject = this.createResponseObject(o, callback.argument);
2835 if (callback.failure) {
2836 if (!callback.scope) {
2837 callback.failure(responseObject);
2840 callback.failure.apply(callback.scope, [responseObject]);
2846 this.releaseObject(o);
2847 responseObject = null;
2850 createResponseObject:function(o, callbackArg)
2857 var headerStr = o.conn.getAllResponseHeaders();
2858 var header = headerStr.split('\n');
2859 for (var i = 0; i < header.length; i++) {
2860 var delimitPos = header[i].indexOf(':');
2861 if (delimitPos != -1) {
2862 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2870 obj.status = o.conn.status;
2871 obj.statusText = o.conn.statusText;
2872 obj.getResponseHeader = headerObj;
2873 obj.getAllResponseHeaders = headerStr;
2874 obj.responseText = o.conn.responseText;
2875 obj.responseXML = o.conn.responseXML;
2877 if (typeof callbackArg !== undefined) {
2878 obj.argument = callbackArg;
2884 createExceptionObject:function(tId, callbackArg, isAbort)
2887 var COMM_ERROR = 'communication failure';
2888 var ABORT_CODE = -1;
2889 var ABORT_ERROR = 'transaction aborted';
2895 obj.status = ABORT_CODE;
2896 obj.statusText = ABORT_ERROR;
2899 obj.status = COMM_CODE;
2900 obj.statusText = COMM_ERROR;
2904 obj.argument = callbackArg;
2910 initHeader:function(label, value, isDefault)
2912 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2914 if (headerObj[label] === undefined) {
2915 headerObj[label] = value;
2920 headerObj[label] = value + "," + headerObj[label];
2924 this.hasDefaultHeaders = true;
2927 this.hasHeaders = true;
2932 setHeader:function(o)
2934 if (this.hasDefaultHeaders) {
2935 for (var prop in this.defaultHeaders) {
2936 if (this.defaultHeaders.hasOwnProperty(prop)) {
2937 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2942 if (this.hasHeaders) {
2943 for (var prop in this.headers) {
2944 if (this.headers.hasOwnProperty(prop)) {
2945 o.conn.setRequestHeader(prop, this.headers[prop]);
2949 this.hasHeaders = false;
2953 resetDefaultHeaders:function() {
2954 delete this.defaultHeaders;
2955 this.defaultHeaders = {};
2956 this.hasDefaultHeaders = false;
2959 abort:function(o, callback, isTimeout)
2961 if(this.isCallInProgress(o)) {
2963 window.clearInterval(this.poll[o.tId]);
2964 delete this.poll[o.tId];
2966 delete this.timeout[o.tId];
2969 this.handleTransactionResponse(o, callback, true);
2979 isCallInProgress:function(o)
2982 return o.conn.readyState != 4 && o.conn.readyState != 0;
2991 releaseObject:function(o)
3000 'MSXML2.XMLHTTP.3.0',
3008 * Portions of this file are based on pieces of Yahoo User Interface Library
3009 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3010 * YUI licensed under the BSD License:
3011 * http://developer.yahoo.net/yui/license.txt
3012 * <script type="text/javascript">
3016 Roo.lib.Region = function(t, r, b, l) {
3026 Roo.lib.Region.prototype = {
3027 contains : function(region) {
3028 return ( region.left >= this.left &&
3029 region.right <= this.right &&
3030 region.top >= this.top &&
3031 region.bottom <= this.bottom );
3035 getArea : function() {
3036 return ( (this.bottom - this.top) * (this.right - this.left) );
3039 intersect : function(region) {
3040 var t = Math.max(this.top, region.top);
3041 var r = Math.min(this.right, region.right);
3042 var b = Math.min(this.bottom, region.bottom);
3043 var l = Math.max(this.left, region.left);
3045 if (b >= t && r >= l) {
3046 return new Roo.lib.Region(t, r, b, l);
3051 union : function(region) {
3052 var t = Math.min(this.top, region.top);
3053 var r = Math.max(this.right, region.right);
3054 var b = Math.max(this.bottom, region.bottom);
3055 var l = Math.min(this.left, region.left);
3057 return new Roo.lib.Region(t, r, b, l);
3060 adjust : function(t, l, b, r) {
3069 Roo.lib.Region.getRegion = function(el) {
3070 var p = Roo.lib.Dom.getXY(el);
3073 var r = p[0] + el.offsetWidth;
3074 var b = p[1] + el.offsetHeight;
3077 return new Roo.lib.Region(t, r, b, l);
3080 * Portions of this file are based on pieces of Yahoo User Interface Library
3081 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3082 * YUI licensed under the BSD License:
3083 * http://developer.yahoo.net/yui/license.txt
3084 * <script type="text/javascript">
3087 //@@dep Roo.lib.Region
3090 Roo.lib.Point = function(x, y) {
3091 if (x instanceof Array) {
3095 this.x = this.right = this.left = this[0] = x;
3096 this.y = this.top = this.bottom = this[1] = y;
3099 Roo.lib.Point.prototype = new Roo.lib.Region();
3101 * Portions of this file are based on pieces of Yahoo User Interface Library
3102 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3103 * YUI licensed under the BSD License:
3104 * http://developer.yahoo.net/yui/license.txt
3105 * <script type="text/javascript">
3112 scroll : function(el, args, duration, easing, cb, scope) {
3113 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3116 motion : function(el, args, duration, easing, cb, scope) {
3117 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3120 color : function(el, args, duration, easing, cb, scope) {
3121 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3124 run : function(el, args, duration, easing, cb, scope, type) {
3125 type = type || Roo.lib.AnimBase;
3126 if (typeof easing == "string") {
3127 easing = Roo.lib.Easing[easing];
3129 var anim = new type(el, args, duration, easing);
3130 anim.animateX(function() {
3131 Roo.callback(cb, scope);
3137 * Portions of this file are based on pieces of Yahoo User Interface Library
3138 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3139 * YUI licensed under the BSD License:
3140 * http://developer.yahoo.net/yui/license.txt
3141 * <script type="text/javascript">
3149 if (!libFlyweight) {
3150 libFlyweight = new Roo.Element.Flyweight();
3152 libFlyweight.dom = el;
3153 return libFlyweight;
3156 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3160 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3162 this.init(el, attributes, duration, method);
3166 Roo.lib.AnimBase.fly = fly;
3170 Roo.lib.AnimBase.prototype = {
3172 toString: function() {
3173 var el = this.getEl();
3174 var id = el.id || el.tagName;
3175 return ("Anim " + id);
3179 noNegatives: /width|height|opacity|padding/i,
3180 offsetAttribute: /^((width|height)|(top|left))$/,
3181 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3182 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3186 doMethod: function(attr, start, end) {
3187 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3191 setAttribute: function(attr, val, unit) {
3192 if (this.patterns.noNegatives.test(attr)) {
3193 val = (val > 0) ? val : 0;
3196 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3200 getAttribute: function(attr) {
3201 var el = this.getEl();
3202 var val = fly(el).getStyle(attr);
3204 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3205 return parseFloat(val);
3208 var a = this.patterns.offsetAttribute.exec(attr) || [];
3209 var pos = !!( a[3] );
3210 var box = !!( a[2] );
3213 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3214 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3223 getDefaultUnit: function(attr) {
3224 if (this.patterns.defaultUnit.test(attr)) {
3231 animateX : function(callback, scope) {
3232 var f = function() {
3233 this.onComplete.removeListener(f);
3234 if (typeof callback == "function") {
3235 callback.call(scope || this, this);
3238 this.onComplete.addListener(f, this);
3243 setRuntimeAttribute: function(attr) {
3246 var attributes = this.attributes;
3248 this.runtimeAttributes[attr] = {};
3250 var isset = function(prop) {
3251 return (typeof prop !== 'undefined');
3254 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3258 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3261 if (isset(attributes[attr]['to'])) {
3262 end = attributes[attr]['to'];
3263 } else if (isset(attributes[attr]['by'])) {
3264 if (start.constructor == Array) {
3266 for (var i = 0, len = start.length; i < len; ++i) {
3267 end[i] = start[i] + attributes[attr]['by'][i];
3270 end = start + attributes[attr]['by'];
3274 this.runtimeAttributes[attr].start = start;
3275 this.runtimeAttributes[attr].end = end;
3278 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3282 init: function(el, attributes, duration, method) {
3284 var isAnimated = false;
3287 var startTime = null;
3290 var actualFrames = 0;
3293 el = Roo.getDom(el);
3296 this.attributes = attributes || {};
3299 this.duration = duration || 1;
3302 this.method = method || Roo.lib.Easing.easeNone;
3305 this.useSeconds = true;
3308 this.currentFrame = 0;
3311 this.totalFrames = Roo.lib.AnimMgr.fps;
3314 this.getEl = function() {
3319 this.isAnimated = function() {
3324 this.getStartTime = function() {
3328 this.runtimeAttributes = {};
3331 this.animate = function() {
3332 if (this.isAnimated()) {
3336 this.currentFrame = 0;
3338 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3340 Roo.lib.AnimMgr.registerElement(this);
3344 this.stop = function(finish) {
3346 this.currentFrame = this.totalFrames;
3347 this._onTween.fire();
3349 Roo.lib.AnimMgr.stop(this);
3352 var onStart = function() {
3353 this.onStart.fire();
3355 this.runtimeAttributes = {};
3356 for (var attr in this.attributes) {
3357 this.setRuntimeAttribute(attr);
3362 startTime = new Date();
3366 var onTween = function() {
3368 duration: new Date() - this.getStartTime(),
3369 currentFrame: this.currentFrame
3372 data.toString = function() {
3374 'duration: ' + data.duration +
3375 ', currentFrame: ' + data.currentFrame
3379 this.onTween.fire(data);
3381 var runtimeAttributes = this.runtimeAttributes;
3383 for (var attr in runtimeAttributes) {
3384 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3390 var onComplete = function() {
3391 var actual_duration = (new Date() - startTime) / 1000 ;
3394 duration: actual_duration,
3395 frames: actualFrames,
3396 fps: actualFrames / actual_duration
3399 data.toString = function() {
3401 'duration: ' + data.duration +
3402 ', frames: ' + data.frames +
3403 ', fps: ' + data.fps
3409 this.onComplete.fire(data);
3413 this._onStart = new Roo.util.Event(this);
3414 this.onStart = new Roo.util.Event(this);
3415 this.onTween = new Roo.util.Event(this);
3416 this._onTween = new Roo.util.Event(this);
3417 this.onComplete = new Roo.util.Event(this);
3418 this._onComplete = new Roo.util.Event(this);
3419 this._onStart.addListener(onStart);
3420 this._onTween.addListener(onTween);
3421 this._onComplete.addListener(onComplete);
3426 * Portions of this file are based on pieces of Yahoo User Interface Library
3427 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3428 * YUI licensed under the BSD License:
3429 * http://developer.yahoo.net/yui/license.txt
3430 * <script type="text/javascript">
3434 Roo.lib.AnimMgr = new function() {
3451 this.registerElement = function(tween) {
3452 queue[queue.length] = tween;
3454 tween._onStart.fire();
3459 this.unRegister = function(tween, index) {
3460 tween._onComplete.fire();
3461 index = index || getIndex(tween);
3463 queue.splice(index, 1);
3467 if (tweenCount <= 0) {
3473 this.start = function() {
3474 if (thread === null) {
3475 thread = setInterval(this.run, this.delay);
3480 this.stop = function(tween) {
3482 clearInterval(thread);
3484 for (var i = 0, len = queue.length; i < len; ++i) {
3485 if (queue[0].isAnimated()) {
3486 this.unRegister(queue[0], 0);
3495 this.unRegister(tween);
3500 this.run = function() {
3501 for (var i = 0, len = queue.length; i < len; ++i) {
3502 var tween = queue[i];
3503 if (!tween || !tween.isAnimated()) {
3507 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3509 tween.currentFrame += 1;
3511 if (tween.useSeconds) {
3512 correctFrame(tween);
3514 tween._onTween.fire();
3517 Roo.lib.AnimMgr.stop(tween, i);
3522 var getIndex = function(anim) {
3523 for (var i = 0, len = queue.length; i < len; ++i) {
3524 if (queue[i] == anim) {
3532 var correctFrame = function(tween) {
3533 var frames = tween.totalFrames;
3534 var frame = tween.currentFrame;
3535 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3536 var elapsed = (new Date() - tween.getStartTime());
3539 if (elapsed < tween.duration * 1000) {
3540 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3542 tweak = frames - (frame + 1);
3544 if (tweak > 0 && isFinite(tweak)) {
3545 if (tween.currentFrame + tweak >= frames) {
3546 tweak = frames - (frame + 1);
3549 tween.currentFrame += tweak;
3555 * Portions of this file are based on pieces of Yahoo User Interface Library
3556 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3557 * YUI licensed under the BSD License:
3558 * http://developer.yahoo.net/yui/license.txt
3559 * <script type="text/javascript">
3562 Roo.lib.Bezier = new function() {
3564 this.getPosition = function(points, t) {
3565 var n = points.length;
3568 for (var i = 0; i < n; ++i) {
3569 tmp[i] = [points[i][0], points[i][1]];
3572 for (var j = 1; j < n; ++j) {
3573 for (i = 0; i < n - j; ++i) {
3574 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3575 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3579 return [ tmp[0][0], tmp[0][1] ];
3583 * Portions of this file are based on pieces of Yahoo User Interface Library
3584 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3585 * YUI licensed under the BSD License:
3586 * http://developer.yahoo.net/yui/license.txt
3587 * <script type="text/javascript">
3592 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3593 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3596 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3598 var fly = Roo.lib.AnimBase.fly;
3600 var superclass = Y.ColorAnim.superclass;
3601 var proto = Y.ColorAnim.prototype;
3603 proto.toString = function() {
3604 var el = this.getEl();
3605 var id = el.id || el.tagName;
3606 return ("ColorAnim " + id);
3609 proto.patterns.color = /color$/i;
3610 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3611 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3612 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3613 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3616 proto.parseColor = function(s) {
3617 if (s.length == 3) {
3621 var c = this.patterns.hex.exec(s);
3622 if (c && c.length == 4) {
3623 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3626 c = this.patterns.rgb.exec(s);
3627 if (c && c.length == 4) {
3628 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3631 c = this.patterns.hex3.exec(s);
3632 if (c && c.length == 4) {
3633 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3638 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3639 proto.getAttribute = function(attr) {
3640 var el = this.getEl();
3641 if (this.patterns.color.test(attr)) {
3642 var val = fly(el).getStyle(attr);
3644 if (this.patterns.transparent.test(val)) {
3645 var parent = el.parentNode;
3646 val = fly(parent).getStyle(attr);
3648 while (parent && this.patterns.transparent.test(val)) {
3649 parent = parent.parentNode;
3650 val = fly(parent).getStyle(attr);
3651 if (parent.tagName.toUpperCase() == 'HTML') {
3657 val = superclass.getAttribute.call(this, attr);
3662 proto.getAttribute = function(attr) {
3663 var el = this.getEl();
3664 if (this.patterns.color.test(attr)) {
3665 var val = fly(el).getStyle(attr);
3667 if (this.patterns.transparent.test(val)) {
3668 var parent = el.parentNode;
3669 val = fly(parent).getStyle(attr);
3671 while (parent && this.patterns.transparent.test(val)) {
3672 parent = parent.parentNode;
3673 val = fly(parent).getStyle(attr);
3674 if (parent.tagName.toUpperCase() == 'HTML') {
3680 val = superclass.getAttribute.call(this, attr);
3686 proto.doMethod = function(attr, start, end) {
3689 if (this.patterns.color.test(attr)) {
3691 for (var i = 0, len = start.length; i < len; ++i) {
3692 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3695 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3698 val = superclass.doMethod.call(this, attr, start, end);
3704 proto.setRuntimeAttribute = function(attr) {
3705 superclass.setRuntimeAttribute.call(this, attr);
3707 if (this.patterns.color.test(attr)) {
3708 var attributes = this.attributes;
3709 var start = this.parseColor(this.runtimeAttributes[attr].start);
3710 var end = this.parseColor(this.runtimeAttributes[attr].end);
3712 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3713 end = this.parseColor(attributes[attr].by);
3715 for (var i = 0, len = start.length; i < len; ++i) {
3716 end[i] = start[i] + end[i];
3720 this.runtimeAttributes[attr].start = start;
3721 this.runtimeAttributes[attr].end = end;
3727 * Portions of this file are based on pieces of Yahoo User Interface Library
3728 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3729 * YUI licensed under the BSD License:
3730 * http://developer.yahoo.net/yui/license.txt
3731 * <script type="text/javascript">
3737 easeNone: function (t, b, c, d) {
3738 return c * t / d + b;
3742 easeIn: function (t, b, c, d) {
3743 return c * (t /= d) * t + b;
3747 easeOut: function (t, b, c, d) {
3748 return -c * (t /= d) * (t - 2) + b;
3752 easeBoth: function (t, b, c, d) {
3753 if ((t /= d / 2) < 1) {
3754 return c / 2 * t * t + b;
3757 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3761 easeInStrong: function (t, b, c, d) {
3762 return c * (t /= d) * t * t * t + b;
3766 easeOutStrong: function (t, b, c, d) {
3767 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3771 easeBothStrong: function (t, b, c, d) {
3772 if ((t /= d / 2) < 1) {
3773 return c / 2 * t * t * t * t + b;
3776 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3781 elasticIn: function (t, b, c, d, a, p) {
3785 if ((t /= d) == 1) {
3792 if (!a || a < Math.abs(c)) {
3797 var s = p / (2 * Math.PI) * Math.asin(c / a);
3800 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3804 elasticOut: function (t, b, c, d, a, p) {
3808 if ((t /= d) == 1) {
3815 if (!a || a < Math.abs(c)) {
3820 var s = p / (2 * Math.PI) * Math.asin(c / a);
3823 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3827 elasticBoth: function (t, b, c, d, a, p) {
3832 if ((t /= d / 2) == 2) {
3840 if (!a || a < Math.abs(c)) {
3845 var s = p / (2 * Math.PI) * Math.asin(c / a);
3849 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3850 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3852 return a * Math.pow(2, -10 * (t -= 1)) *
3853 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3858 backIn: function (t, b, c, d, s) {
3859 if (typeof s == 'undefined') {
3862 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3866 backOut: function (t, b, c, d, s) {
3867 if (typeof s == 'undefined') {
3870 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3874 backBoth: function (t, b, c, d, s) {
3875 if (typeof s == 'undefined') {
3879 if ((t /= d / 2 ) < 1) {
3880 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3882 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3886 bounceIn: function (t, b, c, d) {
3887 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3891 bounceOut: function (t, b, c, d) {
3892 if ((t /= d) < (1 / 2.75)) {
3893 return c * (7.5625 * t * t) + b;
3894 } else if (t < (2 / 2.75)) {
3895 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3896 } else if (t < (2.5 / 2.75)) {
3897 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3899 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3903 bounceBoth: function (t, b, c, d) {
3905 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3907 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3910 * Portions of this file are based on pieces of Yahoo User Interface Library
3911 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3912 * YUI licensed under the BSD License:
3913 * http://developer.yahoo.net/yui/license.txt
3914 * <script type="text/javascript">
3918 Roo.lib.Motion = function(el, attributes, duration, method) {
3920 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3924 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3928 var superclass = Y.Motion.superclass;
3929 var proto = Y.Motion.prototype;
3931 proto.toString = function() {
3932 var el = this.getEl();
3933 var id = el.id || el.tagName;
3934 return ("Motion " + id);
3937 proto.patterns.points = /^points$/i;
3939 proto.setAttribute = function(attr, val, unit) {
3940 if (this.patterns.points.test(attr)) {
3941 unit = unit || 'px';
3942 superclass.setAttribute.call(this, 'left', val[0], unit);
3943 superclass.setAttribute.call(this, 'top', val[1], unit);
3945 superclass.setAttribute.call(this, attr, val, unit);
3949 proto.getAttribute = function(attr) {
3950 if (this.patterns.points.test(attr)) {
3952 superclass.getAttribute.call(this, 'left'),
3953 superclass.getAttribute.call(this, 'top')
3956 val = superclass.getAttribute.call(this, attr);
3962 proto.doMethod = function(attr, start, end) {
3965 if (this.patterns.points.test(attr)) {
3966 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3967 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3969 val = superclass.doMethod.call(this, attr, start, end);
3974 proto.setRuntimeAttribute = function(attr) {
3975 if (this.patterns.points.test(attr)) {
3976 var el = this.getEl();
3977 var attributes = this.attributes;
3979 var control = attributes['points']['control'] || [];
3983 if (control.length > 0 && !(control[0] instanceof Array)) {
3984 control = [control];
3987 for (i = 0,len = control.length; i < len; ++i) {
3988 tmp[i] = control[i];
3993 Roo.fly(el).position();
3995 if (isset(attributes['points']['from'])) {
3996 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3999 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4002 start = this.getAttribute('points');
4005 if (isset(attributes['points']['to'])) {
4006 end = translateValues.call(this, attributes['points']['to'], start);
4008 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4009 for (i = 0,len = control.length; i < len; ++i) {
4010 control[i] = translateValues.call(this, control[i], start);
4014 } else if (isset(attributes['points']['by'])) {
4015 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4017 for (i = 0,len = control.length; i < len; ++i) {
4018 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4022 this.runtimeAttributes[attr] = [start];
4024 if (control.length > 0) {
4025 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4028 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4031 superclass.setRuntimeAttribute.call(this, attr);
4035 var translateValues = function(val, start) {
4036 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4037 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4042 var isset = function(prop) {
4043 return (typeof prop !== 'undefined');
4047 * Portions of this file are based on pieces of Yahoo User Interface Library
4048 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4049 * YUI licensed under the BSD License:
4050 * http://developer.yahoo.net/yui/license.txt
4051 * <script type="text/javascript">
4055 Roo.lib.Scroll = function(el, attributes, duration, method) {
4057 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4061 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4065 var superclass = Y.Scroll.superclass;
4066 var proto = Y.Scroll.prototype;
4068 proto.toString = function() {
4069 var el = this.getEl();
4070 var id = el.id || el.tagName;
4071 return ("Scroll " + id);
4074 proto.doMethod = function(attr, start, end) {
4077 if (attr == 'scroll') {
4079 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4080 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4084 val = superclass.doMethod.call(this, attr, start, end);
4089 proto.getAttribute = function(attr) {
4091 var el = this.getEl();
4093 if (attr == 'scroll') {
4094 val = [ el.scrollLeft, el.scrollTop ];
4096 val = superclass.getAttribute.call(this, attr);
4102 proto.setAttribute = function(attr, val, unit) {
4103 var el = this.getEl();
4105 if (attr == 'scroll') {
4106 el.scrollLeft = val[0];
4107 el.scrollTop = val[1];
4109 superclass.setAttribute.call(this, attr, val, unit);
4115 * Ext JS Library 1.1.1
4116 * Copyright(c) 2006-2007, Ext JS, LLC.
4118 * Originally Released Under LGPL - original licence link has changed is not relivant.
4121 * <script type="text/javascript">
4125 // nasty IE9 hack - what a pile of crap that is..
4127 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4128 Range.prototype.createContextualFragment = function (html) {
4129 var doc = window.document;
4130 var container = doc.createElement("div");
4131 container.innerHTML = html;
4132 var frag = doc.createDocumentFragment(), n;
4133 while ((n = container.firstChild)) {
4134 frag.appendChild(n);
4141 * @class Roo.DomHelper
4142 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4143 * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4146 Roo.DomHelper = function(){
4147 var tempTableEl = null;
4148 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4149 var tableRe = /^table|tbody|tr|td$/i;
4151 // build as innerHTML where available
4153 var createHtml = function(o){
4154 if(typeof o == 'string'){
4163 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4164 if(attr == "style"){
4166 if(typeof s == "function"){
4169 if(typeof s == "string"){
4170 b += ' style="' + s + '"';
4171 }else if(typeof s == "object"){
4174 if(typeof s[key] != "function"){
4175 b += key + ":" + s[key] + ";";
4182 b += ' class="' + o["cls"] + '"';
4183 }else if(attr == "htmlFor"){
4184 b += ' for="' + o["htmlFor"] + '"';
4186 b += " " + attr + '="' + o[attr] + '"';
4190 if(emptyTags.test(o.tag)){
4194 var cn = o.children || o.cn;
4196 //http://bugs.kde.org/show_bug.cgi?id=71506
4197 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4198 for(var i = 0, len = cn.length; i < len; i++) {
4199 b += createHtml(cn[i], b);
4202 b += createHtml(cn, b);
4208 b += "</" + o.tag + ">";
4215 var createDom = function(o, parentNode){
4217 // defininition craeted..
4219 if (o.ns && o.ns != 'html') {
4221 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4222 xmlns[o.ns] = o.xmlns;
4225 if (typeof(xmlns[o.ns]) == 'undefined') {
4226 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4232 if (typeof(o) == 'string') {
4233 return parentNode.appendChild(document.createTextNode(o));
4235 o.tag = o.tag || div;
4236 if (o.ns && Roo.isIE) {
4238 o.tag = o.ns + ':' + o.tag;
4241 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4242 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4245 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4246 attr == "style" || typeof o[attr] == "function") { continue; }
4248 if(attr=="cls" && Roo.isIE){
4249 el.className = o["cls"];
4251 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4257 Roo.DomHelper.applyStyles(el, o.style);
4258 var cn = o.children || o.cn;
4260 //http://bugs.kde.org/show_bug.cgi?id=71506
4261 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4262 for(var i = 0, len = cn.length; i < len; i++) {
4263 createDom(cn[i], el);
4270 el.innerHTML = o.html;
4273 parentNode.appendChild(el);
4278 var ieTable = function(depth, s, h, e){
4279 tempTableEl.innerHTML = [s, h, e].join('');
4280 var i = -1, el = tempTableEl;
4287 // kill repeat to save bytes
4291 tbe = '</tbody>'+te,
4297 * Nasty code for IE's broken table implementation
4299 var insertIntoTable = function(tag, where, el, html){
4301 tempTableEl = document.createElement('div');
4306 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4309 if(where == 'beforebegin'){
4313 before = el.nextSibling;
4316 node = ieTable(4, trs, html, tre);
4318 else if(tag == 'tr'){
4319 if(where == 'beforebegin'){
4322 node = ieTable(3, tbs, html, tbe);
4323 } else if(where == 'afterend'){
4324 before = el.nextSibling;
4326 node = ieTable(3, tbs, html, tbe);
4327 } else{ // INTO a TR
4328 if(where == 'afterbegin'){
4329 before = el.firstChild;
4331 node = ieTable(4, trs, html, tre);
4333 } else if(tag == 'tbody'){
4334 if(where == 'beforebegin'){
4337 node = ieTable(2, ts, html, te);
4338 } else if(where == 'afterend'){
4339 before = el.nextSibling;
4341 node = ieTable(2, ts, html, te);
4343 if(where == 'afterbegin'){
4344 before = el.firstChild;
4346 node = ieTable(3, tbs, html, tbe);
4349 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4352 if(where == 'afterbegin'){
4353 before = el.firstChild;
4355 node = ieTable(2, ts, html, te);
4357 el.insertBefore(node, before);
4362 /** True to force the use of DOM instead of html fragments @type Boolean */
4366 * Returns the markup for the passed Element(s) config
4367 * @param {Object} o The Dom object spec (and children)
4370 markup : function(o){
4371 return createHtml(o);
4375 * Applies a style specification to an element
4376 * @param {String/HTMLElement} el The element to apply styles to
4377 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4378 * a function which returns such a specification.
4380 applyStyles : function(el, styles){
4383 if(typeof styles == "string"){
4384 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4386 while ((matches = re.exec(styles)) != null){
4387 el.setStyle(matches[1], matches[2]);
4389 }else if (typeof styles == "object"){
4390 for (var style in styles){
4391 el.setStyle(style, styles[style]);
4393 }else if (typeof styles == "function"){
4394 Roo.DomHelper.applyStyles(el, styles.call());
4400 * Inserts an HTML fragment into the Dom
4401 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4402 * @param {HTMLElement} el The context element
4403 * @param {String} html The HTML fragmenet
4404 * @return {HTMLElement} The new node
4406 insertHtml : function(where, el, html){
4407 where = where.toLowerCase();
4408 if(el.insertAdjacentHTML){
4409 if(tableRe.test(el.tagName)){
4411 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4417 el.insertAdjacentHTML('BeforeBegin', html);
4418 return el.previousSibling;
4420 el.insertAdjacentHTML('AfterBegin', html);
4421 return el.firstChild;
4423 el.insertAdjacentHTML('BeforeEnd', html);
4424 return el.lastChild;
4426 el.insertAdjacentHTML('AfterEnd', html);
4427 return el.nextSibling;
4429 throw 'Illegal insertion point -> "' + where + '"';
4431 var range = el.ownerDocument.createRange();
4435 range.setStartBefore(el);
4436 frag = range.createContextualFragment(html);
4437 el.parentNode.insertBefore(frag, el);
4438 return el.previousSibling;
4441 range.setStartBefore(el.firstChild);
4442 frag = range.createContextualFragment(html);
4443 el.insertBefore(frag, el.firstChild);
4444 return el.firstChild;
4446 el.innerHTML = html;
4447 return el.firstChild;
4451 range.setStartAfter(el.lastChild);
4452 frag = range.createContextualFragment(html);
4453 el.appendChild(frag);
4454 return el.lastChild;
4456 el.innerHTML = html;
4457 return el.lastChild;
4460 range.setStartAfter(el);
4461 frag = range.createContextualFragment(html);
4462 el.parentNode.insertBefore(frag, el.nextSibling);
4463 return el.nextSibling;
4465 throw 'Illegal insertion point -> "' + where + '"';
4469 * Creates new Dom element(s) and inserts them before el
4470 * @param {String/HTMLElement/Element} el The context element
4471 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4472 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4473 * @return {HTMLElement/Roo.Element} The new node
4475 insertBefore : function(el, o, returnElement){
4476 return this.doInsert(el, o, returnElement, "beforeBegin");
4480 * Creates new Dom element(s) and inserts them after el
4481 * @param {String/HTMLElement/Element} el The context element
4482 * @param {Object} o The Dom object spec (and children)
4483 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4484 * @return {HTMLElement/Roo.Element} The new node
4486 insertAfter : function(el, o, returnElement){
4487 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4491 * Creates new Dom element(s) and inserts them as the first child of el
4492 * @param {String/HTMLElement/Element} el The context element
4493 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4494 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4495 * @return {HTMLElement/Roo.Element} The new node
4497 insertFirst : function(el, o, returnElement){
4498 return this.doInsert(el, o, returnElement, "afterBegin");
4502 doInsert : function(el, o, returnElement, pos, sibling){
4503 el = Roo.getDom(el);
4505 if(this.useDom || o.ns){
4506 newNode = createDom(o, null);
4507 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4509 var html = createHtml(o);
4510 newNode = this.insertHtml(pos, el, html);
4512 return returnElement ? Roo.get(newNode, true) : newNode;
4516 * Creates new Dom element(s) and appends them to el
4517 * @param {String/HTMLElement/Element} el The context element
4518 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4519 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4520 * @return {HTMLElement/Roo.Element} The new node
4522 append : function(el, o, returnElement){
4523 el = Roo.getDom(el);
4525 if(this.useDom || o.ns){
4526 newNode = createDom(o, null);
4527 el.appendChild(newNode);
4529 var html = createHtml(o);
4530 newNode = this.insertHtml("beforeEnd", el, html);
4532 return returnElement ? Roo.get(newNode, true) : newNode;
4536 * Creates new Dom element(s) and overwrites the contents of el with them
4537 * @param {String/HTMLElement/Element} el The context element
4538 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4539 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4540 * @return {HTMLElement/Roo.Element} The new node
4542 overwrite : function(el, o, returnElement){
4543 el = Roo.getDom(el);
4546 while (el.childNodes.length) {
4547 el.removeChild(el.firstChild);
4551 el.innerHTML = createHtml(o);
4554 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4558 * Creates a new Roo.DomHelper.Template from the Dom object spec
4559 * @param {Object} o The Dom object spec (and children)
4560 * @return {Roo.DomHelper.Template} The new template
4562 createTemplate : function(o){
4563 var html = createHtml(o);
4564 return new Roo.Template(html);
4570 * Ext JS Library 1.1.1
4571 * Copyright(c) 2006-2007, Ext JS, LLC.
4573 * Originally Released Under LGPL - original licence link has changed is not relivant.
4576 * <script type="text/javascript">
4580 * @class Roo.Template
4581 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4582 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4585 var t = new Roo.Template({
4586 html : '<div name="{id}">' +
4587 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4589 myformat: function (value, allValues) {
4590 return 'XX' + value;
4593 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4595 * For more information see this blog post with examples:
4596 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4597 - Create Elements using DOM, HTML fragments and Templates</a>.
4599 * @param {Object} cfg - Configuration object.
4601 Roo.Template = function(cfg){
4603 if(cfg instanceof Array){
4605 }else if(arguments.length > 1){
4606 cfg = Array.prototype.join.call(arguments, "");
4610 if (typeof(cfg) == 'object') {
4621 Roo.Template.prototype = {
4624 * @cfg {String} url The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4625 * it should be fixed so that template is observable...
4629 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4633 * Returns an HTML fragment of this template with the specified values applied.
4634 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4635 * @return {String} The HTML fragment
4637 applyTemplate : function(values){
4641 return this.compiled(values);
4643 var useF = this.disableFormats !== true;
4644 var fm = Roo.util.Format, tpl = this;
4645 var fn = function(m, name, format, args){
4647 if(format.substr(0, 5) == "this."){
4648 return tpl.call(format.substr(5), values[name], values);
4651 // quoted values are required for strings in compiled templates,
4652 // but for non compiled we need to strip them
4653 // quoted reversed for jsmin
4654 var re = /^\s*['"](.*)["']\s*$/;
4655 args = args.split(',');
4656 for(var i = 0, len = args.length; i < len; i++){
4657 args[i] = args[i].replace(re, "$1");
4659 args = [values[name]].concat(args);
4661 args = [values[name]];
4663 return fm[format].apply(fm, args);
4666 return values[name] !== undefined ? values[name] : "";
4669 return this.html.replace(this.re, fn);
4687 this.loading = true;
4688 this.compiled = false;
4690 var cx = new Roo.data.Connection();
4694 success : function (response) {
4696 _t.html = response.responseText;
4700 failure : function(response) {
4701 Roo.log("Template failed to load from " + _t.url);
4708 * Sets the HTML used as the template and optionally compiles it.
4709 * @param {String} html
4710 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4711 * @return {Roo.Template} this
4713 set : function(html, compile){
4715 this.compiled = null;
4723 * True to disable format functions (defaults to false)
4726 disableFormats : false,
4729 * The regular expression used to match template variables
4733 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4736 * Compiles the template into an internal function, eliminating the RegEx overhead.
4737 * @return {Roo.Template} this
4739 compile : function(){
4740 var fm = Roo.util.Format;
4741 var useF = this.disableFormats !== true;
4742 var sep = Roo.isGecko ? "+" : ",";
4743 var fn = function(m, name, format, args){
4745 args = args ? ',' + args : "";
4746 if(format.substr(0, 5) != "this."){
4747 format = "fm." + format + '(';
4749 format = 'this.call("'+ format.substr(5) + '", ';
4753 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4755 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4758 // branched to use + in gecko and [].join() in others
4760 body = "this.compiled = function(values){ return '" +
4761 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4764 body = ["this.compiled = function(values){ return ['"];
4765 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4766 body.push("'].join('');};");
4767 body = body.join('');
4777 // private function used to call members
4778 call : function(fnName, value, allValues){
4779 return this[fnName](value, allValues);
4783 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4784 * @param {String/HTMLElement/Roo.Element} el The context element
4785 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4786 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4787 * @return {HTMLElement/Roo.Element} The new node or Element
4789 insertFirst: function(el, values, returnElement){
4790 return this.doInsert('afterBegin', el, values, returnElement);
4794 * Applies the supplied values to the template and inserts the new node(s) before el.
4795 * @param {String/HTMLElement/Roo.Element} el The context element
4796 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4797 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4798 * @return {HTMLElement/Roo.Element} The new node or Element
4800 insertBefore: function(el, values, returnElement){
4801 return this.doInsert('beforeBegin', el, values, returnElement);
4805 * Applies the supplied values to the template and inserts the new node(s) after el.
4806 * @param {String/HTMLElement/Roo.Element} el The context element
4807 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4808 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4809 * @return {HTMLElement/Roo.Element} The new node or Element
4811 insertAfter : function(el, values, returnElement){
4812 return this.doInsert('afterEnd', el, values, returnElement);
4816 * Applies the supplied values to the template and appends the new node(s) to el.
4817 * @param {String/HTMLElement/Roo.Element} el The context element
4818 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4819 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4820 * @return {HTMLElement/Roo.Element} The new node or Element
4822 append : function(el, values, returnElement){
4823 return this.doInsert('beforeEnd', el, values, returnElement);
4826 doInsert : function(where, el, values, returnEl){
4827 el = Roo.getDom(el);
4828 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4829 return returnEl ? Roo.get(newNode, true) : newNode;
4833 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4834 * @param {String/HTMLElement/Roo.Element} el The context element
4835 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4836 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4837 * @return {HTMLElement/Roo.Element} The new node or Element
4839 overwrite : function(el, values, returnElement){
4840 el = Roo.getDom(el);
4841 el.innerHTML = this.applyTemplate(values);
4842 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4846 * Alias for {@link #applyTemplate}
4849 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4852 Roo.DomHelper.Template = Roo.Template;
4855 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4856 * @param {String/HTMLElement} el A DOM element or its id
4857 * @returns {Roo.Template} The created template
4860 Roo.Template.from = function(el){
4861 el = Roo.getDom(el);
4862 return new Roo.Template(el.value || el.innerHTML);
4865 * Ext JS Library 1.1.1
4866 * Copyright(c) 2006-2007, Ext JS, LLC.
4868 * Originally Released Under LGPL - original licence link has changed is not relivant.
4871 * <script type="text/javascript">
4876 * This is code is also distributed under MIT license for use
4877 * with jQuery and prototype JavaScript libraries.
4880 * @class Roo.DomQuery
4881 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4883 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4886 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4888 <h4>Element Selectors:</h4>
4890 <li> <b>*</b> any element</li>
4891 <li> <b>E</b> an element with the tag E</li>
4892 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4893 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4894 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4895 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4897 <h4>Attribute Selectors:</h4>
4898 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4900 <li> <b>E[foo]</b> has an attribute "foo"</li>
4901 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4902 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4903 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4904 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4905 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4906 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4908 <h4>Pseudo Classes:</h4>
4910 <li> <b>E:first-child</b> E is the first child of its parent</li>
4911 <li> <b>E:last-child</b> E is the last child of its parent</li>
4912 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4913 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4914 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4915 <li> <b>E:only-child</b> E is the only child of its parent</li>
4916 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4917 <li> <b>E:first</b> the first E in the resultset</li>
4918 <li> <b>E:last</b> the last E in the resultset</li>
4919 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4920 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4921 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4922 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4923 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4924 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4925 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4926 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4927 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4929 <h4>CSS Value Selectors:</h4>
4931 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4932 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4933 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4934 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4935 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4936 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4940 Roo.DomQuery = function(){
4941 var cache = {}, simpleCache = {}, valueCache = {};
4942 var nonSpace = /\S/;
4943 var trimRe = /^\s+|\s+$/g;
4944 var tplRe = /\{(\d+)\}/g;
4945 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4946 var tagTokenRe = /^(#)?([\w-\*]+)/;
4947 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4949 function child(p, index){
4951 var n = p.firstChild;
4953 if(n.nodeType == 1){
4964 while((n = n.nextSibling) && n.nodeType != 1);
4969 while((n = n.previousSibling) && n.nodeType != 1);
4973 function children(d){
4974 var n = d.firstChild, ni = -1;
4976 var nx = n.nextSibling;
4977 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4987 function byClassName(c, a, v){
4991 var r = [], ri = -1, cn;
4992 for(var i = 0, ci; ci = c[i]; i++){
4993 if((' '+ci.className+' ').indexOf(v) != -1){
5000 function attrValue(n, attr){
5001 if(!n.tagName && typeof n.length != "undefined"){
5010 if(attr == "class" || attr == "className"){
5013 return n.getAttribute(attr) || n[attr];
5017 function getNodes(ns, mode, tagName){
5018 var result = [], ri = -1, cs;
5022 tagName = tagName || "*";
5023 if(typeof ns.getElementsByTagName != "undefined"){
5027 for(var i = 0, ni; ni = ns[i]; i++){
5028 cs = ni.getElementsByTagName(tagName);
5029 for(var j = 0, ci; ci = cs[j]; j++){
5033 }else if(mode == "/" || mode == ">"){
5034 var utag = tagName.toUpperCase();
5035 for(var i = 0, ni, cn; ni = ns[i]; i++){
5036 cn = ni.children || ni.childNodes;
5037 for(var j = 0, cj; cj = cn[j]; j++){
5038 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5043 }else if(mode == "+"){
5044 var utag = tagName.toUpperCase();
5045 for(var i = 0, n; n = ns[i]; i++){
5046 while((n = n.nextSibling) && n.nodeType != 1);
5047 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5051 }else if(mode == "~"){
5052 for(var i = 0, n; n = ns[i]; i++){
5053 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5062 function concat(a, b){
5066 for(var i = 0, l = b.length; i < l; i++){
5072 function byTag(cs, tagName){
5073 if(cs.tagName || cs == document){
5079 var r = [], ri = -1;
5080 tagName = tagName.toLowerCase();
5081 for(var i = 0, ci; ci = cs[i]; i++){
5082 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5089 function byId(cs, attr, id){
5090 if(cs.tagName || cs == document){
5096 var r = [], ri = -1;
5097 for(var i = 0,ci; ci = cs[i]; i++){
5098 if(ci && ci.id == id){
5106 function byAttribute(cs, attr, value, op, custom){
5107 var r = [], ri = -1, st = custom=="{";
5108 var f = Roo.DomQuery.operators[op];
5109 for(var i = 0, ci; ci = cs[i]; i++){
5112 a = Roo.DomQuery.getStyle(ci, attr);
5114 else if(attr == "class" || attr == "className"){
5116 }else if(attr == "for"){
5118 }else if(attr == "href"){
5119 a = ci.getAttribute("href", 2);
5121 a = ci.getAttribute(attr);
5123 if((f && f(a, value)) || (!f && a)){
5130 function byPseudo(cs, name, value){
5131 return Roo.DomQuery.pseudos[name](cs, value);
5134 // This is for IE MSXML which does not support expandos.
5135 // IE runs the same speed using setAttribute, however FF slows way down
5136 // and Safari completely fails so they need to continue to use expandos.
5137 var isIE = window.ActiveXObject ? true : false;
5139 // this eval is stop the compressor from
5140 // renaming the variable to something shorter
5142 /** eval:var:batch */
5147 function nodupIEXml(cs){
5149 cs[0].setAttribute("_nodup", d);
5151 for(var i = 1, len = cs.length; i < len; i++){
5153 if(!c.getAttribute("_nodup") != d){
5154 c.setAttribute("_nodup", d);
5158 for(var i = 0, len = cs.length; i < len; i++){
5159 cs[i].removeAttribute("_nodup");
5168 var len = cs.length, c, i, r = cs, cj, ri = -1;
5169 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5172 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5173 return nodupIEXml(cs);
5177 for(i = 1; c = cs[i]; i++){
5182 for(var j = 0; j < i; j++){
5185 for(j = i+1; cj = cs[j]; j++){
5197 function quickDiffIEXml(c1, c2){
5199 for(var i = 0, len = c1.length; i < len; i++){
5200 c1[i].setAttribute("_qdiff", d);
5203 for(var i = 0, len = c2.length; i < len; i++){
5204 if(c2[i].getAttribute("_qdiff") != d){
5205 r[r.length] = c2[i];
5208 for(var i = 0, len = c1.length; i < len; i++){
5209 c1[i].removeAttribute("_qdiff");
5214 function quickDiff(c1, c2){
5215 var len1 = c1.length;
5219 if(isIE && c1[0].selectSingleNode){
5220 return quickDiffIEXml(c1, c2);
5223 for(var i = 0; i < len1; i++){
5227 for(var i = 0, len = c2.length; i < len; i++){
5228 if(c2[i]._qdiff != d){
5229 r[r.length] = c2[i];
5235 function quickId(ns, mode, root, id){
5237 var d = root.ownerDocument || root;
5238 return d.getElementById(id);
5240 ns = getNodes(ns, mode, "*");
5241 return byId(ns, null, id);
5245 getStyle : function(el, name){
5246 return Roo.fly(el).getStyle(name);
5249 * Compiles a selector/xpath query into a reusable function. The returned function
5250 * takes one parameter "root" (optional), which is the context node from where the query should start.
5251 * @param {String} selector The selector/xpath query
5252 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5253 * @return {Function}
5255 compile : function(path, type){
5256 type = type || "select";
5258 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5259 var q = path, mode, lq;
5260 var tk = Roo.DomQuery.matchers;
5261 var tklen = tk.length;
5264 // accept leading mode switch
5265 var lmode = q.match(modeRe);
5266 if(lmode && lmode[1]){
5267 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5268 q = q.replace(lmode[1], "");
5270 // strip leading slashes
5271 while(path.substr(0, 1)=="/"){
5272 path = path.substr(1);
5275 while(q && lq != q){
5277 var tm = q.match(tagTokenRe);
5278 if(type == "select"){
5281 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5283 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5285 q = q.replace(tm[0], "");
5286 }else if(q.substr(0, 1) != '@'){
5287 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5292 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5294 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5296 q = q.replace(tm[0], "");
5299 while(!(mm = q.match(modeRe))){
5300 var matched = false;
5301 for(var j = 0; j < tklen; j++){
5303 var m = q.match(t.re);
5305 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5308 q = q.replace(m[0], "");
5313 // prevent infinite loop on bad selector
5315 throw 'Error parsing selector, parsing failed at "' + q + '"';
5319 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5320 q = q.replace(mm[1], "");
5323 fn[fn.length] = "return nodup(n);\n}";
5326 * list of variables that need from compression as they are used by eval.
5336 * eval:var:byClassName
5338 * eval:var:byAttribute
5339 * eval:var:attrValue
5347 * Selects a group of elements.
5348 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5349 * @param {Node} root (optional) The start of the query (defaults to document).
5352 select : function(path, root, type){
5353 if(!root || root == document){
5356 if(typeof root == "string"){
5357 root = document.getElementById(root);
5359 var paths = path.split(",");
5361 for(var i = 0, len = paths.length; i < len; i++){
5362 var p = paths[i].replace(trimRe, "");
5364 cache[p] = Roo.DomQuery.compile(p);
5366 throw p + " is not a valid selector";
5369 var result = cache[p](root);
5370 if(result && result != document){
5371 results = results.concat(result);
5374 if(paths.length > 1){
5375 return nodup(results);
5381 * Selects a single element.
5382 * @param {String} selector The selector/xpath query
5383 * @param {Node} root (optional) The start of the query (defaults to document).
5386 selectNode : function(path, root){
5387 return Roo.DomQuery.select(path, root)[0];
5391 * Selects the value of a node, optionally replacing null with the defaultValue.
5392 * @param {String} selector The selector/xpath query
5393 * @param {Node} root (optional) The start of the query (defaults to document).
5394 * @param {String} defaultValue
5396 selectValue : function(path, root, defaultValue){
5397 path = path.replace(trimRe, "");
5398 if(!valueCache[path]){
5399 valueCache[path] = Roo.DomQuery.compile(path, "select");
5401 var n = valueCache[path](root);
5402 n = n[0] ? n[0] : n;
5403 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5404 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5408 * Selects the value of a node, parsing integers and floats.
5409 * @param {String} selector The selector/xpath query
5410 * @param {Node} root (optional) The start of the query (defaults to document).
5411 * @param {Number} defaultValue
5414 selectNumber : function(path, root, defaultValue){
5415 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5416 return parseFloat(v);
5420 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5421 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5422 * @param {String} selector The simple selector to test
5425 is : function(el, ss){
5426 if(typeof el == "string"){
5427 el = document.getElementById(el);
5429 var isArray = (el instanceof Array);
5430 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5431 return isArray ? (result.length == el.length) : (result.length > 0);
5435 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5436 * @param {Array} el An array of elements to filter
5437 * @param {String} selector The simple selector to test
5438 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5439 * the selector instead of the ones that match
5442 filter : function(els, ss, nonMatches){
5443 ss = ss.replace(trimRe, "");
5444 if(!simpleCache[ss]){
5445 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5447 var result = simpleCache[ss](els);
5448 return nonMatches ? quickDiff(result, els) : result;
5452 * Collection of matching regular expressions and code snippets.
5456 select: 'n = byClassName(n, null, " {1} ");'
5458 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5459 select: 'n = byPseudo(n, "{1}", "{2}");'
5461 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5462 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5465 select: 'n = byId(n, null, "{1}");'
5468 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5473 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5474 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
5477 "=" : function(a, v){
5480 "!=" : function(a, v){
5483 "^=" : function(a, v){
5484 return a && a.substr(0, v.length) == v;
5486 "$=" : function(a, v){
5487 return a && a.substr(a.length-v.length) == v;
5489 "*=" : function(a, v){
5490 return a && a.indexOf(v) !== -1;
5492 "%=" : function(a, v){
5493 return (a % v) == 0;
5495 "|=" : function(a, v){
5496 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5498 "~=" : function(a, v){
5499 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5504 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5505 * and the argument (if any) supplied in the selector.
5508 "first-child" : function(c){
5509 var r = [], ri = -1, n;
5510 for(var i = 0, ci; ci = n = c[i]; i++){
5511 while((n = n.previousSibling) && n.nodeType != 1);
5519 "last-child" : function(c){
5520 var r = [], ri = -1, n;
5521 for(var i = 0, ci; ci = n = c[i]; i++){
5522 while((n = n.nextSibling) && n.nodeType != 1);
5530 "nth-child" : function(c, a) {
5531 var r = [], ri = -1;
5532 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5533 var f = (m[1] || 1) - 0, l = m[2] - 0;
5534 for(var i = 0, n; n = c[i]; i++){
5535 var pn = n.parentNode;
5536 if (batch != pn._batch) {
5538 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5539 if(cn.nodeType == 1){
5546 if (l == 0 || n.nodeIndex == l){
5549 } else if ((n.nodeIndex + l) % f == 0){
5557 "only-child" : function(c){
5558 var r = [], ri = -1;;
5559 for(var i = 0, ci; ci = c[i]; i++){
5560 if(!prev(ci) && !next(ci)){
5567 "empty" : function(c){
5568 var r = [], ri = -1;
5569 for(var i = 0, ci; ci = c[i]; i++){
5570 var cns = ci.childNodes, j = 0, cn, empty = true;
5573 if(cn.nodeType == 1 || cn.nodeType == 3){
5585 "contains" : function(c, v){
5586 var r = [], ri = -1;
5587 for(var i = 0, ci; ci = c[i]; i++){
5588 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5595 "nodeValue" : function(c, v){
5596 var r = [], ri = -1;
5597 for(var i = 0, ci; ci = c[i]; i++){
5598 if(ci.firstChild && ci.firstChild.nodeValue == v){
5605 "checked" : function(c){
5606 var r = [], ri = -1;
5607 for(var i = 0, ci; ci = c[i]; i++){
5608 if(ci.checked == true){
5615 "not" : function(c, ss){
5616 return Roo.DomQuery.filter(c, ss, true);
5619 "odd" : function(c){
5620 return this["nth-child"](c, "odd");
5623 "even" : function(c){
5624 return this["nth-child"](c, "even");
5627 "nth" : function(c, a){
5628 return c[a-1] || [];
5631 "first" : function(c){
5635 "last" : function(c){
5636 return c[c.length-1] || [];
5639 "has" : function(c, ss){
5640 var s = Roo.DomQuery.select;
5641 var r = [], ri = -1;
5642 for(var i = 0, ci; ci = c[i]; i++){
5643 if(s(ss, ci).length > 0){
5650 "next" : function(c, ss){
5651 var is = Roo.DomQuery.is;
5652 var r = [], ri = -1;
5653 for(var i = 0, ci; ci = c[i]; i++){
5662 "prev" : function(c, ss){
5663 var is = Roo.DomQuery.is;
5664 var r = [], ri = -1;
5665 for(var i = 0, ci; ci = c[i]; i++){
5678 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5679 * @param {String} path The selector/xpath query
5680 * @param {Node} root (optional) The start of the query (defaults to document).
5685 Roo.query = Roo.DomQuery.select;
5688 * Ext JS Library 1.1.1
5689 * Copyright(c) 2006-2007, Ext JS, LLC.
5691 * Originally Released Under LGPL - original licence link has changed is not relivant.
5694 * <script type="text/javascript">
5698 * @class Roo.util.Observable
5699 * Base class that provides a common interface for publishing events. Subclasses are expected to
5700 * to have a property "events" with all the events defined.<br>
5703 Employee = function(name){
5710 Roo.extend(Employee, Roo.util.Observable);
5712 * @param {Object} config properties to use (incuding events / listeners)
5715 Roo.util.Observable = function(cfg){
5718 this.addEvents(cfg.events || {});
5720 delete cfg.events; // make sure
5723 Roo.apply(this, cfg);
5726 this.on(this.listeners);
5727 delete this.listeners;
5730 Roo.util.Observable.prototype = {
5732 * @cfg {Object} listeners list of events and functions to call for this object,
5736 'click' : function(e) {
5746 * Fires the specified event with the passed parameters (minus the event name).
5747 * @param {String} eventName
5748 * @param {Object...} args Variable number of parameters are passed to handlers
5749 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5751 fireEvent : function(){
5752 var ce = this.events[arguments[0].toLowerCase()];
5753 if(typeof ce == "object"){
5754 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5761 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5764 * Appends an event handler to this component
5765 * @param {String} eventName The type of event to listen for
5766 * @param {Function} handler The method the event invokes
5767 * @param {Object} scope (optional) The scope in which to execute the handler
5768 * function. The handler function's "this" context.
5769 * @param {Object} options (optional) An object containing handler configuration
5770 * properties. This may contain any of the following properties:<ul>
5771 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5772 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5773 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5774 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5775 * by the specified number of milliseconds. If the event fires again within that time, the original
5776 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5779 * <b>Combining Options</b><br>
5780 * Using the options argument, it is possible to combine different types of listeners:<br>
5782 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5784 el.on('click', this.onClick, this, {
5791 * <b>Attaching multiple handlers in 1 call</b><br>
5792 * The method also allows for a single argument to be passed which is a config object containing properties
5793 * which specify multiple handlers.
5802 fn: this.onMouseOver,
5806 fn: this.onMouseOut,
5812 * Or a shorthand syntax which passes the same scope object to all handlers:
5815 'click': this.onClick,
5816 'mouseover': this.onMouseOver,
5817 'mouseout': this.onMouseOut,
5822 addListener : function(eventName, fn, scope, o){
5823 if(typeof eventName == "object"){
5826 if(this.filterOptRe.test(e)){
5829 if(typeof o[e] == "function"){
5831 this.addListener(e, o[e], o.scope, o);
5833 // individual options
5834 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5839 o = (!o || typeof o == "boolean") ? {} : o;
5840 eventName = eventName.toLowerCase();
5841 var ce = this.events[eventName] || true;
5842 if(typeof ce == "boolean"){
5843 ce = new Roo.util.Event(this, eventName);
5844 this.events[eventName] = ce;
5846 ce.addListener(fn, scope, o);
5850 * Removes a listener
5851 * @param {String} eventName The type of event to listen for
5852 * @param {Function} handler The handler to remove
5853 * @param {Object} scope (optional) The scope (this object) for the handler
5855 removeListener : function(eventName, fn, scope){
5856 var ce = this.events[eventName.toLowerCase()];
5857 if(typeof ce == "object"){
5858 ce.removeListener(fn, scope);
5863 * Removes all listeners for this object
5865 purgeListeners : function(){
5866 for(var evt in this.events){
5867 if(typeof this.events[evt] == "object"){
5868 this.events[evt].clearListeners();
5873 relayEvents : function(o, events){
5874 var createHandler = function(ename){
5876 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5879 for(var i = 0, len = events.length; i < len; i++){
5880 var ename = events[i];
5881 if(!this.events[ename]){ this.events[ename] = true; };
5882 o.on(ename, createHandler(ename), this);
5887 * Used to define events on this Observable
5888 * @param {Object} object The object with the events defined
5890 addEvents : function(o){
5894 Roo.applyIf(this.events, o);
5898 * Checks to see if this object has any listeners for a specified event
5899 * @param {String} eventName The name of the event to check for
5900 * @return {Boolean} True if the event is being listened for, else false
5902 hasListener : function(eventName){
5903 var e = this.events[eventName];
5904 return typeof e == "object" && e.listeners.length > 0;
5908 * Appends an event handler to this element (shorthand for addListener)
5909 * @param {String} eventName The type of event to listen for
5910 * @param {Function} handler The method the event invokes
5911 * @param {Object} scope (optional) The scope in which to execute the handler
5912 * function. The handler function's "this" context.
5913 * @param {Object} options (optional)
5916 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5918 * Removes a listener (shorthand for removeListener)
5919 * @param {String} eventName The type of event to listen for
5920 * @param {Function} handler The handler to remove
5921 * @param {Object} scope (optional) The scope (this object) for the handler
5924 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5927 * Starts capture on the specified Observable. All events will be passed
5928 * to the supplied function with the event name + standard signature of the event
5929 * <b>before</b> the event is fired. If the supplied function returns false,
5930 * the event will not fire.
5931 * @param {Observable} o The Observable to capture
5932 * @param {Function} fn The function to call
5933 * @param {Object} scope (optional) The scope (this object) for the fn
5936 Roo.util.Observable.capture = function(o, fn, scope){
5937 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5941 * Removes <b>all</b> added captures from the Observable.
5942 * @param {Observable} o The Observable to release
5945 Roo.util.Observable.releaseCapture = function(o){
5946 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5951 var createBuffered = function(h, o, scope){
5952 var task = new Roo.util.DelayedTask();
5954 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5958 var createSingle = function(h, e, fn, scope){
5960 e.removeListener(fn, scope);
5961 return h.apply(scope, arguments);
5965 var createDelayed = function(h, o, scope){
5967 var args = Array.prototype.slice.call(arguments, 0);
5968 setTimeout(function(){
5969 h.apply(scope, args);
5974 Roo.util.Event = function(obj, name){
5977 this.listeners = [];
5980 Roo.util.Event.prototype = {
5981 addListener : function(fn, scope, options){
5982 var o = options || {};
5983 scope = scope || this.obj;
5984 if(!this.isListening(fn, scope)){
5985 var l = {fn: fn, scope: scope, options: o};
5988 h = createDelayed(h, o, scope);
5991 h = createSingle(h, this, fn, scope);
5994 h = createBuffered(h, o, scope);
5997 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5998 this.listeners.push(l);
6000 this.listeners = this.listeners.slice(0);
6001 this.listeners.push(l);
6006 findListener : function(fn, scope){
6007 scope = scope || this.obj;
6008 var ls = this.listeners;
6009 for(var i = 0, len = ls.length; i < len; i++){
6011 if(l.fn == fn && l.scope == scope){
6018 isListening : function(fn, scope){
6019 return this.findListener(fn, scope) != -1;
6022 removeListener : function(fn, scope){
6024 if((index = this.findListener(fn, scope)) != -1){
6026 this.listeners.splice(index, 1);
6028 this.listeners = this.listeners.slice(0);
6029 this.listeners.splice(index, 1);
6036 clearListeners : function(){
6037 this.listeners = [];
6041 var ls = this.listeners, scope, len = ls.length;
6044 var args = Array.prototype.slice.call(arguments, 0);
6045 for(var i = 0; i < len; i++){
6047 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6048 this.firing = false;
6052 this.firing = false;
6059 * Copyright(c) 2007-2017, Roo J Solutions Ltd
6066 * @class Roo.Document
6067 * @extends Roo.util.Observable
6068 * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6070 * @param {Object} config the methods and properties of the 'base' class for the application.
6072 * Generic Page handler - implement this to start your app..
6075 * MyProject = new Roo.Document({
6077 'load' : true // your events..
6080 'ready' : function() {
6081 // fired on Roo.onReady()
6086 Roo.Document = function(cfg) {
6091 Roo.util.Observable.call(this,cfg);
6095 Roo.onReady(function() {
6096 _this.fireEvent('ready');
6102 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6104 * Ext JS Library 1.1.1
6105 * Copyright(c) 2006-2007, Ext JS, LLC.
6107 * Originally Released Under LGPL - original licence link has changed is not relivant.
6110 * <script type="text/javascript">
6114 * @class Roo.EventManager
6115 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6116 * several useful events directly.
6117 * See {@link Roo.EventObject} for more details on normalized event objects.
6120 Roo.EventManager = function(){
6121 var docReadyEvent, docReadyProcId, docReadyState = false;
6122 var resizeEvent, resizeTask, textEvent, textSize;
6123 var E = Roo.lib.Event;
6124 var D = Roo.lib.Dom;
6129 var fireDocReady = function(){
6131 docReadyState = true;
6134 clearInterval(docReadyProcId);
6136 if(Roo.isGecko || Roo.isOpera) {
6137 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6140 var defer = document.getElementById("ie-deferred-loader");
6142 defer.onreadystatechange = null;
6143 defer.parentNode.removeChild(defer);
6147 docReadyEvent.fire();
6148 docReadyEvent.clearListeners();
6153 var initDocReady = function(){
6154 docReadyEvent = new Roo.util.Event();
6155 if(Roo.isGecko || Roo.isOpera) {
6156 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6158 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6159 var defer = document.getElementById("ie-deferred-loader");
6160 defer.onreadystatechange = function(){
6161 if(this.readyState == "complete"){
6165 }else if(Roo.isSafari){
6166 docReadyProcId = setInterval(function(){
6167 var rs = document.readyState;
6168 if(rs == "complete") {
6173 // no matter what, make sure it fires on load
6174 E.on(window, "load", fireDocReady);
6177 var createBuffered = function(h, o){
6178 var task = new Roo.util.DelayedTask(h);
6180 // create new event object impl so new events don't wipe out properties
6181 e = new Roo.EventObjectImpl(e);
6182 task.delay(o.buffer, h, null, [e]);
6186 var createSingle = function(h, el, ename, fn){
6188 Roo.EventManager.removeListener(el, ename, fn);
6193 var createDelayed = function(h, o){
6195 // create new event object impl so new events don't wipe out properties
6196 e = new Roo.EventObjectImpl(e);
6197 setTimeout(function(){
6202 var transitionEndVal = false;
6204 var transitionEnd = function()
6206 if (transitionEndVal) {
6207 return transitionEndVal;
6209 var el = document.createElement('div');
6211 var transEndEventNames = {
6212 WebkitTransition : 'webkitTransitionEnd',
6213 MozTransition : 'transitionend',
6214 OTransition : 'oTransitionEnd otransitionend',
6215 transition : 'transitionend'
6218 for (var name in transEndEventNames) {
6219 if (el.style[name] !== undefined) {
6220 transitionEndVal = transEndEventNames[name];
6221 return transitionEndVal ;
6227 var listen = function(element, ename, opt, fn, scope){
6228 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6229 fn = fn || o.fn; scope = scope || o.scope;
6230 var el = Roo.getDom(element);
6234 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6237 if (ename == 'transitionend') {
6238 ename = transitionEnd();
6240 var h = function(e){
6241 e = Roo.EventObject.setEvent(e);
6244 t = e.getTarget(o.delegate, el);
6251 if(o.stopEvent === true){
6254 if(o.preventDefault === true){
6257 if(o.stopPropagation === true){
6258 e.stopPropagation();
6261 if(o.normalized === false){
6265 fn.call(scope || el, e, t, o);
6268 h = createDelayed(h, o);
6271 h = createSingle(h, el, ename, fn);
6274 h = createBuffered(h, o);
6276 fn._handlers = fn._handlers || [];
6279 fn._handlers.push([Roo.id(el), ename, h]);
6284 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6285 el.addEventListener("DOMMouseScroll", h, false);
6286 E.on(window, 'unload', function(){
6287 el.removeEventListener("DOMMouseScroll", h, false);
6290 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6291 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6296 var stopListening = function(el, ename, fn){
6297 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6299 for(var i = 0, len = hds.length; i < len; i++){
6301 if(h[0] == id && h[1] == ename){
6308 E.un(el, ename, hd);
6309 el = Roo.getDom(el);
6310 if(ename == "mousewheel" && el.addEventListener){
6311 el.removeEventListener("DOMMouseScroll", hd, false);
6313 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6314 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6318 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6325 * @scope Roo.EventManager
6330 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6331 * object with a Roo.EventObject
6332 * @param {Function} fn The method the event invokes
6333 * @param {Object} scope An object that becomes the scope of the handler
6334 * @param {boolean} override If true, the obj passed in becomes
6335 * the execution scope of the listener
6336 * @return {Function} The wrapped function
6339 wrap : function(fn, scope, override){
6341 Roo.EventObject.setEvent(e);
6342 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6347 * Appends an event handler to an element (shorthand for addListener)
6348 * @param {String/HTMLElement} element The html element or id to assign the
6349 * @param {String} eventName The type of event to listen for
6350 * @param {Function} handler The method the event invokes
6351 * @param {Object} scope (optional) The scope in which to execute the handler
6352 * function. The handler function's "this" context.
6353 * @param {Object} options (optional) An object containing handler configuration
6354 * properties. This may contain any of the following properties:<ul>
6355 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6356 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6357 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6358 * <li>preventDefault {Boolean} True to prevent the default action</li>
6359 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6360 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6361 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6362 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6363 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6364 * by the specified number of milliseconds. If the event fires again within that time, the original
6365 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6368 * <b>Combining Options</b><br>
6369 * Using the options argument, it is possible to combine different types of listeners:<br>
6371 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6373 el.on('click', this.onClick, this, {
6380 * <b>Attaching multiple handlers in 1 call</b><br>
6381 * The method also allows for a single argument to be passed which is a config object containing properties
6382 * which specify multiple handlers.
6392 fn: this.onMouseOver
6401 * Or a shorthand syntax:<br>
6404 'click' : this.onClick,
6405 'mouseover' : this.onMouseOver,
6406 'mouseout' : this.onMouseOut
6410 addListener : function(element, eventName, fn, scope, options){
6411 if(typeof eventName == "object"){
6417 if(typeof o[e] == "function"){
6419 listen(element, e, o, o[e], o.scope);
6421 // individual options
6422 listen(element, e, o[e]);
6427 return listen(element, eventName, options, fn, scope);
6431 * Removes an event handler
6433 * @param {String/HTMLElement} element The id or html element to remove the
6435 * @param {String} eventName The type of event
6436 * @param {Function} fn
6437 * @return {Boolean} True if a listener was actually removed
6439 removeListener : function(element, eventName, fn){
6440 return stopListening(element, eventName, fn);
6444 * Fires when the document is ready (before onload and before images are loaded). Can be
6445 * accessed shorthanded Roo.onReady().
6446 * @param {Function} fn The method the event invokes
6447 * @param {Object} scope An object that becomes the scope of the handler
6448 * @param {boolean} options
6450 onDocumentReady : function(fn, scope, options){
6451 if(docReadyState){ // if it already fired
6452 docReadyEvent.addListener(fn, scope, options);
6453 docReadyEvent.fire();
6454 docReadyEvent.clearListeners();
6460 docReadyEvent.addListener(fn, scope, options);
6464 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6465 * @param {Function} fn The method the event invokes
6466 * @param {Object} scope An object that becomes the scope of the handler
6467 * @param {boolean} options
6469 onWindowResize : function(fn, scope, options){
6471 resizeEvent = new Roo.util.Event();
6472 resizeTask = new Roo.util.DelayedTask(function(){
6473 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6475 E.on(window, "resize", function(){
6477 resizeTask.delay(50);
6479 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6483 resizeEvent.addListener(fn, scope, options);
6487 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6488 * @param {Function} fn The method the event invokes
6489 * @param {Object} scope An object that becomes the scope of the handler
6490 * @param {boolean} options
6492 onTextResize : function(fn, scope, options){
6494 textEvent = new Roo.util.Event();
6495 var textEl = new Roo.Element(document.createElement('div'));
6496 textEl.dom.className = 'x-text-resize';
6497 textEl.dom.innerHTML = 'X';
6498 textEl.appendTo(document.body);
6499 textSize = textEl.dom.offsetHeight;
6500 setInterval(function(){
6501 if(textEl.dom.offsetHeight != textSize){
6502 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6504 }, this.textResizeInterval);
6506 textEvent.addListener(fn, scope, options);
6510 * Removes the passed window resize listener.
6511 * @param {Function} fn The method the event invokes
6512 * @param {Object} scope The scope of handler
6514 removeResizeListener : function(fn, scope){
6516 resizeEvent.removeListener(fn, scope);
6521 fireResize : function(){
6523 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6527 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6531 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6533 textResizeInterval : 50
6538 * @scopeAlias pub=Roo.EventManager
6542 * Appends an event handler to an element (shorthand for addListener)
6543 * @param {String/HTMLElement} element The html element or id to assign the
6544 * @param {String} eventName The type of event to listen for
6545 * @param {Function} handler The method the event invokes
6546 * @param {Object} scope (optional) The scope in which to execute the handler
6547 * function. The handler function's "this" context.
6548 * @param {Object} options (optional) An object containing handler configuration
6549 * properties. This may contain any of the following properties:<ul>
6550 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6551 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6552 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6553 * <li>preventDefault {Boolean} True to prevent the default action</li>
6554 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6555 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6556 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6557 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6558 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6559 * by the specified number of milliseconds. If the event fires again within that time, the original
6560 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6563 * <b>Combining Options</b><br>
6564 * Using the options argument, it is possible to combine different types of listeners:<br>
6566 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6568 el.on('click', this.onClick, this, {
6575 * <b>Attaching multiple handlers in 1 call</b><br>
6576 * The method also allows for a single argument to be passed which is a config object containing properties
6577 * which specify multiple handlers.
6587 fn: this.onMouseOver
6596 * Or a shorthand syntax:<br>
6599 'click' : this.onClick,
6600 'mouseover' : this.onMouseOver,
6601 'mouseout' : this.onMouseOut
6605 pub.on = pub.addListener;
6606 pub.un = pub.removeListener;
6608 pub.stoppedMouseDownEvent = new Roo.util.Event();
6612 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6613 * @param {Function} fn The method the event invokes
6614 * @param {Object} scope An object that becomes the scope of the handler
6615 * @param {boolean} override If true, the obj passed in becomes
6616 * the execution scope of the listener
6620 Roo.onReady = Roo.EventManager.onDocumentReady;
6622 Roo.onReady(function(){
6623 var bd = Roo.get(document.body);
6628 : Roo.isGecko ? "roo-gecko"
6629 : Roo.isOpera ? "roo-opera"
6630 : Roo.isSafari ? "roo-safari" : ""];
6633 cls.push("roo-mac");
6636 cls.push("roo-linux");
6639 cls.push("roo-ios");
6642 cls.push("roo-touch");
6644 if(Roo.isBorderBox){
6645 cls.push('roo-border-box');
6647 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6648 var p = bd.dom.parentNode;
6650 p.className += ' roo-strict';
6653 bd.addClass(cls.join(' '));
6657 * @class Roo.EventObject
6658 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6659 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6662 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6664 var target = e.getTarget();
6667 var myDiv = Roo.get("myDiv");
6668 myDiv.on("click", handleClick);
6670 Roo.EventManager.on("myDiv", 'click', handleClick);
6671 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6675 Roo.EventObject = function(){
6677 var E = Roo.lib.Event;
6679 // safari keypress events for special keys return bad keycodes
6682 63235 : 39, // right
6685 63276 : 33, // page up
6686 63277 : 34, // page down
6687 63272 : 46, // delete
6692 // normalize button clicks
6693 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6694 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6696 Roo.EventObjectImpl = function(e){
6698 this.setEvent(e.browserEvent || e);
6701 Roo.EventObjectImpl.prototype = {
6703 * Used to fix doc tools.
6704 * @scope Roo.EventObject.prototype
6710 /** The normal browser event */
6711 browserEvent : null,
6712 /** The button pressed in a mouse event */
6714 /** True if the shift key was down during the event */
6716 /** True if the control key was down during the event */
6718 /** True if the alt key was down during the event */
6777 setEvent : function(e){
6778 if(e == this || (e && e.browserEvent)){ // already wrapped
6781 this.browserEvent = e;
6783 // normalize buttons
6784 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6785 if(e.type == 'click' && this.button == -1){
6789 this.shiftKey = e.shiftKey;
6790 // mac metaKey behaves like ctrlKey
6791 this.ctrlKey = e.ctrlKey || e.metaKey;
6792 this.altKey = e.altKey;
6793 // in getKey these will be normalized for the mac
6794 this.keyCode = e.keyCode;
6795 // keyup warnings on firefox.
6796 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6797 // cache the target for the delayed and or buffered events
6798 this.target = E.getTarget(e);
6800 this.xy = E.getXY(e);
6803 this.shiftKey = false;
6804 this.ctrlKey = false;
6805 this.altKey = false;
6815 * Stop the event (preventDefault and stopPropagation)
6817 stopEvent : function(){
6818 if(this.browserEvent){
6819 if(this.browserEvent.type == 'mousedown'){
6820 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6822 E.stopEvent(this.browserEvent);
6827 * Prevents the browsers default handling of the event.
6829 preventDefault : function(){
6830 if(this.browserEvent){
6831 E.preventDefault(this.browserEvent);
6836 isNavKeyPress : function(){
6837 var k = this.keyCode;
6838 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6839 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6842 isSpecialKey : function(){
6843 var k = this.keyCode;
6844 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6845 (k == 16) || (k == 17) ||
6846 (k >= 18 && k <= 20) ||
6847 (k >= 33 && k <= 35) ||
6848 (k >= 36 && k <= 39) ||
6849 (k >= 44 && k <= 45);
6852 * Cancels bubbling of the event.
6854 stopPropagation : function(){
6855 if(this.browserEvent){
6856 if(this.type == 'mousedown'){
6857 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6859 E.stopPropagation(this.browserEvent);
6864 * Gets the key code for the event.
6867 getCharCode : function(){
6868 return this.charCode || this.keyCode;
6872 * Returns a normalized keyCode for the event.
6873 * @return {Number} The key code
6875 getKey : function(){
6876 var k = this.keyCode || this.charCode;
6877 return Roo.isSafari ? (safariKeys[k] || k) : k;
6881 * Gets the x coordinate of the event.
6884 getPageX : function(){
6889 * Gets the y coordinate of the event.
6892 getPageY : function(){
6897 * Gets the time of the event.
6900 getTime : function(){
6901 if(this.browserEvent){
6902 return E.getTime(this.browserEvent);
6908 * Gets the page coordinates of the event.
6909 * @return {Array} The xy values like [x, y]
6916 * Gets the target for the event.
6917 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6918 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6919 search as a number or element (defaults to 10 || document.body)
6920 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6921 * @return {HTMLelement}
6923 getTarget : function(selector, maxDepth, returnEl){
6924 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6927 * Gets the related target.
6928 * @return {HTMLElement}
6930 getRelatedTarget : function(){
6931 if(this.browserEvent){
6932 return E.getRelatedTarget(this.browserEvent);
6938 * Normalizes mouse wheel delta across browsers
6939 * @return {Number} The delta
6941 getWheelDelta : function(){
6942 var e = this.browserEvent;
6944 if(e.wheelDelta){ /* IE/Opera. */
6945 delta = e.wheelDelta/120;
6946 }else if(e.detail){ /* Mozilla case. */
6947 delta = -e.detail/3;
6953 * Returns true if the control, meta, shift or alt key was pressed during this event.
6956 hasModifier : function(){
6957 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6961 * Returns true if the target of this event equals el or is a child of el
6962 * @param {String/HTMLElement/Element} el
6963 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6966 within : function(el, related){
6967 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6968 return t && Roo.fly(el).contains(t);
6971 getPoint : function(){
6972 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6976 return new Roo.EventObjectImpl();
6981 * Ext JS Library 1.1.1
6982 * Copyright(c) 2006-2007, Ext JS, LLC.
6984 * Originally Released Under LGPL - original licence link has changed is not relivant.
6987 * <script type="text/javascript">
6991 // was in Composite Element!??!?!
6994 var D = Roo.lib.Dom;
6995 var E = Roo.lib.Event;
6996 var A = Roo.lib.Anim;
6998 // local style camelizing for speed
7000 var camelRe = /(-[a-z])/gi;
7001 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7002 var view = document.defaultView;
7005 * @class Roo.Element
7006 * Represents an Element in the DOM.<br><br>
7009 var el = Roo.get("my-div");
7012 var el = getEl("my-div");
7014 // or with a DOM element
7015 var el = Roo.get(myDivElement);
7017 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7018 * each call instead of constructing a new one.<br><br>
7019 * <b>Animations</b><br />
7020 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7021 * should either be a boolean (true) or an object literal with animation options. The animation options are:
7023 Option Default Description
7024 --------- -------- ---------------------------------------------
7025 duration .35 The duration of the animation in seconds
7026 easing easeOut The YUI easing method
7027 callback none A function to execute when the anim completes
7028 scope this The scope (this) of the callback function
7030 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7031 * manipulate the animation. Here's an example:
7033 var el = Roo.get("my-div");
7038 // default animation
7039 el.setWidth(100, true);
7041 // animation with some options set
7048 // using the "anim" property to get the Anim object
7054 el.setWidth(100, opt);
7056 if(opt.anim.isAnimated()){
7060 * <b> Composite (Collections of) Elements</b><br />
7061 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7062 * @constructor Create a new Element directly.
7063 * @param {String/HTMLElement} element
7064 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
7066 Roo.Element = function(element, forceNew){
7067 var dom = typeof element == "string" ?
7068 document.getElementById(element) : element;
7069 if(!dom){ // invalid id/element
7073 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7074 return Roo.Element.cache[id];
7084 * The DOM element ID
7087 this.id = id || Roo.id(dom);
7090 var El = Roo.Element;
7094 * The element's default display mode (defaults to "")
7097 originalDisplay : "",
7101 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7107 * Sets the element's visibility mode. When setVisible() is called it
7108 * will use this to determine whether to set the visibility or the display property.
7109 * @param visMode Element.VISIBILITY or Element.DISPLAY
7110 * @return {Roo.Element} this
7112 setVisibilityMode : function(visMode){
7113 this.visibilityMode = visMode;
7117 * Convenience method for setVisibilityMode(Element.DISPLAY)
7118 * @param {String} display (optional) What to set display to when visible
7119 * @return {Roo.Element} this
7121 enableDisplayMode : function(display){
7122 this.setVisibilityMode(El.DISPLAY);
7123 if(typeof display != "undefined") { this.originalDisplay = display; }
7128 * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7129 * @param {String} selector The simple selector to test
7130 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7131 search as a number or element (defaults to 10 || document.body)
7132 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7133 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7135 findParent : function(simpleSelector, maxDepth, returnEl){
7136 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7137 maxDepth = maxDepth || 50;
7138 if(typeof maxDepth != "number"){
7139 stopEl = Roo.getDom(maxDepth);
7142 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7143 if(dq.is(p, simpleSelector)){
7144 return returnEl ? Roo.get(p) : p;
7154 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7155 * @param {String} selector The simple selector to test
7156 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7157 search as a number or element (defaults to 10 || document.body)
7158 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7159 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7161 findParentNode : function(simpleSelector, maxDepth, returnEl){
7162 var p = Roo.fly(this.dom.parentNode, '_internal');
7163 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7167 * Looks at the scrollable parent element
7169 findScrollableParent : function(){
7171 var el = Roo.get(this.dom.parentNode);
7173 while (el && !el.isScrollable() && el.dom.nodeName.toLowerCase() != 'body'){
7174 el = Roo.get(el.dom.parentNode);
7177 if(!el.isScrollable()){
7185 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7186 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7187 * @param {String} selector The simple selector to test
7188 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7189 search as a number or element (defaults to 10 || document.body)
7190 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7192 up : function(simpleSelector, maxDepth){
7193 return this.findParentNode(simpleSelector, maxDepth, true);
7199 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7200 * @param {String} selector The simple selector to test
7201 * @return {Boolean} True if this element matches the selector, else false
7203 is : function(simpleSelector){
7204 return Roo.DomQuery.is(this.dom, simpleSelector);
7208 * Perform animation on this element.
7209 * @param {Object} args The YUI animation control args
7210 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7211 * @param {Function} onComplete (optional) Function to call when animation completes
7212 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7213 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7214 * @return {Roo.Element} this
7216 animate : function(args, duration, onComplete, easing, animType){
7217 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7222 * @private Internal animation call
7224 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7225 animType = animType || 'run';
7227 var anim = Roo.lib.Anim[animType](
7229 (opt.duration || defaultDur) || .35,
7230 (opt.easing || defaultEase) || 'easeOut',
7232 Roo.callback(cb, this);
7233 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7241 // private legacy anim prep
7242 preanim : function(a, i){
7243 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7247 * Removes worthless text nodes
7248 * @param {Boolean} forceReclean (optional) By default the element
7249 * keeps track if it has been cleaned already so
7250 * you can call this over and over. However, if you update the element and
7251 * need to force a reclean, you can pass true.
7253 clean : function(forceReclean){
7254 if(this.isCleaned && forceReclean !== true){
7258 var d = this.dom, n = d.firstChild, ni = -1;
7260 var nx = n.nextSibling;
7261 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7268 this.isCleaned = true;
7273 calcOffsetsTo : function(el){
7276 var restorePos = false;
7277 if(el.getStyle('position') == 'static'){
7278 el.position('relative');
7283 while(op && op != d && op.tagName != 'HTML'){
7286 op = op.offsetParent;
7289 el.position('static');
7295 * Scrolls this element into view within the passed container.
7296 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7297 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7298 * @return {Roo.Element} this
7300 scrollIntoView : function(container, hscroll){
7301 var c = Roo.getDom(container) || document.body;
7304 var o = this.calcOffsetsTo(c),
7307 b = t+el.offsetHeight,
7308 r = l+el.offsetWidth;
7310 var ch = c.clientHeight;
7311 var ct = parseInt(c.scrollTop, 10);
7312 var cl = parseInt(c.scrollLeft, 10);
7314 var cr = cl + c.clientWidth;
7322 if(hscroll !== false){
7326 c.scrollLeft = r-c.clientWidth;
7333 scrollChildIntoView : function(child, hscroll){
7334 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7338 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7339 * the new height may not be available immediately.
7340 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7341 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7342 * @param {Function} onComplete (optional) Function to call when animation completes
7343 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7344 * @return {Roo.Element} this
7346 autoHeight : function(animate, duration, onComplete, easing){
7347 var oldHeight = this.getHeight();
7349 this.setHeight(1); // force clipping
7350 setTimeout(function(){
7351 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7353 this.setHeight(height);
7355 if(typeof onComplete == "function"){
7359 this.setHeight(oldHeight); // restore original height
7360 this.setHeight(height, animate, duration, function(){
7362 if(typeof onComplete == "function") { onComplete(); }
7363 }.createDelegate(this), easing);
7365 }.createDelegate(this), 0);
7370 * Returns true if this element is an ancestor of the passed element
7371 * @param {HTMLElement/String} el The element to check
7372 * @return {Boolean} True if this element is an ancestor of el, else false
7374 contains : function(el){
7375 if(!el){return false;}
7376 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7380 * Checks whether the element is currently visible using both visibility and display properties.
7381 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7382 * @return {Boolean} True if the element is currently visible, else false
7384 isVisible : function(deep) {
7385 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7386 if(deep !== true || !vis){
7389 var p = this.dom.parentNode;
7390 while(p && p.tagName.toLowerCase() != "body"){
7391 if(!Roo.fly(p, '_isVisible').isVisible()){
7400 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7401 * @param {String} selector The CSS selector
7402 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7403 * @return {CompositeElement/CompositeElementLite} The composite element
7405 select : function(selector, unique){
7406 return El.select(selector, unique, this.dom);
7410 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7411 * @param {String} selector The CSS selector
7412 * @return {Array} An array of the matched nodes
7414 query : function(selector, unique){
7415 return Roo.DomQuery.select(selector, this.dom);
7419 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7420 * @param {String} selector The CSS selector
7421 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7422 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7424 child : function(selector, returnDom){
7425 var n = Roo.DomQuery.selectNode(selector, this.dom);
7426 return returnDom ? n : Roo.get(n);
7430 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7431 * @param {String} selector The CSS selector
7432 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7433 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7435 down : function(selector, returnDom){
7436 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7437 return returnDom ? n : Roo.get(n);
7441 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7442 * @param {String} group The group the DD object is member of
7443 * @param {Object} config The DD config object
7444 * @param {Object} overrides An object containing methods to override/implement on the DD object
7445 * @return {Roo.dd.DD} The DD object
7447 initDD : function(group, config, overrides){
7448 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7449 return Roo.apply(dd, overrides);
7453 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7454 * @param {String} group The group the DDProxy object is member of
7455 * @param {Object} config The DDProxy config object
7456 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7457 * @return {Roo.dd.DDProxy} The DDProxy object
7459 initDDProxy : function(group, config, overrides){
7460 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7461 return Roo.apply(dd, overrides);
7465 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7466 * @param {String} group The group the DDTarget object is member of
7467 * @param {Object} config The DDTarget config object
7468 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7469 * @return {Roo.dd.DDTarget} The DDTarget object
7471 initDDTarget : function(group, config, overrides){
7472 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7473 return Roo.apply(dd, overrides);
7477 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7478 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7479 * @param {Boolean} visible Whether the element is visible
7480 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7481 * @return {Roo.Element} this
7483 setVisible : function(visible, animate){
7485 if(this.visibilityMode == El.DISPLAY){
7486 this.setDisplayed(visible);
7489 this.dom.style.visibility = visible ? "visible" : "hidden";
7492 // closure for composites
7494 var visMode = this.visibilityMode;
7496 this.setOpacity(.01);
7497 this.setVisible(true);
7499 this.anim({opacity: { to: (visible?1:0) }},
7500 this.preanim(arguments, 1),
7501 null, .35, 'easeIn', function(){
7503 if(visMode == El.DISPLAY){
7504 dom.style.display = "none";
7506 dom.style.visibility = "hidden";
7508 Roo.get(dom).setOpacity(1);
7516 * Returns true if display is not "none"
7519 isDisplayed : function() {
7520 return this.getStyle("display") != "none";
7524 * Toggles the element's visibility or display, depending on visibility mode.
7525 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7526 * @return {Roo.Element} this
7528 toggle : function(animate){
7529 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7534 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7535 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7536 * @return {Roo.Element} this
7538 setDisplayed : function(value) {
7539 if(typeof value == "boolean"){
7540 value = value ? this.originalDisplay : "none";
7542 this.setStyle("display", value);
7547 * Tries to focus the element. Any exceptions are caught and ignored.
7548 * @return {Roo.Element} this
7550 focus : function() {
7558 * Tries to blur the element. Any exceptions are caught and ignored.
7559 * @return {Roo.Element} this
7569 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7570 * @param {String/Array} className The CSS class to add, or an array of classes
7571 * @return {Roo.Element} this
7573 addClass : function(className){
7574 if(className instanceof Array){
7575 for(var i = 0, len = className.length; i < len; i++) {
7576 this.addClass(className[i]);
7579 if(className && !this.hasClass(className)){
7580 this.dom.className = this.dom.className + " " + className;
7587 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7588 * @param {String/Array} className The CSS class to add, or an array of classes
7589 * @return {Roo.Element} this
7591 radioClass : function(className){
7592 var siblings = this.dom.parentNode.childNodes;
7593 for(var i = 0; i < siblings.length; i++) {
7594 var s = siblings[i];
7595 if(s.nodeType == 1){
7596 Roo.get(s).removeClass(className);
7599 this.addClass(className);
7604 * Removes one or more CSS classes from the element.
7605 * @param {String/Array} className The CSS class to remove, or an array of classes
7606 * @return {Roo.Element} this
7608 removeClass : function(className){
7609 if(!className || !this.dom.className){
7612 if(className instanceof Array){
7613 for(var i = 0, len = className.length; i < len; i++) {
7614 this.removeClass(className[i]);
7617 if(this.hasClass(className)){
7618 var re = this.classReCache[className];
7620 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7621 this.classReCache[className] = re;
7623 this.dom.className =
7624 this.dom.className.replace(re, " ");
7634 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7635 * @param {String} className The CSS class to toggle
7636 * @return {Roo.Element} this
7638 toggleClass : function(className){
7639 if(this.hasClass(className)){
7640 this.removeClass(className);
7642 this.addClass(className);
7648 * Checks if the specified CSS class exists on this element's DOM node.
7649 * @param {String} className The CSS class to check for
7650 * @return {Boolean} True if the class exists, else false
7652 hasClass : function(className){
7653 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7657 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7658 * @param {String} oldClassName The CSS class to replace
7659 * @param {String} newClassName The replacement CSS class
7660 * @return {Roo.Element} this
7662 replaceClass : function(oldClassName, newClassName){
7663 this.removeClass(oldClassName);
7664 this.addClass(newClassName);
7669 * Returns an object with properties matching the styles requested.
7670 * For example, el.getStyles('color', 'font-size', 'width') might return
7671 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7672 * @param {String} style1 A style name
7673 * @param {String} style2 A style name
7674 * @param {String} etc.
7675 * @return {Object} The style object
7677 getStyles : function(){
7678 var a = arguments, len = a.length, r = {};
7679 for(var i = 0; i < len; i++){
7680 r[a[i]] = this.getStyle(a[i]);
7686 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7687 * @param {String} property The style property whose value is returned.
7688 * @return {String} The current value of the style property for this element.
7690 getStyle : function(){
7691 return view && view.getComputedStyle ?
7693 var el = this.dom, v, cs, camel;
7694 if(prop == 'float'){
7697 if(el.style && (v = el.style[prop])){
7700 if(cs = view.getComputedStyle(el, "")){
7701 if(!(camel = propCache[prop])){
7702 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7709 var el = this.dom, v, cs, camel;
7710 if(prop == 'opacity'){
7711 if(typeof el.style.filter == 'string'){
7712 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7714 var fv = parseFloat(m[1]);
7716 return fv ? fv / 100 : 0;
7721 }else if(prop == 'float'){
7722 prop = "styleFloat";
7724 if(!(camel = propCache[prop])){
7725 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7727 if(v = el.style[camel]){
7730 if(cs = el.currentStyle){
7738 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7739 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7740 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7741 * @return {Roo.Element} this
7743 setStyle : function(prop, value){
7744 if(typeof prop == "string"){
7746 if (prop == 'float') {
7747 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7752 if(!(camel = propCache[prop])){
7753 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7756 if(camel == 'opacity') {
7757 this.setOpacity(value);
7759 this.dom.style[camel] = value;
7762 for(var style in prop){
7763 if(typeof prop[style] != "function"){
7764 this.setStyle(style, prop[style]);
7772 * More flexible version of {@link #setStyle} for setting style properties.
7773 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7774 * a function which returns such a specification.
7775 * @return {Roo.Element} this
7777 applyStyles : function(style){
7778 Roo.DomHelper.applyStyles(this.dom, style);
7783 * 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).
7784 * @return {Number} The X position of the element
7787 return D.getX(this.dom);
7791 * 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).
7792 * @return {Number} The Y position of the element
7795 return D.getY(this.dom);
7799 * 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).
7800 * @return {Array} The XY position of the element
7803 return D.getXY(this.dom);
7807 * 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).
7808 * @param {Number} The X position of the element
7809 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7810 * @return {Roo.Element} this
7812 setX : function(x, animate){
7814 D.setX(this.dom, x);
7816 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7822 * 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).
7823 * @param {Number} The Y position of the element
7824 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7825 * @return {Roo.Element} this
7827 setY : function(y, animate){
7829 D.setY(this.dom, y);
7831 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7837 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7838 * @param {String} left The left CSS property value
7839 * @return {Roo.Element} this
7841 setLeft : function(left){
7842 this.setStyle("left", this.addUnits(left));
7847 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7848 * @param {String} top The top CSS property value
7849 * @return {Roo.Element} this
7851 setTop : function(top){
7852 this.setStyle("top", this.addUnits(top));
7857 * Sets the element's CSS right style.
7858 * @param {String} right The right CSS property value
7859 * @return {Roo.Element} this
7861 setRight : function(right){
7862 this.setStyle("right", this.addUnits(right));
7867 * Sets the element's CSS bottom style.
7868 * @param {String} bottom The bottom CSS property value
7869 * @return {Roo.Element} this
7871 setBottom : function(bottom){
7872 this.setStyle("bottom", this.addUnits(bottom));
7877 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7878 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7879 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7880 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7881 * @return {Roo.Element} this
7883 setXY : function(pos, animate){
7885 D.setXY(this.dom, pos);
7887 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7893 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7894 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7895 * @param {Number} x X value for new position (coordinates are page-based)
7896 * @param {Number} y Y value for new position (coordinates are page-based)
7897 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7898 * @return {Roo.Element} this
7900 setLocation : function(x, y, animate){
7901 this.setXY([x, y], this.preanim(arguments, 2));
7906 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7907 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7908 * @param {Number} x X value for new position (coordinates are page-based)
7909 * @param {Number} y Y value for new position (coordinates are page-based)
7910 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7911 * @return {Roo.Element} this
7913 moveTo : function(x, y, animate){
7914 this.setXY([x, y], this.preanim(arguments, 2));
7919 * Returns the region of the given element.
7920 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7921 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7923 getRegion : function(){
7924 return D.getRegion(this.dom);
7928 * Returns the offset height of the element
7929 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7930 * @return {Number} The element's height
7932 getHeight : function(contentHeight){
7933 var h = this.dom.offsetHeight || 0;
7934 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7938 * Returns the offset width of the element
7939 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7940 * @return {Number} The element's width
7942 getWidth : function(contentWidth){
7943 var w = this.dom.offsetWidth || 0;
7944 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7948 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7949 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7950 * if a height has not been set using CSS.
7953 getComputedHeight : function(){
7954 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7956 h = parseInt(this.getStyle('height'), 10) || 0;
7957 if(!this.isBorderBox()){
7958 h += this.getFrameWidth('tb');
7965 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7966 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7967 * if a width has not been set using CSS.
7970 getComputedWidth : function(){
7971 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7973 w = parseInt(this.getStyle('width'), 10) || 0;
7974 if(!this.isBorderBox()){
7975 w += this.getFrameWidth('lr');
7982 * Returns the size of the element.
7983 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7984 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7986 getSize : function(contentSize){
7987 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7991 * Returns the width and height of the viewport.
7992 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7994 getViewSize : function(){
7995 var d = this.dom, doc = document, aw = 0, ah = 0;
7996 if(d == doc || d == doc.body){
7997 return {width : D.getViewWidth(), height: D.getViewHeight()};
8000 width : d.clientWidth,
8001 height: d.clientHeight
8007 * Returns the value of the "value" attribute
8008 * @param {Boolean} asNumber true to parse the value as a number
8009 * @return {String/Number}
8011 getValue : function(asNumber){
8012 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8016 adjustWidth : function(width){
8017 if(typeof width == "number"){
8018 if(this.autoBoxAdjust && !this.isBorderBox()){
8019 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8029 adjustHeight : function(height){
8030 if(typeof height == "number"){
8031 if(this.autoBoxAdjust && !this.isBorderBox()){
8032 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8042 * Set the width of the element
8043 * @param {Number} width The new width
8044 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8045 * @return {Roo.Element} this
8047 setWidth : function(width, animate){
8048 width = this.adjustWidth(width);
8050 this.dom.style.width = this.addUnits(width);
8052 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8058 * Set the height of the element
8059 * @param {Number} height The new height
8060 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8061 * @return {Roo.Element} this
8063 setHeight : function(height, animate){
8064 height = this.adjustHeight(height);
8066 this.dom.style.height = this.addUnits(height);
8068 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8074 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8075 * @param {Number} width The new width
8076 * @param {Number} height The new height
8077 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8078 * @return {Roo.Element} this
8080 setSize : function(width, height, animate){
8081 if(typeof width == "object"){ // in case of object from getSize()
8082 height = width.height; width = width.width;
8084 width = this.adjustWidth(width); height = this.adjustHeight(height);
8086 this.dom.style.width = this.addUnits(width);
8087 this.dom.style.height = this.addUnits(height);
8089 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8095 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8096 * @param {Number} x X value for new position (coordinates are page-based)
8097 * @param {Number} y Y value for new position (coordinates are page-based)
8098 * @param {Number} width The new width
8099 * @param {Number} height The new height
8100 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8101 * @return {Roo.Element} this
8103 setBounds : function(x, y, width, height, animate){
8105 this.setSize(width, height);
8106 this.setLocation(x, y);
8108 width = this.adjustWidth(width); height = this.adjustHeight(height);
8109 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8110 this.preanim(arguments, 4), 'motion');
8116 * 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.
8117 * @param {Roo.lib.Region} region The region to fill
8118 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8119 * @return {Roo.Element} this
8121 setRegion : function(region, animate){
8122 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8127 * Appends an event handler
8129 * @param {String} eventName The type of event to append
8130 * @param {Function} fn The method the event invokes
8131 * @param {Object} scope (optional) The scope (this object) of the fn
8132 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8134 addListener : function(eventName, fn, scope, options){
8136 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8141 * Removes an event handler from this element
8142 * @param {String} eventName the type of event to remove
8143 * @param {Function} fn the method the event invokes
8144 * @return {Roo.Element} this
8146 removeListener : function(eventName, fn){
8147 Roo.EventManager.removeListener(this.dom, eventName, fn);
8152 * Removes all previous added listeners from this element
8153 * @return {Roo.Element} this
8155 removeAllListeners : function(){
8156 E.purgeElement(this.dom);
8160 relayEvent : function(eventName, observable){
8161 this.on(eventName, function(e){
8162 observable.fireEvent(eventName, e);
8167 * Set the opacity of the element
8168 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8169 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8170 * @return {Roo.Element} this
8172 setOpacity : function(opacity, animate){
8174 var s = this.dom.style;
8177 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8178 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8180 s.opacity = opacity;
8183 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8189 * Gets the left X coordinate
8190 * @param {Boolean} local True to get the local css position instead of page coordinate
8193 getLeft : function(local){
8197 return parseInt(this.getStyle("left"), 10) || 0;
8202 * Gets the right X coordinate of the element (element X position + element width)
8203 * @param {Boolean} local True to get the local css position instead of page coordinate
8206 getRight : function(local){
8208 return this.getX() + this.getWidth();
8210 return (this.getLeft(true) + this.getWidth()) || 0;
8215 * Gets the top Y coordinate
8216 * @param {Boolean} local True to get the local css position instead of page coordinate
8219 getTop : function(local) {
8223 return parseInt(this.getStyle("top"), 10) || 0;
8228 * Gets the bottom Y coordinate of the element (element Y position + element height)
8229 * @param {Boolean} local True to get the local css position instead of page coordinate
8232 getBottom : function(local){
8234 return this.getY() + this.getHeight();
8236 return (this.getTop(true) + this.getHeight()) || 0;
8241 * Initializes positioning on this element. If a desired position is not passed, it will make the
8242 * the element positioned relative IF it is not already positioned.
8243 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8244 * @param {Number} zIndex (optional) The zIndex to apply
8245 * @param {Number} x (optional) Set the page X position
8246 * @param {Number} y (optional) Set the page Y position
8248 position : function(pos, zIndex, x, y){
8250 if(this.getStyle('position') == 'static'){
8251 this.setStyle('position', 'relative');
8254 this.setStyle("position", pos);
8257 this.setStyle("z-index", zIndex);
8259 if(x !== undefined && y !== undefined){
8261 }else if(x !== undefined){
8263 }else if(y !== undefined){
8269 * Clear positioning back to the default when the document was loaded
8270 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8271 * @return {Roo.Element} this
8273 clearPositioning : function(value){
8281 "position" : "static"
8287 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8288 * snapshot before performing an update and then restoring the element.
8291 getPositioning : function(){
8292 var l = this.getStyle("left");
8293 var t = this.getStyle("top");
8295 "position" : this.getStyle("position"),
8297 "right" : l ? "" : this.getStyle("right"),
8299 "bottom" : t ? "" : this.getStyle("bottom"),
8300 "z-index" : this.getStyle("z-index")
8305 * Gets the width of the border(s) for the specified side(s)
8306 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8307 * passing lr would get the border (l)eft width + the border (r)ight width.
8308 * @return {Number} The width of the sides passed added together
8310 getBorderWidth : function(side){
8311 return this.addStyles(side, El.borders);
8315 * Gets the width of the padding(s) for the specified side(s)
8316 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8317 * passing lr would get the padding (l)eft + the padding (r)ight.
8318 * @return {Number} The padding of the sides passed added together
8320 getPadding : function(side){
8321 return this.addStyles(side, El.paddings);
8325 * Set positioning with an object returned by getPositioning().
8326 * @param {Object} posCfg
8327 * @return {Roo.Element} this
8329 setPositioning : function(pc){
8330 this.applyStyles(pc);
8331 if(pc.right == "auto"){
8332 this.dom.style.right = "";
8334 if(pc.bottom == "auto"){
8335 this.dom.style.bottom = "";
8341 fixDisplay : function(){
8342 if(this.getStyle("display") == "none"){
8343 this.setStyle("visibility", "hidden");
8344 this.setStyle("display", this.originalDisplay); // first try reverting to default
8345 if(this.getStyle("display") == "none"){ // if that fails, default to block
8346 this.setStyle("display", "block");
8352 * Quick set left and top adding default units
8353 * @param {String} left The left CSS property value
8354 * @param {String} top The top CSS property value
8355 * @return {Roo.Element} this
8357 setLeftTop : function(left, top){
8358 this.dom.style.left = this.addUnits(left);
8359 this.dom.style.top = this.addUnits(top);
8364 * Move this element relative to its current position.
8365 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8366 * @param {Number} distance How far to move the element in pixels
8367 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8368 * @return {Roo.Element} this
8370 move : function(direction, distance, animate){
8371 var xy = this.getXY();
8372 direction = direction.toLowerCase();
8376 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8380 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8385 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8390 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8397 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8398 * @return {Roo.Element} this
8401 if(!this.isClipped){
8402 this.isClipped = true;
8403 this.originalClip = {
8404 "o": this.getStyle("overflow"),
8405 "x": this.getStyle("overflow-x"),
8406 "y": this.getStyle("overflow-y")
8408 this.setStyle("overflow", "hidden");
8409 this.setStyle("overflow-x", "hidden");
8410 this.setStyle("overflow-y", "hidden");
8416 * Return clipping (overflow) to original clipping before clip() was called
8417 * @return {Roo.Element} this
8419 unclip : function(){
8421 this.isClipped = false;
8422 var o = this.originalClip;
8423 if(o.o){this.setStyle("overflow", o.o);}
8424 if(o.x){this.setStyle("overflow-x", o.x);}
8425 if(o.y){this.setStyle("overflow-y", o.y);}
8432 * Gets the x,y coordinates specified by the anchor position on the element.
8433 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8434 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8435 * {width: (target width), height: (target height)} (defaults to the element's current size)
8436 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8437 * @return {Array} [x, y] An array containing the element's x and y coordinates
8439 getAnchorXY : function(anchor, local, s){
8440 //Passing a different size is useful for pre-calculating anchors,
8441 //especially for anchored animations that change the el size.
8443 var w, h, vp = false;
8446 if(d == document.body || d == document){
8448 w = D.getViewWidth(); h = D.getViewHeight();
8450 w = this.getWidth(); h = this.getHeight();
8453 w = s.width; h = s.height;
8455 var x = 0, y = 0, r = Math.round;
8456 switch((anchor || "tl").toLowerCase()){
8498 var sc = this.getScroll();
8499 return [x + sc.left, y + sc.top];
8501 //Add the element's offset xy
8502 var o = this.getXY();
8503 return [x+o[0], y+o[1]];
8507 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8508 * supported position values.
8509 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8510 * @param {String} position The position to align to.
8511 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8512 * @return {Array} [x, y]
8514 getAlignToXY : function(el, p, o){
8518 throw "Element.alignTo with an element that doesn't exist";
8520 var c = false; //constrain to viewport
8521 var p1 = "", p2 = "";
8528 }else if(p.indexOf("-") == -1){
8531 p = p.toLowerCase();
8532 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8534 throw "Element.alignTo with an invalid alignment " + p;
8536 p1 = m[1]; p2 = m[2]; c = !!m[3];
8538 //Subtract the aligned el's internal xy from the target's offset xy
8539 //plus custom offset to get the aligned el's new offset xy
8540 var a1 = this.getAnchorXY(p1, true);
8541 var a2 = el.getAnchorXY(p2, false);
8542 var x = a2[0] - a1[0] + o[0];
8543 var y = a2[1] - a1[1] + o[1];
8545 //constrain the aligned el to viewport if necessary
8546 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8547 // 5px of margin for ie
8548 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8550 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8551 //perpendicular to the vp border, allow the aligned el to slide on that border,
8552 //otherwise swap the aligned el to the opposite border of the target.
8553 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8554 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8555 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8556 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8559 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8560 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8562 if((x+w) > dw + scrollX){
8563 x = swapX ? r.left-w : dw+scrollX-w;
8566 x = swapX ? r.right : scrollX;
8568 if((y+h) > dh + scrollY){
8569 y = swapY ? r.top-h : dh+scrollY-h;
8572 y = swapY ? r.bottom : scrollY;
8579 getConstrainToXY : function(){
8580 var os = {top:0, left:0, bottom:0, right: 0};
8582 return function(el, local, offsets, proposedXY){
8584 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8586 var vw, vh, vx = 0, vy = 0;
8587 if(el.dom == document.body || el.dom == document){
8588 vw = Roo.lib.Dom.getViewWidth();
8589 vh = Roo.lib.Dom.getViewHeight();
8591 vw = el.dom.clientWidth;
8592 vh = el.dom.clientHeight;
8594 var vxy = el.getXY();
8600 var s = el.getScroll();
8602 vx += offsets.left + s.left;
8603 vy += offsets.top + s.top;
8605 vw -= offsets.right;
8606 vh -= offsets.bottom;
8611 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8612 var x = xy[0], y = xy[1];
8613 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8615 // only move it if it needs it
8618 // first validate right/bottom
8627 // then make sure top/left isn't negative
8636 return moved ? [x, y] : false;
8641 adjustForConstraints : function(xy, parent, offsets){
8642 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8646 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8647 * document it aligns it to the viewport.
8648 * The position parameter is optional, and can be specified in any one of the following formats:
8650 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8651 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8652 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8653 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8654 * <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
8655 * element's anchor point, and the second value is used as the target's anchor point.</li>
8657 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8658 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8659 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8660 * that specified in order to enforce the viewport constraints.
8661 * Following are all of the supported anchor positions:
8664 ----- -----------------------------
8665 tl The top left corner (default)
8666 t The center of the top edge
8667 tr The top right corner
8668 l The center of the left edge
8669 c In the center of the element
8670 r The center of the right edge
8671 bl The bottom left corner
8672 b The center of the bottom edge
8673 br The bottom right corner
8677 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8678 el.alignTo("other-el");
8680 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8681 el.alignTo("other-el", "tr?");
8683 // align the bottom right corner of el with the center left edge of other-el
8684 el.alignTo("other-el", "br-l?");
8686 // align the center of el with the bottom left corner of other-el and
8687 // adjust the x position by -6 pixels (and the y position by 0)
8688 el.alignTo("other-el", "c-bl", [-6, 0]);
8690 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8691 * @param {String} position The position to align to.
8692 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8693 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8694 * @return {Roo.Element} this
8696 alignTo : function(element, position, offsets, animate){
8697 var xy = this.getAlignToXY(element, position, offsets);
8698 this.setXY(xy, this.preanim(arguments, 3));
8703 * Anchors an element to another element and realigns it when the window is resized.
8704 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8705 * @param {String} position The position to align to.
8706 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8707 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8708 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8709 * is a number, it is used as the buffer delay (defaults to 50ms).
8710 * @param {Function} callback The function to call after the animation finishes
8711 * @return {Roo.Element} this
8713 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8714 var action = function(){
8715 this.alignTo(el, alignment, offsets, animate);
8716 Roo.callback(callback, this);
8718 Roo.EventManager.onWindowResize(action, this);
8719 var tm = typeof monitorScroll;
8720 if(tm != 'undefined'){
8721 Roo.EventManager.on(window, 'scroll', action, this,
8722 {buffer: tm == 'number' ? monitorScroll : 50});
8724 action.call(this); // align immediately
8728 * Clears any opacity settings from this element. Required in some cases for IE.
8729 * @return {Roo.Element} this
8731 clearOpacity : function(){
8732 if (window.ActiveXObject) {
8733 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8734 this.dom.style.filter = "";
8737 this.dom.style.opacity = "";
8738 this.dom.style["-moz-opacity"] = "";
8739 this.dom.style["-khtml-opacity"] = "";
8745 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8746 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8747 * @return {Roo.Element} this
8749 hide : function(animate){
8750 this.setVisible(false, this.preanim(arguments, 0));
8755 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8756 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8757 * @return {Roo.Element} this
8759 show : function(animate){
8760 this.setVisible(true, this.preanim(arguments, 0));
8765 * @private Test if size has a unit, otherwise appends the default
8767 addUnits : function(size){
8768 return Roo.Element.addUnits(size, this.defaultUnit);
8772 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8773 * @return {Roo.Element} this
8775 beginMeasure : function(){
8777 if(el.offsetWidth || el.offsetHeight){
8778 return this; // offsets work already
8781 var p = this.dom, b = document.body; // start with this element
8782 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8783 var pe = Roo.get(p);
8784 if(pe.getStyle('display') == 'none'){
8785 changed.push({el: p, visibility: pe.getStyle("visibility")});
8786 p.style.visibility = "hidden";
8787 p.style.display = "block";
8791 this._measureChanged = changed;
8797 * Restores displays to before beginMeasure was called
8798 * @return {Roo.Element} this
8800 endMeasure : function(){
8801 var changed = this._measureChanged;
8803 for(var i = 0, len = changed.length; i < len; i++) {
8805 r.el.style.visibility = r.visibility;
8806 r.el.style.display = "none";
8808 this._measureChanged = null;
8814 * Update the innerHTML of this element, optionally searching for and processing scripts
8815 * @param {String} html The new HTML
8816 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8817 * @param {Function} callback For async script loading you can be noticed when the update completes
8818 * @return {Roo.Element} this
8820 update : function(html, loadScripts, callback){
8821 if(typeof html == "undefined"){
8824 if(loadScripts !== true){
8825 this.dom.innerHTML = html;
8826 if(typeof callback == "function"){
8834 html += '<span id="' + id + '"></span>';
8836 E.onAvailable(id, function(){
8837 var hd = document.getElementsByTagName("head")[0];
8838 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8839 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8840 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8843 while(match = re.exec(html)){
8844 var attrs = match[1];
8845 var srcMatch = attrs ? attrs.match(srcRe) : false;
8846 if(srcMatch && srcMatch[2]){
8847 var s = document.createElement("script");
8848 s.src = srcMatch[2];
8849 var typeMatch = attrs.match(typeRe);
8850 if(typeMatch && typeMatch[2]){
8851 s.type = typeMatch[2];
8854 }else if(match[2] && match[2].length > 0){
8855 if(window.execScript) {
8856 window.execScript(match[2]);
8864 window.eval(match[2]);
8868 var el = document.getElementById(id);
8869 if(el){el.parentNode.removeChild(el);}
8870 if(typeof callback == "function"){
8874 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8879 * Direct access to the UpdateManager update() method (takes the same parameters).
8880 * @param {String/Function} url The url for this request or a function to call to get the url
8881 * @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}
8882 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8883 * @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.
8884 * @return {Roo.Element} this
8887 var um = this.getUpdateManager();
8888 um.update.apply(um, arguments);
8893 * Gets this element's UpdateManager
8894 * @return {Roo.UpdateManager} The UpdateManager
8896 getUpdateManager : function(){
8897 if(!this.updateManager){
8898 this.updateManager = new Roo.UpdateManager(this);
8900 return this.updateManager;
8904 * Disables text selection for this element (normalized across browsers)
8905 * @return {Roo.Element} this
8907 unselectable : function(){
8908 this.dom.unselectable = "on";
8909 this.swallowEvent("selectstart", true);
8910 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8911 this.addClass("x-unselectable");
8916 * Calculates the x, y to center this element on the screen
8917 * @return {Array} The x, y values [x, y]
8919 getCenterXY : function(){
8920 return this.getAlignToXY(document, 'c-c');
8924 * Centers the Element in either the viewport, or another Element.
8925 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8927 center : function(centerIn){
8928 this.alignTo(centerIn || document, 'c-c');
8933 * Tests various css rules/browsers to determine if this element uses a border box
8936 isBorderBox : function(){
8937 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8941 * Return a box {x, y, width, height} that can be used to set another elements
8942 * size/location to match this element.
8943 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8944 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8945 * @return {Object} box An object in the format {x, y, width, height}
8947 getBox : function(contentBox, local){
8952 var left = parseInt(this.getStyle("left"), 10) || 0;
8953 var top = parseInt(this.getStyle("top"), 10) || 0;
8956 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8958 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8960 var l = this.getBorderWidth("l")+this.getPadding("l");
8961 var r = this.getBorderWidth("r")+this.getPadding("r");
8962 var t = this.getBorderWidth("t")+this.getPadding("t");
8963 var b = this.getBorderWidth("b")+this.getPadding("b");
8964 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)};
8966 bx.right = bx.x + bx.width;
8967 bx.bottom = bx.y + bx.height;
8972 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8973 for more information about the sides.
8974 * @param {String} sides
8977 getFrameWidth : function(sides, onlyContentBox){
8978 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8982 * 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.
8983 * @param {Object} box The box to fill {x, y, width, height}
8984 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8985 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8986 * @return {Roo.Element} this
8988 setBox : function(box, adjust, animate){
8989 var w = box.width, h = box.height;
8990 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8991 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8992 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8994 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8999 * Forces the browser to repaint this element
9000 * @return {Roo.Element} this
9002 repaint : function(){
9004 this.addClass("x-repaint");
9005 setTimeout(function(){
9006 Roo.get(dom).removeClass("x-repaint");
9012 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9013 * then it returns the calculated width of the sides (see getPadding)
9014 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9015 * @return {Object/Number}
9017 getMargins : function(side){
9020 top: parseInt(this.getStyle("margin-top"), 10) || 0,
9021 left: parseInt(this.getStyle("margin-left"), 10) || 0,
9022 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9023 right: parseInt(this.getStyle("margin-right"), 10) || 0
9026 return this.addStyles(side, El.margins);
9031 addStyles : function(sides, styles){
9033 for(var i = 0, len = sides.length; i < len; i++){
9034 v = this.getStyle(styles[sides.charAt(i)]);
9036 w = parseInt(v, 10);
9044 * Creates a proxy element of this element
9045 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9046 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9047 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9048 * @return {Roo.Element} The new proxy element
9050 createProxy : function(config, renderTo, matchBox){
9052 renderTo = Roo.getDom(renderTo);
9054 renderTo = document.body;
9056 config = typeof config == "object" ?
9057 config : {tag : "div", cls: config};
9058 var proxy = Roo.DomHelper.append(renderTo, config, true);
9060 proxy.setBox(this.getBox());
9066 * Puts a mask over this element to disable user interaction. Requires core.css.
9067 * This method can only be applied to elements which accept child nodes.
9068 * @param {String} msg (optional) A message to display in the mask
9069 * @param {String} msgCls (optional) A css class to apply to the msg element
9070 * @return {Element} The mask element
9072 mask : function(msg, msgCls)
9074 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9075 this.setStyle("position", "relative");
9078 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9080 this.addClass("x-masked");
9081 this._mask.setDisplayed(true);
9086 while (dom && dom.style) {
9087 if (!isNaN(parseInt(dom.style.zIndex))) {
9088 z = Math.max(z, parseInt(dom.style.zIndex));
9090 dom = dom.parentNode;
9092 // if we are masking the body - then it hides everything..
9093 if (this.dom == document.body) {
9095 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9096 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9099 if(typeof msg == 'string'){
9101 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9103 var mm = this._maskMsg;
9104 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9105 if (mm.dom.firstChild) { // weird IE issue?
9106 mm.dom.firstChild.innerHTML = msg;
9108 mm.setDisplayed(true);
9110 mm.setStyle('z-index', z + 102);
9112 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9113 this._mask.setHeight(this.getHeight());
9115 this._mask.setStyle('z-index', z + 100);
9121 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9122 * it is cached for reuse.
9124 unmask : function(removeEl){
9126 if(removeEl === true){
9127 this._mask.remove();
9130 this._maskMsg.remove();
9131 delete this._maskMsg;
9134 this._mask.setDisplayed(false);
9136 this._maskMsg.setDisplayed(false);
9140 this.removeClass("x-masked");
9144 * Returns true if this element is masked
9147 isMasked : function(){
9148 return this._mask && this._mask.isVisible();
9152 * Creates an iframe shim for this element to keep selects and other windowed objects from
9154 * @return {Roo.Element} The new shim element
9156 createShim : function(){
9157 var el = document.createElement('iframe');
9158 el.frameBorder = 'no';
9159 el.className = 'roo-shim';
9160 if(Roo.isIE && Roo.isSecure){
9161 el.src = Roo.SSL_SECURE_URL;
9163 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9164 shim.autoBoxAdjust = false;
9169 * Removes this element from the DOM and deletes it from the cache
9171 remove : function(){
9172 if(this.dom.parentNode){
9173 this.dom.parentNode.removeChild(this.dom);
9175 delete El.cache[this.dom.id];
9179 * Sets up event handlers to add and remove a css class when the mouse is over this element
9180 * @param {String} className
9181 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9182 * mouseout events for children elements
9183 * @return {Roo.Element} this
9185 addClassOnOver : function(className, preventFlicker){
9186 this.on("mouseover", function(){
9187 Roo.fly(this, '_internal').addClass(className);
9189 var removeFn = function(e){
9190 if(preventFlicker !== true || !e.within(this, true)){
9191 Roo.fly(this, '_internal').removeClass(className);
9194 this.on("mouseout", removeFn, this.dom);
9199 * Sets up event handlers to add and remove a css class when this element has the focus
9200 * @param {String} className
9201 * @return {Roo.Element} this
9203 addClassOnFocus : function(className){
9204 this.on("focus", function(){
9205 Roo.fly(this, '_internal').addClass(className);
9207 this.on("blur", function(){
9208 Roo.fly(this, '_internal').removeClass(className);
9213 * 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)
9214 * @param {String} className
9215 * @return {Roo.Element} this
9217 addClassOnClick : function(className){
9219 this.on("mousedown", function(){
9220 Roo.fly(dom, '_internal').addClass(className);
9221 var d = Roo.get(document);
9222 var fn = function(){
9223 Roo.fly(dom, '_internal').removeClass(className);
9224 d.removeListener("mouseup", fn);
9226 d.on("mouseup", fn);
9232 * Stops the specified event from bubbling and optionally prevents the default action
9233 * @param {String} eventName
9234 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9235 * @return {Roo.Element} this
9237 swallowEvent : function(eventName, preventDefault){
9238 var fn = function(e){
9239 e.stopPropagation();
9244 if(eventName instanceof Array){
9245 for(var i = 0, len = eventName.length; i < len; i++){
9246 this.on(eventName[i], fn);
9250 this.on(eventName, fn);
9257 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9260 * Sizes this element to its parent element's dimensions performing
9261 * neccessary box adjustments.
9262 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9263 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9264 * @return {Roo.Element} this
9266 fitToParent : function(monitorResize, targetParent) {
9267 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9268 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9269 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9272 var p = Roo.get(targetParent || this.dom.parentNode);
9273 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9274 if (monitorResize === true) {
9275 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9276 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9282 * Gets the next sibling, skipping text nodes
9283 * @return {HTMLElement} The next sibling or null
9285 getNextSibling : function(){
9286 var n = this.dom.nextSibling;
9287 while(n && n.nodeType != 1){
9294 * Gets the previous sibling, skipping text nodes
9295 * @return {HTMLElement} The previous sibling or null
9297 getPrevSibling : function(){
9298 var n = this.dom.previousSibling;
9299 while(n && n.nodeType != 1){
9300 n = n.previousSibling;
9307 * Appends the passed element(s) to this element
9308 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9309 * @return {Roo.Element} this
9311 appendChild: function(el){
9318 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9319 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9320 * automatically generated with the specified attributes.
9321 * @param {HTMLElement} insertBefore (optional) a child element of this element
9322 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9323 * @return {Roo.Element} The new child element
9325 createChild: function(config, insertBefore, returnDom){
9326 config = config || {tag:'div'};
9328 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9330 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9334 * Appends this element to the passed element
9335 * @param {String/HTMLElement/Element} el The new parent element
9336 * @return {Roo.Element} this
9338 appendTo: function(el){
9339 el = Roo.getDom(el);
9340 el.appendChild(this.dom);
9345 * Inserts this element before the passed element in the DOM
9346 * @param {String/HTMLElement/Element} el The element to insert before
9347 * @return {Roo.Element} this
9349 insertBefore: function(el){
9350 el = Roo.getDom(el);
9351 el.parentNode.insertBefore(this.dom, el);
9356 * Inserts this element after the passed element in the DOM
9357 * @param {String/HTMLElement/Element} el The element to insert after
9358 * @return {Roo.Element} this
9360 insertAfter: function(el){
9361 el = Roo.getDom(el);
9362 el.parentNode.insertBefore(this.dom, el.nextSibling);
9367 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9368 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9369 * @return {Roo.Element} The new child
9371 insertFirst: function(el, returnDom){
9373 if(typeof el == 'object' && !el.nodeType){ // dh config
9374 return this.createChild(el, this.dom.firstChild, returnDom);
9376 el = Roo.getDom(el);
9377 this.dom.insertBefore(el, this.dom.firstChild);
9378 return !returnDom ? Roo.get(el) : el;
9383 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9384 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9385 * @param {String} where (optional) 'before' or 'after' defaults to before
9386 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9387 * @return {Roo.Element} the inserted Element
9389 insertSibling: function(el, where, returnDom){
9390 where = where ? where.toLowerCase() : 'before';
9392 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9394 if(typeof el == 'object' && !el.nodeType){ // dh config
9395 if(where == 'after' && !this.dom.nextSibling){
9396 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9398 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9402 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9403 where == 'before' ? this.dom : this.dom.nextSibling);
9412 * Creates and wraps this element with another element
9413 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9414 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9415 * @return {HTMLElement/Element} The newly created wrapper element
9417 wrap: function(config, returnDom){
9419 config = {tag: "div"};
9421 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9422 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9427 * Replaces the passed element with this element
9428 * @param {String/HTMLElement/Element} el The element to replace
9429 * @return {Roo.Element} this
9431 replace: function(el){
9433 this.insertBefore(el);
9439 * Inserts an html fragment into this element
9440 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9441 * @param {String} html The HTML fragment
9442 * @param {Boolean} returnEl True to return an Roo.Element
9443 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9445 insertHtml : function(where, html, returnEl){
9446 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9447 return returnEl ? Roo.get(el) : el;
9451 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9452 * @param {Object} o The object with the attributes
9453 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9454 * @return {Roo.Element} this
9456 set : function(o, useSet){
9458 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9460 if(attr == "style" || typeof o[attr] == "function") { continue; }
9462 el.className = o["cls"];
9465 el.setAttribute(attr, o[attr]);
9472 Roo.DomHelper.applyStyles(el, o.style);
9478 * Convenience method for constructing a KeyMap
9479 * @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:
9480 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9481 * @param {Function} fn The function to call
9482 * @param {Object} scope (optional) The scope of the function
9483 * @return {Roo.KeyMap} The KeyMap created
9485 addKeyListener : function(key, fn, scope){
9487 if(typeof key != "object" || key instanceof Array){
9503 return new Roo.KeyMap(this, config);
9507 * Creates a KeyMap for this element
9508 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9509 * @return {Roo.KeyMap} The KeyMap created
9511 addKeyMap : function(config){
9512 return new Roo.KeyMap(this, config);
9516 * Returns true if this element is scrollable.
9519 isScrollable : function(){
9521 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9525 * 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().
9526 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9527 * @param {Number} value The new scroll value
9528 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9529 * @return {Element} this
9532 scrollTo : function(side, value, animate){
9533 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9535 this.dom[prop] = value;
9537 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9538 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9544 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9545 * within this element's scrollable range.
9546 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9547 * @param {Number} distance How far to scroll the element in pixels
9548 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9549 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9550 * was scrolled as far as it could go.
9552 scroll : function(direction, distance, animate){
9553 if(!this.isScrollable()){
9557 var l = el.scrollLeft, t = el.scrollTop;
9558 var w = el.scrollWidth, h = el.scrollHeight;
9559 var cw = el.clientWidth, ch = el.clientHeight;
9560 direction = direction.toLowerCase();
9561 var scrolled = false;
9562 var a = this.preanim(arguments, 2);
9567 var v = Math.min(l + distance, w-cw);
9568 this.scrollTo("left", v, a);
9575 var v = Math.max(l - distance, 0);
9576 this.scrollTo("left", v, a);
9584 var v = Math.max(t - distance, 0);
9585 this.scrollTo("top", v, a);
9593 var v = Math.min(t + distance, h-ch);
9594 this.scrollTo("top", v, a);
9603 * Translates the passed page coordinates into left/top css values for this element
9604 * @param {Number/Array} x The page x or an array containing [x, y]
9605 * @param {Number} y The page y
9606 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9608 translatePoints : function(x, y){
9609 if(typeof x == 'object' || x instanceof Array){
9612 var p = this.getStyle('position');
9613 var o = this.getXY();
9615 var l = parseInt(this.getStyle('left'), 10);
9616 var t = parseInt(this.getStyle('top'), 10);
9619 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9622 t = (p == "relative") ? 0 : this.dom.offsetTop;
9625 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9629 * Returns the current scroll position of the element.
9630 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9632 getScroll : function(){
9633 var d = this.dom, doc = document;
9634 if(d == doc || d == doc.body){
9635 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9636 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9637 return {left: l, top: t};
9639 return {left: d.scrollLeft, top: d.scrollTop};
9644 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9645 * are convert to standard 6 digit hex color.
9646 * @param {String} attr The css attribute
9647 * @param {String} defaultValue The default value to use when a valid color isn't found
9648 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9651 getColor : function(attr, defaultValue, prefix){
9652 var v = this.getStyle(attr);
9653 if(!v || v == "transparent" || v == "inherit") {
9654 return defaultValue;
9656 var color = typeof prefix == "undefined" ? "#" : prefix;
9657 if(v.substr(0, 4) == "rgb("){
9658 var rvs = v.slice(4, v.length -1).split(",");
9659 for(var i = 0; i < 3; i++){
9660 var h = parseInt(rvs[i]).toString(16);
9667 if(v.substr(0, 1) == "#"){
9669 for(var i = 1; i < 4; i++){
9670 var c = v.charAt(i);
9673 }else if(v.length == 7){
9674 color += v.substr(1);
9678 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9682 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9683 * gradient background, rounded corners and a 4-way shadow.
9684 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9685 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9686 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9687 * @return {Roo.Element} this
9689 boxWrap : function(cls){
9690 cls = cls || 'x-box';
9691 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9692 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9697 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9698 * @param {String} namespace The namespace in which to look for the attribute
9699 * @param {String} name The attribute name
9700 * @return {String} The attribute value
9702 getAttributeNS : Roo.isIE ? function(ns, name){
9704 var type = typeof d[ns+":"+name];
9705 if(type != 'undefined' && type != 'unknown'){
9706 return d[ns+":"+name];
9709 } : function(ns, name){
9711 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9716 * Sets or Returns the value the dom attribute value
9717 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9718 * @param {String} value (optional) The value to set the attribute to
9719 * @return {String} The attribute value
9721 attr : function(name){
9722 if (arguments.length > 1) {
9723 this.dom.setAttribute(name, arguments[1]);
9724 return arguments[1];
9726 if (typeof(name) == 'object') {
9727 for(var i in name) {
9728 this.attr(i, name[i]);
9734 if (!this.dom.hasAttribute(name)) {
9737 return this.dom.getAttribute(name);
9744 var ep = El.prototype;
9747 * Appends an event handler (Shorthand for addListener)
9748 * @param {String} eventName The type of event to append
9749 * @param {Function} fn The method the event invokes
9750 * @param {Object} scope (optional) The scope (this object) of the fn
9751 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9754 ep.on = ep.addListener;
9756 ep.mon = ep.addListener;
9759 * Removes an event handler from this element (shorthand for removeListener)
9760 * @param {String} eventName the type of event to remove
9761 * @param {Function} fn the method the event invokes
9762 * @return {Roo.Element} this
9765 ep.un = ep.removeListener;
9768 * true to automatically adjust width and height settings for box-model issues (default to true)
9770 ep.autoBoxAdjust = true;
9773 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9776 El.addUnits = function(v, defaultUnit){
9777 if(v === "" || v == "auto"){
9780 if(v === undefined){
9783 if(typeof v == "number" || !El.unitPattern.test(v)){
9784 return v + (defaultUnit || 'px');
9789 // special markup used throughout Roo when box wrapping elements
9790 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>';
9792 * Visibility mode constant - Use visibility to hide element
9798 * Visibility mode constant - Use display to hide element
9804 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9805 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9806 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9818 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9819 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9820 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9821 * @return {Element} The Element object
9824 El.get = function(el){
9826 if(!el){ return null; }
9827 if(typeof el == "string"){ // element id
9828 if(!(elm = document.getElementById(el))){
9831 if(ex = El.cache[el]){
9834 ex = El.cache[el] = new El(elm);
9837 }else if(el.tagName){ // dom element
9841 if(ex = El.cache[id]){
9844 ex = El.cache[id] = new El(el);
9847 }else if(el instanceof El){
9849 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9850 // catch case where it hasn't been appended
9851 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9854 }else if(el.isComposite){
9856 }else if(el instanceof Array){
9857 return El.select(el);
9858 }else if(el == document){
9859 // create a bogus element object representing the document object
9861 var f = function(){};
9862 f.prototype = El.prototype;
9864 docEl.dom = document;
9872 El.uncache = function(el){
9873 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9875 delete El.cache[a[i].id || a[i]];
9881 // Garbage collection - uncache elements/purge listeners on orphaned elements
9882 // so we don't hold a reference and cause the browser to retain them
9883 El.garbageCollect = function(){
9884 if(!Roo.enableGarbageCollector){
9885 clearInterval(El.collectorThread);
9888 for(var eid in El.cache){
9889 var el = El.cache[eid], d = el.dom;
9890 // -------------------------------------------------------
9891 // Determining what is garbage:
9892 // -------------------------------------------------------
9894 // dom node is null, definitely garbage
9895 // -------------------------------------------------------
9897 // no parentNode == direct orphan, definitely garbage
9898 // -------------------------------------------------------
9899 // !d.offsetParent && !document.getElementById(eid)
9900 // display none elements have no offsetParent so we will
9901 // also try to look it up by it's id. However, check
9902 // offsetParent first so we don't do unneeded lookups.
9903 // This enables collection of elements that are not orphans
9904 // directly, but somewhere up the line they have an orphan
9906 // -------------------------------------------------------
9907 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9908 delete El.cache[eid];
9909 if(d && Roo.enableListenerCollection){
9915 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9919 El.Flyweight = function(dom){
9922 El.Flyweight.prototype = El.prototype;
9924 El._flyweights = {};
9926 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9927 * the dom node can be overwritten by other code.
9928 * @param {String/HTMLElement} el The dom node or id
9929 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9930 * prevent conflicts (e.g. internally Roo uses "_internal")
9932 * @return {Element} The shared Element object
9934 El.fly = function(el, named){
9935 named = named || '_global';
9936 el = Roo.getDom(el);
9940 if(!El._flyweights[named]){
9941 El._flyweights[named] = new El.Flyweight();
9943 El._flyweights[named].dom = el;
9944 return El._flyweights[named];
9948 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9949 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9950 * Shorthand of {@link Roo.Element#get}
9951 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9952 * @return {Element} The Element object
9958 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9959 * the dom node can be overwritten by other code.
9960 * Shorthand of {@link Roo.Element#fly}
9961 * @param {String/HTMLElement} el The dom node or id
9962 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9963 * prevent conflicts (e.g. internally Roo uses "_internal")
9965 * @return {Element} The shared Element object
9971 // speedy lookup for elements never to box adjust
9972 var noBoxAdjust = Roo.isStrict ? {
9975 input:1, select:1, textarea:1
9977 if(Roo.isIE || Roo.isGecko){
9978 noBoxAdjust['button'] = 1;
9982 Roo.EventManager.on(window, 'unload', function(){
9984 delete El._flyweights;
9992 Roo.Element.selectorFunction = Roo.DomQuery.select;
9995 Roo.Element.select = function(selector, unique, root){
9997 if(typeof selector == "string"){
9998 els = Roo.Element.selectorFunction(selector, root);
9999 }else if(selector.length !== undefined){
10002 throw "Invalid selector";
10004 if(unique === true){
10005 return new Roo.CompositeElement(els);
10007 return new Roo.CompositeElementLite(els);
10011 * Selects elements based on the passed CSS selector to enable working on them as 1.
10012 * @param {String/Array} selector The CSS selector or an array of elements
10013 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10014 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10015 * @return {CompositeElementLite/CompositeElement}
10019 Roo.select = Roo.Element.select;
10036 * Ext JS Library 1.1.1
10037 * Copyright(c) 2006-2007, Ext JS, LLC.
10039 * Originally Released Under LGPL - original licence link has changed is not relivant.
10042 * <script type="text/javascript">
10047 //Notifies Element that fx methods are available
10048 Roo.enableFx = true;
10052 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
10053 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10054 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
10055 * Element effects to work.</p><br/>
10057 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10058 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10059 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10060 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10061 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10062 * expected results and should be done with care.</p><br/>
10064 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10065 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10068 ----- -----------------------------
10069 tl The top left corner
10070 t The center of the top edge
10071 tr The top right corner
10072 l The center of the left edge
10073 r The center of the right edge
10074 bl The bottom left corner
10075 b The center of the bottom edge
10076 br The bottom right corner
10078 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10079 * below are common options that can be passed to any Fx method.</b>
10080 * @cfg {Function} callback A function called when the effect is finished
10081 * @cfg {Object} scope The scope of the effect function
10082 * @cfg {String} easing A valid Easing value for the effect
10083 * @cfg {String} afterCls A css class to apply after the effect
10084 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10085 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10086 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10087 * effects that end with the element being visually hidden, ignored otherwise)
10088 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10089 * a function which returns such a specification that will be applied to the Element after the effect finishes
10090 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10091 * @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
10092 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10096 * Slides the element into view. An anchor point can be optionally passed to set the point of
10097 * origin for the slide effect. This function automatically handles wrapping the element with
10098 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10101 // default: slide the element in from the top
10104 // custom: slide the element in from the right with a 2-second duration
10105 el.slideIn('r', { duration: 2 });
10107 // common config options shown with default values
10113 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10114 * @param {Object} options (optional) Object literal with any of the Fx config options
10115 * @return {Roo.Element} The Element
10117 slideIn : function(anchor, o){
10118 var el = this.getFxEl();
10121 el.queueFx(o, function(){
10123 anchor = anchor || "t";
10125 // fix display to visibility
10128 // restore values after effect
10129 var r = this.getFxRestore();
10130 var b = this.getBox();
10131 // fixed size for slide
10135 var wrap = this.fxWrap(r.pos, o, "hidden");
10137 var st = this.dom.style;
10138 st.visibility = "visible";
10139 st.position = "absolute";
10141 // clear out temp styles after slide and unwrap
10142 var after = function(){
10143 el.fxUnwrap(wrap, r.pos, o);
10144 st.width = r.width;
10145 st.height = r.height;
10148 // time to calc the positions
10149 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10151 switch(anchor.toLowerCase()){
10153 wrap.setSize(b.width, 0);
10154 st.left = st.bottom = "0";
10158 wrap.setSize(0, b.height);
10159 st.right = st.top = "0";
10163 wrap.setSize(0, b.height);
10164 wrap.setX(b.right);
10165 st.left = st.top = "0";
10166 a = {width: bw, points: pt};
10169 wrap.setSize(b.width, 0);
10170 wrap.setY(b.bottom);
10171 st.left = st.top = "0";
10172 a = {height: bh, points: pt};
10175 wrap.setSize(0, 0);
10176 st.right = st.bottom = "0";
10177 a = {width: bw, height: bh};
10180 wrap.setSize(0, 0);
10181 wrap.setY(b.y+b.height);
10182 st.right = st.top = "0";
10183 a = {width: bw, height: bh, points: pt};
10186 wrap.setSize(0, 0);
10187 wrap.setXY([b.right, b.bottom]);
10188 st.left = st.top = "0";
10189 a = {width: bw, height: bh, points: pt};
10192 wrap.setSize(0, 0);
10193 wrap.setX(b.x+b.width);
10194 st.left = st.bottom = "0";
10195 a = {width: bw, height: bh, points: pt};
10198 this.dom.style.visibility = "visible";
10201 arguments.callee.anim = wrap.fxanim(a,
10211 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10212 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10213 * 'hidden') but block elements will still take up space in the document. The element must be removed
10214 * from the DOM using the 'remove' config option if desired. This function automatically handles
10215 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10218 // default: slide the element out to the top
10221 // custom: slide the element out to the right with a 2-second duration
10222 el.slideOut('r', { duration: 2 });
10224 // common config options shown with default values
10232 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10233 * @param {Object} options (optional) Object literal with any of the Fx config options
10234 * @return {Roo.Element} The Element
10236 slideOut : function(anchor, o){
10237 var el = this.getFxEl();
10240 el.queueFx(o, function(){
10242 anchor = anchor || "t";
10244 // restore values after effect
10245 var r = this.getFxRestore();
10247 var b = this.getBox();
10248 // fixed size for slide
10252 var wrap = this.fxWrap(r.pos, o, "visible");
10254 var st = this.dom.style;
10255 st.visibility = "visible";
10256 st.position = "absolute";
10260 var after = function(){
10262 el.setDisplayed(false);
10267 el.fxUnwrap(wrap, r.pos, o);
10269 st.width = r.width;
10270 st.height = r.height;
10275 var a, zero = {to: 0};
10276 switch(anchor.toLowerCase()){
10278 st.left = st.bottom = "0";
10279 a = {height: zero};
10282 st.right = st.top = "0";
10286 st.left = st.top = "0";
10287 a = {width: zero, points: {to:[b.right, b.y]}};
10290 st.left = st.top = "0";
10291 a = {height: zero, points: {to:[b.x, b.bottom]}};
10294 st.right = st.bottom = "0";
10295 a = {width: zero, height: zero};
10298 st.right = st.top = "0";
10299 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10302 st.left = st.top = "0";
10303 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10306 st.left = st.bottom = "0";
10307 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10311 arguments.callee.anim = wrap.fxanim(a,
10321 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10322 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10323 * The element must be removed from the DOM using the 'remove' config option if desired.
10329 // common config options shown with default values
10337 * @param {Object} options (optional) Object literal with any of the Fx config options
10338 * @return {Roo.Element} The Element
10340 puff : function(o){
10341 var el = this.getFxEl();
10344 el.queueFx(o, function(){
10345 this.clearOpacity();
10348 // restore values after effect
10349 var r = this.getFxRestore();
10350 var st = this.dom.style;
10352 var after = function(){
10354 el.setDisplayed(false);
10361 el.setPositioning(r.pos);
10362 st.width = r.width;
10363 st.height = r.height;
10368 var width = this.getWidth();
10369 var height = this.getHeight();
10371 arguments.callee.anim = this.fxanim({
10372 width : {to: this.adjustWidth(width * 2)},
10373 height : {to: this.adjustHeight(height * 2)},
10374 points : {by: [-(width * .5), -(height * .5)]},
10376 fontSize: {to:200, unit: "%"}
10387 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10388 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10389 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10395 // all config options shown with default values
10403 * @param {Object} options (optional) Object literal with any of the Fx config options
10404 * @return {Roo.Element} The Element
10406 switchOff : function(o){
10407 var el = this.getFxEl();
10410 el.queueFx(o, function(){
10411 this.clearOpacity();
10414 // restore values after effect
10415 var r = this.getFxRestore();
10416 var st = this.dom.style;
10418 var after = function(){
10420 el.setDisplayed(false);
10426 el.setPositioning(r.pos);
10427 st.width = r.width;
10428 st.height = r.height;
10433 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10434 this.clearOpacity();
10438 points:{by:[0, this.getHeight() * .5]}
10439 }, o, 'motion', 0.3, 'easeIn', after);
10440 }).defer(100, this);
10447 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10448 * changed using the "attr" config option) and then fading back to the original color. If no original
10449 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10452 // default: highlight background to yellow
10455 // custom: highlight foreground text to blue for 2 seconds
10456 el.highlight("0000ff", { attr: 'color', duration: 2 });
10458 // common config options shown with default values
10459 el.highlight("ffff9c", {
10460 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10461 endColor: (current color) or "ffffff",
10466 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10467 * @param {Object} options (optional) Object literal with any of the Fx config options
10468 * @return {Roo.Element} The Element
10470 highlight : function(color, o){
10471 var el = this.getFxEl();
10474 el.queueFx(o, function(){
10475 color = color || "ffff9c";
10476 attr = o.attr || "backgroundColor";
10478 this.clearOpacity();
10481 var origColor = this.getColor(attr);
10482 var restoreColor = this.dom.style[attr];
10483 endColor = (o.endColor || origColor) || "ffffff";
10485 var after = function(){
10486 el.dom.style[attr] = restoreColor;
10491 a[attr] = {from: color, to: endColor};
10492 arguments.callee.anim = this.fxanim(a,
10502 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10505 // default: a single light blue ripple
10508 // custom: 3 red ripples lasting 3 seconds total
10509 el.frame("ff0000", 3, { duration: 3 });
10511 // common config options shown with default values
10512 el.frame("C3DAF9", 1, {
10513 duration: 1 //duration of entire animation (not each individual ripple)
10514 // Note: Easing is not configurable and will be ignored if included
10517 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10518 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10519 * @param {Object} options (optional) Object literal with any of the Fx config options
10520 * @return {Roo.Element} The Element
10522 frame : function(color, count, o){
10523 var el = this.getFxEl();
10526 el.queueFx(o, function(){
10527 color = color || "#C3DAF9";
10528 if(color.length == 6){
10529 color = "#" + color;
10531 count = count || 1;
10532 duration = o.duration || 1;
10535 var b = this.getBox();
10536 var animFn = function(){
10537 var proxy = this.createProxy({
10540 visbility:"hidden",
10541 position:"absolute",
10542 "z-index":"35000", // yee haw
10543 border:"0px solid " + color
10546 var scale = Roo.isBorderBox ? 2 : 1;
10548 top:{from:b.y, to:b.y - 20},
10549 left:{from:b.x, to:b.x - 20},
10550 borderWidth:{from:0, to:10},
10551 opacity:{from:1, to:0},
10552 height:{from:b.height, to:(b.height + (20*scale))},
10553 width:{from:b.width, to:(b.width + (20*scale))}
10554 }, duration, function(){
10558 animFn.defer((duration/2)*1000, this);
10569 * Creates a pause before any subsequent queued effects begin. If there are
10570 * no effects queued after the pause it will have no effect.
10575 * @param {Number} seconds The length of time to pause (in seconds)
10576 * @return {Roo.Element} The Element
10578 pause : function(seconds){
10579 var el = this.getFxEl();
10582 el.queueFx(o, function(){
10583 setTimeout(function(){
10585 }, seconds * 1000);
10591 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10592 * using the "endOpacity" config option.
10595 // default: fade in from opacity 0 to 100%
10598 // custom: fade in from opacity 0 to 75% over 2 seconds
10599 el.fadeIn({ endOpacity: .75, duration: 2});
10601 // common config options shown with default values
10603 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10608 * @param {Object} options (optional) Object literal with any of the Fx config options
10609 * @return {Roo.Element} The Element
10611 fadeIn : function(o){
10612 var el = this.getFxEl();
10614 el.queueFx(o, function(){
10615 this.setOpacity(0);
10617 this.dom.style.visibility = 'visible';
10618 var to = o.endOpacity || 1;
10619 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10620 o, null, .5, "easeOut", function(){
10622 this.clearOpacity();
10631 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10632 * using the "endOpacity" config option.
10635 // default: fade out from the element's current opacity to 0
10638 // custom: fade out from the element's current opacity to 25% over 2 seconds
10639 el.fadeOut({ endOpacity: .25, duration: 2});
10641 // common config options shown with default values
10643 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10650 * @param {Object} options (optional) Object literal with any of the Fx config options
10651 * @return {Roo.Element} The Element
10653 fadeOut : function(o){
10654 var el = this.getFxEl();
10656 el.queueFx(o, function(){
10657 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10658 o, null, .5, "easeOut", function(){
10659 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10660 this.dom.style.display = "none";
10662 this.dom.style.visibility = "hidden";
10664 this.clearOpacity();
10672 * Animates the transition of an element's dimensions from a starting height/width
10673 * to an ending height/width.
10676 // change height and width to 100x100 pixels
10677 el.scale(100, 100);
10679 // common config options shown with default values. The height and width will default to
10680 // the element's existing values if passed as null.
10683 [element's height], {
10688 * @param {Number} width The new width (pass undefined to keep the original width)
10689 * @param {Number} height The new height (pass undefined to keep the original height)
10690 * @param {Object} options (optional) Object literal with any of the Fx config options
10691 * @return {Roo.Element} The Element
10693 scale : function(w, h, o){
10694 this.shift(Roo.apply({}, o, {
10702 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10703 * Any of these properties not specified in the config object will not be changed. This effect
10704 * requires that at least one new dimension, position or opacity setting must be passed in on
10705 * the config object in order for the function to have any effect.
10708 // slide the element horizontally to x position 200 while changing the height and opacity
10709 el.shift({ x: 200, height: 50, opacity: .8 });
10711 // common config options shown with default values.
10713 width: [element's width],
10714 height: [element's height],
10715 x: [element's x position],
10716 y: [element's y position],
10717 opacity: [element's opacity],
10722 * @param {Object} options Object literal with any of the Fx config options
10723 * @return {Roo.Element} The Element
10725 shift : function(o){
10726 var el = this.getFxEl();
10728 el.queueFx(o, function(){
10729 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10730 if(w !== undefined){
10731 a.width = {to: this.adjustWidth(w)};
10733 if(h !== undefined){
10734 a.height = {to: this.adjustHeight(h)};
10736 if(x !== undefined || y !== undefined){
10738 x !== undefined ? x : this.getX(),
10739 y !== undefined ? y : this.getY()
10742 if(op !== undefined){
10743 a.opacity = {to: op};
10745 if(o.xy !== undefined){
10746 a.points = {to: o.xy};
10748 arguments.callee.anim = this.fxanim(a,
10749 o, 'motion', .35, "easeOut", function(){
10757 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10758 * ending point of the effect.
10761 // default: slide the element downward while fading out
10764 // custom: slide the element out to the right with a 2-second duration
10765 el.ghost('r', { duration: 2 });
10767 // common config options shown with default values
10775 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10776 * @param {Object} options (optional) Object literal with any of the Fx config options
10777 * @return {Roo.Element} The Element
10779 ghost : function(anchor, o){
10780 var el = this.getFxEl();
10783 el.queueFx(o, function(){
10784 anchor = anchor || "b";
10786 // restore values after effect
10787 var r = this.getFxRestore();
10788 var w = this.getWidth(),
10789 h = this.getHeight();
10791 var st = this.dom.style;
10793 var after = function(){
10795 el.setDisplayed(false);
10801 el.setPositioning(r.pos);
10802 st.width = r.width;
10803 st.height = r.height;
10808 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10809 switch(anchor.toLowerCase()){
10836 arguments.callee.anim = this.fxanim(a,
10846 * Ensures that all effects queued after syncFx is called on the element are
10847 * run concurrently. This is the opposite of {@link #sequenceFx}.
10848 * @return {Roo.Element} The Element
10850 syncFx : function(){
10851 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10860 * Ensures that all effects queued after sequenceFx is called on the element are
10861 * run in sequence. This is the opposite of {@link #syncFx}.
10862 * @return {Roo.Element} The Element
10864 sequenceFx : function(){
10865 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10867 concurrent : false,
10874 nextFx : function(){
10875 var ef = this.fxQueue[0];
10882 * Returns true if the element has any effects actively running or queued, else returns false.
10883 * @return {Boolean} True if element has active effects, else false
10885 hasActiveFx : function(){
10886 return this.fxQueue && this.fxQueue[0];
10890 * Stops any running effects and clears the element's internal effects queue if it contains
10891 * any additional effects that haven't started yet.
10892 * @return {Roo.Element} The Element
10894 stopFx : function(){
10895 if(this.hasActiveFx()){
10896 var cur = this.fxQueue[0];
10897 if(cur && cur.anim && cur.anim.isAnimated()){
10898 this.fxQueue = [cur]; // clear out others
10899 cur.anim.stop(true);
10906 beforeFx : function(o){
10907 if(this.hasActiveFx() && !o.concurrent){
10918 * Returns true if the element is currently blocking so that no other effect can be queued
10919 * until this effect is finished, else returns false if blocking is not set. This is commonly
10920 * used to ensure that an effect initiated by a user action runs to completion prior to the
10921 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10922 * @return {Boolean} True if blocking, else false
10924 hasFxBlock : function(){
10925 var q = this.fxQueue;
10926 return q && q[0] && q[0].block;
10930 queueFx : function(o, fn){
10934 if(!this.hasFxBlock()){
10935 Roo.applyIf(o, this.fxDefaults);
10937 var run = this.beforeFx(o);
10938 fn.block = o.block;
10939 this.fxQueue.push(fn);
10951 fxWrap : function(pos, o, vis){
10953 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10956 wrapXY = this.getXY();
10958 var div = document.createElement("div");
10959 div.style.visibility = vis;
10960 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10961 wrap.setPositioning(pos);
10962 if(wrap.getStyle("position") == "static"){
10963 wrap.position("relative");
10965 this.clearPositioning('auto');
10967 wrap.dom.appendChild(this.dom);
10969 wrap.setXY(wrapXY);
10976 fxUnwrap : function(wrap, pos, o){
10977 this.clearPositioning();
10978 this.setPositioning(pos);
10980 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10986 getFxRestore : function(){
10987 var st = this.dom.style;
10988 return {pos: this.getPositioning(), width: st.width, height : st.height};
10992 afterFx : function(o){
10994 this.applyStyles(o.afterStyle);
10997 this.addClass(o.afterCls);
10999 if(o.remove === true){
11002 Roo.callback(o.callback, o.scope, [this]);
11004 this.fxQueue.shift();
11010 getFxEl : function(){ // support for composite element fx
11011 return Roo.get(this.dom);
11015 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11016 animType = animType || 'run';
11018 var anim = Roo.lib.Anim[animType](
11020 (opt.duration || defaultDur) || .35,
11021 (opt.easing || defaultEase) || 'easeOut',
11023 Roo.callback(cb, this);
11032 // backwords compat
11033 Roo.Fx.resize = Roo.Fx.scale;
11035 //When included, Roo.Fx is automatically applied to Element so that all basic
11036 //effects are available directly via the Element API
11037 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11039 * Ext JS Library 1.1.1
11040 * Copyright(c) 2006-2007, Ext JS, LLC.
11042 * Originally Released Under LGPL - original licence link has changed is not relivant.
11045 * <script type="text/javascript">
11050 * @class Roo.CompositeElement
11051 * Standard composite class. Creates a Roo.Element for every element in the collection.
11053 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11054 * actions will be performed on all the elements in this collection.</b>
11056 * All methods return <i>this</i> and can be chained.
11058 var els = Roo.select("#some-el div.some-class", true);
11059 // or select directly from an existing element
11060 var el = Roo.get('some-el');
11061 el.select('div.some-class', true);
11063 els.setWidth(100); // all elements become 100 width
11064 els.hide(true); // all elements fade out and hide
11066 els.setWidth(100).hide(true);
11069 Roo.CompositeElement = function(els){
11070 this.elements = [];
11071 this.addElements(els);
11073 Roo.CompositeElement.prototype = {
11075 addElements : function(els){
11079 if(typeof els == "string"){
11080 els = Roo.Element.selectorFunction(els);
11082 var yels = this.elements;
11083 var index = yels.length-1;
11084 for(var i = 0, len = els.length; i < len; i++) {
11085 yels[++index] = Roo.get(els[i]);
11091 * Clears this composite and adds the elements returned by the passed selector.
11092 * @param {String/Array} els A string CSS selector, an array of elements or an element
11093 * @return {CompositeElement} this
11095 fill : function(els){
11096 this.elements = [];
11102 * Filters this composite to only elements that match the passed selector.
11103 * @param {String} selector A string CSS selector
11104 * @param {Boolean} inverse return inverse filter (not matches)
11105 * @return {CompositeElement} this
11107 filter : function(selector, inverse){
11109 inverse = inverse || false;
11110 this.each(function(el){
11111 var match = inverse ? !el.is(selector) : el.is(selector);
11113 els[els.length] = el.dom;
11120 invoke : function(fn, args){
11121 var els = this.elements;
11122 for(var i = 0, len = els.length; i < len; i++) {
11123 Roo.Element.prototype[fn].apply(els[i], args);
11128 * Adds elements to this composite.
11129 * @param {String/Array} els A string CSS selector, an array of elements or an element
11130 * @return {CompositeElement} this
11132 add : function(els){
11133 if(typeof els == "string"){
11134 this.addElements(Roo.Element.selectorFunction(els));
11135 }else if(els.length !== undefined){
11136 this.addElements(els);
11138 this.addElements([els]);
11143 * Calls the passed function passing (el, this, index) for each element in this composite.
11144 * @param {Function} fn The function to call
11145 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11146 * @return {CompositeElement} this
11148 each : function(fn, scope){
11149 var els = this.elements;
11150 for(var i = 0, len = els.length; i < len; i++){
11151 if(fn.call(scope || els[i], els[i], this, i) === false) {
11159 * Returns the Element object at the specified index
11160 * @param {Number} index
11161 * @return {Roo.Element}
11163 item : function(index){
11164 return this.elements[index] || null;
11168 * Returns the first Element
11169 * @return {Roo.Element}
11171 first : function(){
11172 return this.item(0);
11176 * Returns the last Element
11177 * @return {Roo.Element}
11180 return this.item(this.elements.length-1);
11184 * Returns the number of elements in this composite
11187 getCount : function(){
11188 return this.elements.length;
11192 * Returns true if this composite contains the passed element
11195 contains : function(el){
11196 return this.indexOf(el) !== -1;
11200 * Returns true if this composite contains the passed element
11203 indexOf : function(el){
11204 return this.elements.indexOf(Roo.get(el));
11209 * Removes the specified element(s).
11210 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11211 * or an array of any of those.
11212 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11213 * @return {CompositeElement} this
11215 removeElement : function(el, removeDom){
11216 if(el instanceof Array){
11217 for(var i = 0, len = el.length; i < len; i++){
11218 this.removeElement(el[i]);
11222 var index = typeof el == 'number' ? el : this.indexOf(el);
11225 var d = this.elements[index];
11229 d.parentNode.removeChild(d);
11232 this.elements.splice(index, 1);
11238 * Replaces the specified element with the passed element.
11239 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11241 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11242 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11243 * @return {CompositeElement} this
11245 replaceElement : function(el, replacement, domReplace){
11246 var index = typeof el == 'number' ? el : this.indexOf(el);
11249 this.elements[index].replaceWith(replacement);
11251 this.elements.splice(index, 1, Roo.get(replacement))
11258 * Removes all elements.
11260 clear : function(){
11261 this.elements = [];
11265 Roo.CompositeElement.createCall = function(proto, fnName){
11266 if(!proto[fnName]){
11267 proto[fnName] = function(){
11268 return this.invoke(fnName, arguments);
11272 for(var fnName in Roo.Element.prototype){
11273 if(typeof Roo.Element.prototype[fnName] == "function"){
11274 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11280 * Ext JS Library 1.1.1
11281 * Copyright(c) 2006-2007, Ext JS, LLC.
11283 * Originally Released Under LGPL - original licence link has changed is not relivant.
11286 * <script type="text/javascript">
11290 * @class Roo.CompositeElementLite
11291 * @extends Roo.CompositeElement
11292 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11294 var els = Roo.select("#some-el div.some-class");
11295 // or select directly from an existing element
11296 var el = Roo.get('some-el');
11297 el.select('div.some-class');
11299 els.setWidth(100); // all elements become 100 width
11300 els.hide(true); // all elements fade out and hide
11302 els.setWidth(100).hide(true);
11303 </code></pre><br><br>
11304 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11305 * actions will be performed on all the elements in this collection.</b>
11307 Roo.CompositeElementLite = function(els){
11308 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11309 this.el = new Roo.Element.Flyweight();
11311 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11312 addElements : function(els){
11314 if(els instanceof Array){
11315 this.elements = this.elements.concat(els);
11317 var yels = this.elements;
11318 var index = yels.length-1;
11319 for(var i = 0, len = els.length; i < len; i++) {
11320 yels[++index] = els[i];
11326 invoke : function(fn, args){
11327 var els = this.elements;
11329 for(var i = 0, len = els.length; i < len; i++) {
11331 Roo.Element.prototype[fn].apply(el, args);
11336 * Returns a flyweight Element of the dom element object at the specified index
11337 * @param {Number} index
11338 * @return {Roo.Element}
11340 item : function(index){
11341 if(!this.elements[index]){
11344 this.el.dom = this.elements[index];
11348 // fixes scope with flyweight
11349 addListener : function(eventName, handler, scope, opt){
11350 var els = this.elements;
11351 for(var i = 0, len = els.length; i < len; i++) {
11352 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11358 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11359 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11360 * a reference to the dom node, use el.dom.</b>
11361 * @param {Function} fn The function to call
11362 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11363 * @return {CompositeElement} this
11365 each : function(fn, scope){
11366 var els = this.elements;
11368 for(var i = 0, len = els.length; i < len; i++){
11370 if(fn.call(scope || el, el, this, i) === false){
11377 indexOf : function(el){
11378 return this.elements.indexOf(Roo.getDom(el));
11381 replaceElement : function(el, replacement, domReplace){
11382 var index = typeof el == 'number' ? el : this.indexOf(el);
11384 replacement = Roo.getDom(replacement);
11386 var d = this.elements[index];
11387 d.parentNode.insertBefore(replacement, d);
11388 d.parentNode.removeChild(d);
11390 this.elements.splice(index, 1, replacement);
11395 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11399 * Ext JS Library 1.1.1
11400 * Copyright(c) 2006-2007, Ext JS, LLC.
11402 * Originally Released Under LGPL - original licence link has changed is not relivant.
11405 * <script type="text/javascript">
11411 * @class Roo.data.Connection
11412 * @extends Roo.util.Observable
11413 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11414 * either to a configured URL, or to a URL specified at request time.<br><br>
11416 * Requests made by this class are asynchronous, and will return immediately. No data from
11417 * the server will be available to the statement immediately following the {@link #request} call.
11418 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11420 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11421 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11422 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11423 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11424 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11425 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11426 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11427 * standard DOM methods.
11429 * @param {Object} config a configuration object.
11431 Roo.data.Connection = function(config){
11432 Roo.apply(this, config);
11435 * @event beforerequest
11436 * Fires before a network request is made to retrieve a data object.
11437 * @param {Connection} conn This Connection object.
11438 * @param {Object} options The options config object passed to the {@link #request} method.
11440 "beforerequest" : true,
11442 * @event requestcomplete
11443 * Fires if the request was successfully completed.
11444 * @param {Connection} conn This Connection object.
11445 * @param {Object} response The XHR object containing the response data.
11446 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11447 * @param {Object} options The options config object passed to the {@link #request} method.
11449 "requestcomplete" : true,
11451 * @event requestexception
11452 * Fires if an error HTTP status was returned from the server.
11453 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11454 * @param {Connection} conn This Connection object.
11455 * @param {Object} response The XHR object containing the response data.
11456 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11457 * @param {Object} options The options config object passed to the {@link #request} method.
11459 "requestexception" : true
11461 Roo.data.Connection.superclass.constructor.call(this);
11464 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11466 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11469 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11470 * extra parameters to each request made by this object. (defaults to undefined)
11473 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11474 * to each request made by this object. (defaults to undefined)
11477 * @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)
11480 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11484 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11490 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11493 disableCaching: true,
11496 * Sends an HTTP request to a remote server.
11497 * @param {Object} options An object which may contain the following properties:<ul>
11498 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11499 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11500 * request, a url encoded string or a function to call to get either.</li>
11501 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11502 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11503 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11504 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11505 * <li>options {Object} The parameter to the request call.</li>
11506 * <li>success {Boolean} True if the request succeeded.</li>
11507 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11509 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11510 * The callback is passed the following parameters:<ul>
11511 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11512 * <li>options {Object} The parameter to the request call.</li>
11514 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11515 * The callback is passed the following parameters:<ul>
11516 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11517 * <li>options {Object} The parameter to the request call.</li>
11519 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11520 * for the callback function. Defaults to the browser window.</li>
11521 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11522 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11523 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11524 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11525 * params for the post data. Any params will be appended to the URL.</li>
11526 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11528 * @return {Number} transactionId
11530 request : function(o){
11531 if(this.fireEvent("beforerequest", this, o) !== false){
11534 if(typeof p == "function"){
11535 p = p.call(o.scope||window, o);
11537 if(typeof p == "object"){
11538 p = Roo.urlEncode(o.params);
11540 if(this.extraParams){
11541 var extras = Roo.urlEncode(this.extraParams);
11542 p = p ? (p + '&' + extras) : extras;
11545 var url = o.url || this.url;
11546 if(typeof url == 'function'){
11547 url = url.call(o.scope||window, o);
11551 var form = Roo.getDom(o.form);
11552 url = url || form.action;
11554 var enctype = form.getAttribute("enctype");
11555 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11556 return this.doFormUpload(o, p, url);
11558 var f = Roo.lib.Ajax.serializeForm(form);
11559 p = p ? (p + '&' + f) : f;
11562 var hs = o.headers;
11563 if(this.defaultHeaders){
11564 hs = Roo.apply(hs || {}, this.defaultHeaders);
11571 success: this.handleResponse,
11572 failure: this.handleFailure,
11574 argument: {options: o},
11575 timeout : o.timeout || this.timeout
11578 var method = o.method||this.method||(p ? "POST" : "GET");
11580 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11581 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11584 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11588 }else if(this.autoAbort !== false){
11592 if((method == 'GET' && p) || o.xmlData){
11593 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11596 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11597 return this.transId;
11599 Roo.callback(o.callback, o.scope, [o, null, null]);
11605 * Determine whether this object has a request outstanding.
11606 * @param {Number} transactionId (Optional) defaults to the last transaction
11607 * @return {Boolean} True if there is an outstanding request.
11609 isLoading : function(transId){
11611 return Roo.lib.Ajax.isCallInProgress(transId);
11613 return this.transId ? true : false;
11618 * Aborts any outstanding request.
11619 * @param {Number} transactionId (Optional) defaults to the last transaction
11621 abort : function(transId){
11622 if(transId || this.isLoading()){
11623 Roo.lib.Ajax.abort(transId || this.transId);
11628 handleResponse : function(response){
11629 this.transId = false;
11630 var options = response.argument.options;
11631 response.argument = options ? options.argument : null;
11632 this.fireEvent("requestcomplete", this, response, options);
11633 Roo.callback(options.success, options.scope, [response, options]);
11634 Roo.callback(options.callback, options.scope, [options, true, response]);
11638 handleFailure : function(response, e){
11639 this.transId = false;
11640 var options = response.argument.options;
11641 response.argument = options ? options.argument : null;
11642 this.fireEvent("requestexception", this, response, options, e);
11643 Roo.callback(options.failure, options.scope, [response, options]);
11644 Roo.callback(options.callback, options.scope, [options, false, response]);
11648 doFormUpload : function(o, ps, url){
11650 var frame = document.createElement('iframe');
11653 frame.className = 'x-hidden';
11655 frame.src = Roo.SSL_SECURE_URL;
11657 document.body.appendChild(frame);
11660 document.frames[id].name = id;
11663 var form = Roo.getDom(o.form);
11665 form.method = 'POST';
11666 form.enctype = form.encoding = 'multipart/form-data';
11672 if(ps){ // add dynamic params
11674 ps = Roo.urlDecode(ps, false);
11676 if(ps.hasOwnProperty(k)){
11677 hd = document.createElement('input');
11678 hd.type = 'hidden';
11681 form.appendChild(hd);
11688 var r = { // bogus response object
11693 r.argument = o ? o.argument : null;
11698 doc = frame.contentWindow.document;
11700 doc = (frame.contentDocument || window.frames[id].document);
11702 if(doc && doc.body){
11703 r.responseText = doc.body.innerHTML;
11705 if(doc && doc.XMLDocument){
11706 r.responseXML = doc.XMLDocument;
11708 r.responseXML = doc;
11715 Roo.EventManager.removeListener(frame, 'load', cb, this);
11717 this.fireEvent("requestcomplete", this, r, o);
11718 Roo.callback(o.success, o.scope, [r, o]);
11719 Roo.callback(o.callback, o.scope, [o, true, r]);
11721 setTimeout(function(){document.body.removeChild(frame);}, 100);
11724 Roo.EventManager.on(frame, 'load', cb, this);
11727 if(hiddens){ // remove dynamic params
11728 for(var i = 0, len = hiddens.length; i < len; i++){
11729 form.removeChild(hiddens[i]);
11736 * Ext JS Library 1.1.1
11737 * Copyright(c) 2006-2007, Ext JS, LLC.
11739 * Originally Released Under LGPL - original licence link has changed is not relivant.
11742 * <script type="text/javascript">
11746 * Global Ajax request class.
11749 * @extends Roo.data.Connection
11752 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11753 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11754 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11755 * @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)
11756 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11757 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11758 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11760 Roo.Ajax = new Roo.data.Connection({
11769 * Serialize the passed form into a url encoded string
11771 * @param {String/HTMLElement} form
11774 serializeForm : function(form){
11775 return Roo.lib.Ajax.serializeForm(form);
11779 * Ext JS Library 1.1.1
11780 * Copyright(c) 2006-2007, Ext JS, LLC.
11782 * Originally Released Under LGPL - original licence link has changed is not relivant.
11785 * <script type="text/javascript">
11790 * @class Roo.UpdateManager
11791 * @extends Roo.util.Observable
11792 * Provides AJAX-style update for Element object.<br><br>
11795 * // Get it from a Roo.Element object
11796 * var el = Roo.get("foo");
11797 * var mgr = el.getUpdateManager();
11798 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11800 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11802 * // or directly (returns the same UpdateManager instance)
11803 * var mgr = new Roo.UpdateManager("myElementId");
11804 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11805 * mgr.on("update", myFcnNeedsToKnow);
11807 // short handed call directly from the element object
11808 Roo.get("foo").load({
11812 text: "Loading Foo..."
11816 * Create new UpdateManager directly.
11817 * @param {String/HTMLElement/Roo.Element} el The element to update
11818 * @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).
11820 Roo.UpdateManager = function(el, forceNew){
11822 if(!forceNew && el.updateManager){
11823 return el.updateManager;
11826 * The Element object
11827 * @type Roo.Element
11831 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11834 this.defaultUrl = null;
11838 * @event beforeupdate
11839 * Fired before an update is made, return false from your handler and the update is cancelled.
11840 * @param {Roo.Element} el
11841 * @param {String/Object/Function} url
11842 * @param {String/Object} params
11844 "beforeupdate": true,
11847 * Fired after successful update is made.
11848 * @param {Roo.Element} el
11849 * @param {Object} oResponseObject The response Object
11854 * Fired on update failure.
11855 * @param {Roo.Element} el
11856 * @param {Object} oResponseObject The response Object
11860 var d = Roo.UpdateManager.defaults;
11862 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11865 this.sslBlankUrl = d.sslBlankUrl;
11867 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11870 this.disableCaching = d.disableCaching;
11872 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11875 this.indicatorText = d.indicatorText;
11877 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11880 this.showLoadIndicator = d.showLoadIndicator;
11882 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11885 this.timeout = d.timeout;
11888 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11891 this.loadScripts = d.loadScripts;
11894 * Transaction object of current executing transaction
11896 this.transaction = null;
11901 this.autoRefreshProcId = null;
11903 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11906 this.refreshDelegate = this.refresh.createDelegate(this);
11908 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11911 this.updateDelegate = this.update.createDelegate(this);
11913 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11916 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11920 this.successDelegate = this.processSuccess.createDelegate(this);
11924 this.failureDelegate = this.processFailure.createDelegate(this);
11926 if(!this.renderer){
11928 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11930 this.renderer = new Roo.UpdateManager.BasicRenderer();
11933 Roo.UpdateManager.superclass.constructor.call(this);
11936 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11938 * Get the Element this UpdateManager is bound to
11939 * @return {Roo.Element} The element
11941 getEl : function(){
11945 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11946 * @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:
11949 url: "your-url.php",<br/>
11950 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11951 callback: yourFunction,<br/>
11952 scope: yourObject, //(optional scope) <br/>
11953 discardUrl: false, <br/>
11954 nocache: false,<br/>
11955 text: "Loading...",<br/>
11957 scripts: false<br/>
11960 * The only required property is url. The optional properties nocache, text and scripts
11961 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11962 * @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}
11963 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11964 * @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.
11966 update : function(url, params, callback, discardUrl){
11967 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11968 var method = this.method,
11970 if(typeof url == "object"){ // must be config object
11973 params = params || cfg.params;
11974 callback = callback || cfg.callback;
11975 discardUrl = discardUrl || cfg.discardUrl;
11976 if(callback && cfg.scope){
11977 callback = callback.createDelegate(cfg.scope);
11979 if(typeof cfg.method != "undefined"){method = cfg.method;};
11980 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11981 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11982 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11983 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11985 this.showLoading();
11987 this.defaultUrl = url;
11989 if(typeof url == "function"){
11990 url = url.call(this);
11993 method = method || (params ? "POST" : "GET");
11994 if(method == "GET"){
11995 url = this.prepareUrl(url);
11998 var o = Roo.apply(cfg ||{}, {
12001 success: this.successDelegate,
12002 failure: this.failureDelegate,
12003 callback: undefined,
12004 timeout: (this.timeout*1000),
12005 argument: {"url": url, "form": null, "callback": callback, "params": params}
12007 Roo.log("updated manager called with timeout of " + o.timeout);
12008 this.transaction = Roo.Ajax.request(o);
12013 * 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.
12014 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12015 * @param {String/HTMLElement} form The form Id or form element
12016 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12017 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12018 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12020 formUpdate : function(form, url, reset, callback){
12021 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12022 if(typeof url == "function"){
12023 url = url.call(this);
12025 form = Roo.getDom(form);
12026 this.transaction = Roo.Ajax.request({
12029 success: this.successDelegate,
12030 failure: this.failureDelegate,
12031 timeout: (this.timeout*1000),
12032 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12034 this.showLoading.defer(1, this);
12039 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12040 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12042 refresh : function(callback){
12043 if(this.defaultUrl == null){
12046 this.update(this.defaultUrl, null, callback, true);
12050 * Set this element to auto refresh.
12051 * @param {Number} interval How often to update (in seconds).
12052 * @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)
12053 * @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}
12054 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12055 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12057 startAutoRefresh : function(interval, url, params, callback, refreshNow){
12059 this.update(url || this.defaultUrl, params, callback, true);
12061 if(this.autoRefreshProcId){
12062 clearInterval(this.autoRefreshProcId);
12064 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12068 * Stop auto refresh on this element.
12070 stopAutoRefresh : function(){
12071 if(this.autoRefreshProcId){
12072 clearInterval(this.autoRefreshProcId);
12073 delete this.autoRefreshProcId;
12077 isAutoRefreshing : function(){
12078 return this.autoRefreshProcId ? true : false;
12081 * Called to update the element to "Loading" state. Override to perform custom action.
12083 showLoading : function(){
12084 if(this.showLoadIndicator){
12085 this.el.update(this.indicatorText);
12090 * Adds unique parameter to query string if disableCaching = true
12093 prepareUrl : function(url){
12094 if(this.disableCaching){
12095 var append = "_dc=" + (new Date().getTime());
12096 if(url.indexOf("?") !== -1){
12097 url += "&" + append;
12099 url += "?" + append;
12108 processSuccess : function(response){
12109 this.transaction = null;
12110 if(response.argument.form && response.argument.reset){
12111 try{ // put in try/catch since some older FF releases had problems with this
12112 response.argument.form.reset();
12115 if(this.loadScripts){
12116 this.renderer.render(this.el, response, this,
12117 this.updateComplete.createDelegate(this, [response]));
12119 this.renderer.render(this.el, response, this);
12120 this.updateComplete(response);
12124 updateComplete : function(response){
12125 this.fireEvent("update", this.el, response);
12126 if(typeof response.argument.callback == "function"){
12127 response.argument.callback(this.el, true, response);
12134 processFailure : function(response){
12135 this.transaction = null;
12136 this.fireEvent("failure", this.el, response);
12137 if(typeof response.argument.callback == "function"){
12138 response.argument.callback(this.el, false, response);
12143 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12144 * @param {Object} renderer The object implementing the render() method
12146 setRenderer : function(renderer){
12147 this.renderer = renderer;
12150 getRenderer : function(){
12151 return this.renderer;
12155 * Set the defaultUrl used for updates
12156 * @param {String/Function} defaultUrl The url or a function to call to get the url
12158 setDefaultUrl : function(defaultUrl){
12159 this.defaultUrl = defaultUrl;
12163 * Aborts the executing transaction
12165 abort : function(){
12166 if(this.transaction){
12167 Roo.Ajax.abort(this.transaction);
12172 * Returns true if an update is in progress
12173 * @return {Boolean}
12175 isUpdating : function(){
12176 if(this.transaction){
12177 return Roo.Ajax.isLoading(this.transaction);
12184 * @class Roo.UpdateManager.defaults
12185 * @static (not really - but it helps the doc tool)
12186 * The defaults collection enables customizing the default properties of UpdateManager
12188 Roo.UpdateManager.defaults = {
12190 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12196 * True to process scripts by default (Defaults to false).
12199 loadScripts : false,
12202 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12205 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12207 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12210 disableCaching : false,
12212 * Whether to show indicatorText when loading (Defaults to true).
12215 showLoadIndicator : true,
12217 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12220 indicatorText : '<div class="loading-indicator">Loading...</div>'
12224 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12226 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12227 * @param {String/HTMLElement/Roo.Element} el The element to update
12228 * @param {String} url The url
12229 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12230 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12233 * @member Roo.UpdateManager
12235 Roo.UpdateManager.updateElement = function(el, url, params, options){
12236 var um = Roo.get(el, true).getUpdateManager();
12237 Roo.apply(um, options);
12238 um.update(url, params, options ? options.callback : null);
12240 // alias for backwards compat
12241 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12243 * @class Roo.UpdateManager.BasicRenderer
12244 * Default Content renderer. Updates the elements innerHTML with the responseText.
12246 Roo.UpdateManager.BasicRenderer = function(){};
12248 Roo.UpdateManager.BasicRenderer.prototype = {
12250 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12251 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12252 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12253 * @param {Roo.Element} el The element being rendered
12254 * @param {Object} response The YUI Connect response object
12255 * @param {UpdateManager} updateManager The calling update manager
12256 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12258 render : function(el, response, updateManager, callback){
12259 el.update(response.responseText, updateManager.loadScripts, callback);
12265 * (c)) Alan Knowles
12271 * @class Roo.DomTemplate
12272 * @extends Roo.Template
12273 * An effort at a dom based template engine..
12275 * Similar to XTemplate, except it uses dom parsing to create the template..
12277 * Supported features:
12282 {a_variable} - output encoded.
12283 {a_variable.format:("Y-m-d")} - call a method on the variable
12284 {a_variable:raw} - unencoded output
12285 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12286 {a_variable:this.method_on_template(...)} - call a method on the template object.
12291 <div roo-for="a_variable or condition.."></div>
12292 <div roo-if="a_variable or condition"></div>
12293 <div roo-exec="some javascript"></div>
12294 <div roo-name="named_template"></div>
12299 Roo.DomTemplate = function()
12301 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12308 Roo.extend(Roo.DomTemplate, Roo.Template, {
12310 * id counter for sub templates.
12314 * flag to indicate if dom parser is inside a pre,
12315 * it will strip whitespace if not.
12320 * The various sub templates
12328 * basic tag replacing syntax
12331 * // you can fake an object call by doing this
12335 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12336 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12338 iterChild : function (node, method) {
12340 var oldPre = this.inPre;
12341 if (node.tagName == 'PRE') {
12344 for( var i = 0; i < node.childNodes.length; i++) {
12345 method.call(this, node.childNodes[i]);
12347 this.inPre = oldPre;
12353 * compile the template
12355 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12358 compile: function()
12362 // covert the html into DOM...
12366 doc = document.implementation.createHTMLDocument("");
12367 doc.documentElement.innerHTML = this.html ;
12368 div = doc.documentElement;
12370 // old IE... - nasty -- it causes all sorts of issues.. with
12371 // images getting pulled from server..
12372 div = document.createElement('div');
12373 div.innerHTML = this.html;
12375 //doc.documentElement.innerHTML = htmlBody
12381 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12383 var tpls = this.tpls;
12385 // create a top level template from the snippet..
12387 //Roo.log(div.innerHTML);
12394 body : div.innerHTML,
12407 Roo.each(tpls, function(tp){
12408 this.compileTpl(tp);
12409 this.tpls[tp.id] = tp;
12412 this.master = tpls[0];
12418 compileNode : function(node, istop) {
12423 // skip anything not a tag..
12424 if (node.nodeType != 1) {
12425 if (node.nodeType == 3 && !this.inPre) {
12426 // reduce white space..
12427 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12450 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12451 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12452 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12453 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12459 // just itterate children..
12460 this.iterChild(node,this.compileNode);
12463 tpl.uid = this.id++;
12464 tpl.value = node.getAttribute('roo-' + tpl.attr);
12465 node.removeAttribute('roo-'+ tpl.attr);
12466 if (tpl.attr != 'name') {
12467 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12468 node.parentNode.replaceChild(placeholder, node);
12471 var placeholder = document.createElement('span');
12472 placeholder.className = 'roo-tpl-' + tpl.value;
12473 node.parentNode.replaceChild(placeholder, node);
12476 // parent now sees '{domtplXXXX}
12477 this.iterChild(node,this.compileNode);
12479 // we should now have node body...
12480 var div = document.createElement('div');
12481 div.appendChild(node);
12483 // this has the unfortunate side effect of converting tagged attributes
12484 // eg. href="{...}" into %7C...%7D
12485 // this has been fixed by searching for those combo's although it's a bit hacky..
12488 tpl.body = div.innerHTML;
12495 switch (tpl.value) {
12496 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12497 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12498 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12503 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12507 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12511 tpl.id = tpl.value; // replace non characters???
12517 this.tpls.push(tpl);
12527 * Compile a segment of the template into a 'sub-template'
12533 compileTpl : function(tpl)
12535 var fm = Roo.util.Format;
12536 var useF = this.disableFormats !== true;
12538 var sep = Roo.isGecko ? "+\n" : ",\n";
12540 var undef = function(str) {
12541 Roo.debug && Roo.log("Property not found :" + str);
12545 //Roo.log(tpl.body);
12549 var fn = function(m, lbrace, name, format, args)
12552 //Roo.log(arguments);
12553 args = args ? args.replace(/\\'/g,"'") : args;
12554 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12555 if (typeof(format) == 'undefined') {
12556 format = 'htmlEncode';
12558 if (format == 'raw' ) {
12562 if(name.substr(0, 6) == 'domtpl'){
12563 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12566 // build an array of options to determine if value is undefined..
12568 // basically get 'xxxx.yyyy' then do
12569 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12570 // (function () { Roo.log("Property not found"); return ''; })() :
12575 Roo.each(name.split('.'), function(st) {
12576 lookfor += (lookfor.length ? '.': '') + st;
12577 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12580 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12583 if(format && useF){
12585 args = args ? ',' + args : "";
12587 if(format.substr(0, 5) != "this."){
12588 format = "fm." + format + '(';
12590 format = 'this.call("'+ format.substr(5) + '", ';
12594 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12597 if (args && args.length) {
12598 // called with xxyx.yuu:(test,test)
12600 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12602 // raw.. - :raw modifier..
12603 return "'"+ sep + udef_st + name + ")"+sep+"'";
12607 // branched to use + in gecko and [].join() in others
12609 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12610 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12613 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12614 body.push(tpl.body.replace(/(\r\n|\n)/g,
12615 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12616 body.push("'].join('');};};");
12617 body = body.join('');
12620 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12622 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12629 * same as applyTemplate, except it's done to one of the subTemplates
12630 * when using named templates, you can do:
12632 * var str = pl.applySubTemplate('your-name', values);
12635 * @param {Number} id of the template
12636 * @param {Object} values to apply to template
12637 * @param {Object} parent (normaly the instance of this object)
12639 applySubTemplate : function(id, values, parent)
12643 var t = this.tpls[id];
12647 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12648 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12652 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12659 if(t.execCall && t.execCall.call(this, values, parent)){
12663 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12669 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12670 parent = t.target ? values : parent;
12671 if(t.forCall && vs instanceof Array){
12673 for(var i = 0, len = vs.length; i < len; i++){
12675 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12677 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12679 //Roo.log(t.compiled);
12683 return buf.join('');
12686 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12691 return t.compiled.call(this, vs, parent);
12693 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12695 //Roo.log(t.compiled);
12703 applyTemplate : function(values){
12704 return this.master.compiled.call(this, values, {});
12705 //var s = this.subs;
12708 apply : function(){
12709 return this.applyTemplate.apply(this, arguments);
12714 Roo.DomTemplate.from = function(el){
12715 el = Roo.getDom(el);
12716 return new Roo.Domtemplate(el.value || el.innerHTML);
12719 * Ext JS Library 1.1.1
12720 * Copyright(c) 2006-2007, Ext JS, LLC.
12722 * Originally Released Under LGPL - original licence link has changed is not relivant.
12725 * <script type="text/javascript">
12729 * @class Roo.util.DelayedTask
12730 * Provides a convenient method of performing setTimeout where a new
12731 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12732 * You can use this class to buffer
12733 * the keypress events for a certain number of milliseconds, and perform only if they stop
12734 * for that amount of time.
12735 * @constructor The parameters to this constructor serve as defaults and are not required.
12736 * @param {Function} fn (optional) The default function to timeout
12737 * @param {Object} scope (optional) The default scope of that timeout
12738 * @param {Array} args (optional) The default Array of arguments
12740 Roo.util.DelayedTask = function(fn, scope, args){
12741 var id = null, d, t;
12743 var call = function(){
12744 var now = new Date().getTime();
12748 fn.apply(scope, args || []);
12752 * Cancels any pending timeout and queues a new one
12753 * @param {Number} delay The milliseconds to delay
12754 * @param {Function} newFn (optional) Overrides function passed to constructor
12755 * @param {Object} newScope (optional) Overrides scope passed to constructor
12756 * @param {Array} newArgs (optional) Overrides args passed to constructor
12758 this.delay = function(delay, newFn, newScope, newArgs){
12759 if(id && delay != d){
12763 t = new Date().getTime();
12765 scope = newScope || scope;
12766 args = newArgs || args;
12768 id = setInterval(call, d);
12773 * Cancel the last queued timeout
12775 this.cancel = function(){
12783 * Ext JS Library 1.1.1
12784 * Copyright(c) 2006-2007, Ext JS, LLC.
12786 * Originally Released Under LGPL - original licence link has changed is not relivant.
12789 * <script type="text/javascript">
12793 Roo.util.TaskRunner = function(interval){
12794 interval = interval || 10;
12795 var tasks = [], removeQueue = [];
12797 var running = false;
12799 var stopThread = function(){
12805 var startThread = function(){
12808 id = setInterval(runTasks, interval);
12812 var removeTask = function(task){
12813 removeQueue.push(task);
12819 var runTasks = function(){
12820 if(removeQueue.length > 0){
12821 for(var i = 0, len = removeQueue.length; i < len; i++){
12822 tasks.remove(removeQueue[i]);
12825 if(tasks.length < 1){
12830 var now = new Date().getTime();
12831 for(var i = 0, len = tasks.length; i < len; ++i){
12833 var itime = now - t.taskRunTime;
12834 if(t.interval <= itime){
12835 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12836 t.taskRunTime = now;
12837 if(rt === false || t.taskRunCount === t.repeat){
12842 if(t.duration && t.duration <= (now - t.taskStartTime)){
12849 * Queues a new task.
12850 * @param {Object} task
12852 this.start = function(task){
12854 task.taskStartTime = new Date().getTime();
12855 task.taskRunTime = 0;
12856 task.taskRunCount = 0;
12861 this.stop = function(task){
12866 this.stopAll = function(){
12868 for(var i = 0, len = tasks.length; i < len; i++){
12869 if(tasks[i].onStop){
12878 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12880 * Ext JS Library 1.1.1
12881 * Copyright(c) 2006-2007, Ext JS, LLC.
12883 * Originally Released Under LGPL - original licence link has changed is not relivant.
12886 * <script type="text/javascript">
12891 * @class Roo.util.MixedCollection
12892 * @extends Roo.util.Observable
12893 * A Collection class that maintains both numeric indexes and keys and exposes events.
12895 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12896 * collection (defaults to false)
12897 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12898 * and return the key value for that item. This is used when available to look up the key on items that
12899 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12900 * equivalent to providing an implementation for the {@link #getKey} method.
12902 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12910 * Fires when the collection is cleared.
12915 * Fires when an item is added to the collection.
12916 * @param {Number} index The index at which the item was added.
12917 * @param {Object} o The item added.
12918 * @param {String} key The key associated with the added item.
12923 * Fires when an item is replaced in the collection.
12924 * @param {String} key he key associated with the new added.
12925 * @param {Object} old The item being replaced.
12926 * @param {Object} new The new item.
12931 * Fires when an item is removed from the collection.
12932 * @param {Object} o The item being removed.
12933 * @param {String} key (optional) The key associated with the removed item.
12938 this.allowFunctions = allowFunctions === true;
12940 this.getKey = keyFn;
12942 Roo.util.MixedCollection.superclass.constructor.call(this);
12945 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12946 allowFunctions : false,
12949 * Adds an item to the collection.
12950 * @param {String} key The key to associate with the item
12951 * @param {Object} o The item to add.
12952 * @return {Object} The item added.
12954 add : function(key, o){
12955 if(arguments.length == 1){
12957 key = this.getKey(o);
12959 if(typeof key == "undefined" || key === null){
12961 this.items.push(o);
12962 this.keys.push(null);
12964 var old = this.map[key];
12966 return this.replace(key, o);
12969 this.items.push(o);
12971 this.keys.push(key);
12973 this.fireEvent("add", this.length-1, o, key);
12978 * MixedCollection has a generic way to fetch keys if you implement getKey.
12981 var mc = new Roo.util.MixedCollection();
12982 mc.add(someEl.dom.id, someEl);
12983 mc.add(otherEl.dom.id, otherEl);
12987 var mc = new Roo.util.MixedCollection();
12988 mc.getKey = function(el){
12994 // or via the constructor
12995 var mc = new Roo.util.MixedCollection(false, function(el){
13001 * @param o {Object} The item for which to find the key.
13002 * @return {Object} The key for the passed item.
13004 getKey : function(o){
13009 * Replaces an item in the collection.
13010 * @param {String} key The key associated with the item to replace, or the item to replace.
13011 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13012 * @return {Object} The new item.
13014 replace : function(key, o){
13015 if(arguments.length == 1){
13017 key = this.getKey(o);
13019 var old = this.item(key);
13020 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13021 return this.add(key, o);
13023 var index = this.indexOfKey(key);
13024 this.items[index] = o;
13026 this.fireEvent("replace", key, old, o);
13031 * Adds all elements of an Array or an Object to the collection.
13032 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13033 * an Array of values, each of which are added to the collection.
13035 addAll : function(objs){
13036 if(arguments.length > 1 || objs instanceof Array){
13037 var args = arguments.length > 1 ? arguments : objs;
13038 for(var i = 0, len = args.length; i < len; i++){
13042 for(var key in objs){
13043 if(this.allowFunctions || typeof objs[key] != "function"){
13044 this.add(key, objs[key]);
13051 * Executes the specified function once for every item in the collection, passing each
13052 * item as the first and only parameter. returning false from the function will stop the iteration.
13053 * @param {Function} fn The function to execute for each item.
13054 * @param {Object} scope (optional) The scope in which to execute the function.
13056 each : function(fn, scope){
13057 var items = [].concat(this.items); // each safe for removal
13058 for(var i = 0, len = items.length; i < len; i++){
13059 if(fn.call(scope || items[i], items[i], i, len) === false){
13066 * Executes the specified function once for every key in the collection, passing each
13067 * key, and its associated item as the first two parameters.
13068 * @param {Function} fn The function to execute for each item.
13069 * @param {Object} scope (optional) The scope in which to execute the function.
13071 eachKey : function(fn, scope){
13072 for(var i = 0, len = this.keys.length; i < len; i++){
13073 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13078 * Returns the first item in the collection which elicits a true return value from the
13079 * passed selection function.
13080 * @param {Function} fn The selection function to execute for each item.
13081 * @param {Object} scope (optional) The scope in which to execute the function.
13082 * @return {Object} The first item in the collection which returned true from the selection function.
13084 find : function(fn, scope){
13085 for(var i = 0, len = this.items.length; i < len; i++){
13086 if(fn.call(scope || window, this.items[i], this.keys[i])){
13087 return this.items[i];
13094 * Inserts an item at the specified index in the collection.
13095 * @param {Number} index The index to insert the item at.
13096 * @param {String} key The key to associate with the new item, or the item itself.
13097 * @param {Object} o (optional) If the second parameter was a key, the new item.
13098 * @return {Object} The item inserted.
13100 insert : function(index, key, o){
13101 if(arguments.length == 2){
13103 key = this.getKey(o);
13105 if(index >= this.length){
13106 return this.add(key, o);
13109 this.items.splice(index, 0, o);
13110 if(typeof key != "undefined" && key != null){
13113 this.keys.splice(index, 0, key);
13114 this.fireEvent("add", index, o, key);
13119 * Removed an item from the collection.
13120 * @param {Object} o The item to remove.
13121 * @return {Object} The item removed.
13123 remove : function(o){
13124 return this.removeAt(this.indexOf(o));
13128 * Remove an item from a specified index in the collection.
13129 * @param {Number} index The index within the collection of the item to remove.
13131 removeAt : function(index){
13132 if(index < this.length && index >= 0){
13134 var o = this.items[index];
13135 this.items.splice(index, 1);
13136 var key = this.keys[index];
13137 if(typeof key != "undefined"){
13138 delete this.map[key];
13140 this.keys.splice(index, 1);
13141 this.fireEvent("remove", o, key);
13146 * Removed an item associated with the passed key fom the collection.
13147 * @param {String} key The key of the item to remove.
13149 removeKey : function(key){
13150 return this.removeAt(this.indexOfKey(key));
13154 * Returns the number of items in the collection.
13155 * @return {Number} the number of items in the collection.
13157 getCount : function(){
13158 return this.length;
13162 * Returns index within the collection of the passed Object.
13163 * @param {Object} o The item to find the index of.
13164 * @return {Number} index of the item.
13166 indexOf : function(o){
13167 if(!this.items.indexOf){
13168 for(var i = 0, len = this.items.length; i < len; i++){
13169 if(this.items[i] == o) {
13175 return this.items.indexOf(o);
13180 * Returns index within the collection of the passed key.
13181 * @param {String} key The key to find the index of.
13182 * @return {Number} index of the key.
13184 indexOfKey : function(key){
13185 if(!this.keys.indexOf){
13186 for(var i = 0, len = this.keys.length; i < len; i++){
13187 if(this.keys[i] == key) {
13193 return this.keys.indexOf(key);
13198 * Returns the item associated with the passed key OR index. Key has priority over index.
13199 * @param {String/Number} key The key or index of the item.
13200 * @return {Object} The item associated with the passed key.
13202 item : function(key){
13203 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13204 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13208 * Returns the item at the specified index.
13209 * @param {Number} index The index of the item.
13212 itemAt : function(index){
13213 return this.items[index];
13217 * Returns the item associated with the passed key.
13218 * @param {String/Number} key The key of the item.
13219 * @return {Object} The item associated with the passed key.
13221 key : function(key){
13222 return this.map[key];
13226 * Returns true if the collection contains the passed Object as an item.
13227 * @param {Object} o The Object to look for in the collection.
13228 * @return {Boolean} True if the collection contains the Object as an item.
13230 contains : function(o){
13231 return this.indexOf(o) != -1;
13235 * Returns true if the collection contains the passed Object as a key.
13236 * @param {String} key The key to look for in the collection.
13237 * @return {Boolean} True if the collection contains the Object as a key.
13239 containsKey : function(key){
13240 return typeof this.map[key] != "undefined";
13244 * Removes all items from the collection.
13246 clear : function(){
13251 this.fireEvent("clear");
13255 * Returns the first item in the collection.
13256 * @return {Object} the first item in the collection..
13258 first : function(){
13259 return this.items[0];
13263 * Returns the last item in the collection.
13264 * @return {Object} the last item in the collection..
13267 return this.items[this.length-1];
13270 _sort : function(property, dir, fn){
13271 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13272 fn = fn || function(a, b){
13275 var c = [], k = this.keys, items = this.items;
13276 for(var i = 0, len = items.length; i < len; i++){
13277 c[c.length] = {key: k[i], value: items[i], index: i};
13279 c.sort(function(a, b){
13280 var v = fn(a[property], b[property]) * dsc;
13282 v = (a.index < b.index ? -1 : 1);
13286 for(var i = 0, len = c.length; i < len; i++){
13287 items[i] = c[i].value;
13290 this.fireEvent("sort", this);
13294 * Sorts this collection with the passed comparison function
13295 * @param {String} direction (optional) "ASC" or "DESC"
13296 * @param {Function} fn (optional) comparison function
13298 sort : function(dir, fn){
13299 this._sort("value", dir, fn);
13303 * Sorts this collection by keys
13304 * @param {String} direction (optional) "ASC" or "DESC"
13305 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13307 keySort : function(dir, fn){
13308 this._sort("key", dir, fn || function(a, b){
13309 return String(a).toUpperCase()-String(b).toUpperCase();
13314 * Returns a range of items in this collection
13315 * @param {Number} startIndex (optional) defaults to 0
13316 * @param {Number} endIndex (optional) default to the last item
13317 * @return {Array} An array of items
13319 getRange : function(start, end){
13320 var items = this.items;
13321 if(items.length < 1){
13324 start = start || 0;
13325 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13328 for(var i = start; i <= end; i++) {
13329 r[r.length] = items[i];
13332 for(var i = start; i >= end; i--) {
13333 r[r.length] = items[i];
13340 * Filter the <i>objects</i> in this collection by a specific property.
13341 * Returns a new collection that has been filtered.
13342 * @param {String} property A property on your objects
13343 * @param {String/RegExp} value Either string that the property values
13344 * should start with or a RegExp to test against the property
13345 * @return {MixedCollection} The new filtered collection
13347 filter : function(property, value){
13348 if(!value.exec){ // not a regex
13349 value = String(value);
13350 if(value.length == 0){
13351 return this.clone();
13353 value = new RegExp("^" + Roo.escapeRe(value), "i");
13355 return this.filterBy(function(o){
13356 return o && value.test(o[property]);
13361 * Filter by a function. * Returns a new collection that has been filtered.
13362 * The passed function will be called with each
13363 * object in the collection. If the function returns true, the value is included
13364 * otherwise it is filtered.
13365 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13366 * @param {Object} scope (optional) The scope of the function (defaults to this)
13367 * @return {MixedCollection} The new filtered collection
13369 filterBy : function(fn, scope){
13370 var r = new Roo.util.MixedCollection();
13371 r.getKey = this.getKey;
13372 var k = this.keys, it = this.items;
13373 for(var i = 0, len = it.length; i < len; i++){
13374 if(fn.call(scope||this, it[i], k[i])){
13375 r.add(k[i], it[i]);
13382 * Creates a duplicate of this collection
13383 * @return {MixedCollection}
13385 clone : function(){
13386 var r = new Roo.util.MixedCollection();
13387 var k = this.keys, it = this.items;
13388 for(var i = 0, len = it.length; i < len; i++){
13389 r.add(k[i], it[i]);
13391 r.getKey = this.getKey;
13396 * Returns the item associated with the passed key or index.
13398 * @param {String/Number} key The key or index of the item.
13399 * @return {Object} The item associated with the passed key.
13401 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13403 * Ext JS Library 1.1.1
13404 * Copyright(c) 2006-2007, Ext JS, LLC.
13406 * Originally Released Under LGPL - original licence link has changed is not relivant.
13409 * <script type="text/javascript">
13412 * @class Roo.util.JSON
13413 * Modified version of Douglas Crockford"s json.js that doesn"t
13414 * mess with the Object prototype
13415 * http://www.json.org/js.html
13418 Roo.util.JSON = new (function(){
13419 var useHasOwn = {}.hasOwnProperty ? true : false;
13421 // crashes Safari in some instances
13422 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13424 var pad = function(n) {
13425 return n < 10 ? "0" + n : n;
13438 var encodeString = function(s){
13439 if (/["\\\x00-\x1f]/.test(s)) {
13440 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13445 c = b.charCodeAt();
13447 Math.floor(c / 16).toString(16) +
13448 (c % 16).toString(16);
13451 return '"' + s + '"';
13454 var encodeArray = function(o){
13455 var a = ["["], b, i, l = o.length, v;
13456 for (i = 0; i < l; i += 1) {
13458 switch (typeof v) {
13467 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13475 var encodeDate = function(o){
13476 return '"' + o.getFullYear() + "-" +
13477 pad(o.getMonth() + 1) + "-" +
13478 pad(o.getDate()) + "T" +
13479 pad(o.getHours()) + ":" +
13480 pad(o.getMinutes()) + ":" +
13481 pad(o.getSeconds()) + '"';
13485 * Encodes an Object, Array or other value
13486 * @param {Mixed} o The variable to encode
13487 * @return {String} The JSON string
13489 this.encode = function(o)
13491 // should this be extended to fully wrap stringify..
13493 if(typeof o == "undefined" || o === null){
13495 }else if(o instanceof Array){
13496 return encodeArray(o);
13497 }else if(o instanceof Date){
13498 return encodeDate(o);
13499 }else if(typeof o == "string"){
13500 return encodeString(o);
13501 }else if(typeof o == "number"){
13502 return isFinite(o) ? String(o) : "null";
13503 }else if(typeof o == "boolean"){
13506 var a = ["{"], b, i, v;
13508 if(!useHasOwn || o.hasOwnProperty(i)) {
13510 switch (typeof v) {
13519 a.push(this.encode(i), ":",
13520 v === null ? "null" : this.encode(v));
13531 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13532 * @param {String} json The JSON string
13533 * @return {Object} The resulting object
13535 this.decode = function(json){
13537 return /** eval:var:json */ eval("(" + json + ')');
13541 * Shorthand for {@link Roo.util.JSON#encode}
13542 * @member Roo encode
13544 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13546 * Shorthand for {@link Roo.util.JSON#decode}
13547 * @member Roo decode
13549 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13552 * Ext JS Library 1.1.1
13553 * Copyright(c) 2006-2007, Ext JS, LLC.
13555 * Originally Released Under LGPL - original licence link has changed is not relivant.
13558 * <script type="text/javascript">
13562 * @class Roo.util.Format
13563 * Reusable data formatting functions
13566 Roo.util.Format = function(){
13567 var trimRe = /^\s+|\s+$/g;
13570 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13571 * @param {String} value The string to truncate
13572 * @param {Number} length The maximum length to allow before truncating
13573 * @return {String} The converted text
13575 ellipsis : function(value, len){
13576 if(value && value.length > len){
13577 return value.substr(0, len-3)+"...";
13583 * Checks a reference and converts it to empty string if it is undefined
13584 * @param {Mixed} value Reference to check
13585 * @return {Mixed} Empty string if converted, otherwise the original value
13587 undef : function(value){
13588 return typeof value != "undefined" ? value : "";
13592 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13593 * @param {String} value The string to encode
13594 * @return {String} The encoded text
13596 htmlEncode : function(value){
13597 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13601 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13602 * @param {String} value The string to decode
13603 * @return {String} The decoded text
13605 htmlDecode : function(value){
13606 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13610 * Trims any whitespace from either side of a string
13611 * @param {String} value The text to trim
13612 * @return {String} The trimmed text
13614 trim : function(value){
13615 return String(value).replace(trimRe, "");
13619 * Returns a substring from within an original string
13620 * @param {String} value The original text
13621 * @param {Number} start The start index of the substring
13622 * @param {Number} length The length of the substring
13623 * @return {String} The substring
13625 substr : function(value, start, length){
13626 return String(value).substr(start, length);
13630 * Converts a string to all lower case letters
13631 * @param {String} value The text to convert
13632 * @return {String} The converted text
13634 lowercase : function(value){
13635 return String(value).toLowerCase();
13639 * Converts a string to all upper case letters
13640 * @param {String} value The text to convert
13641 * @return {String} The converted text
13643 uppercase : function(value){
13644 return String(value).toUpperCase();
13648 * Converts the first character only of a string to upper case
13649 * @param {String} value The text to convert
13650 * @return {String} The converted text
13652 capitalize : function(value){
13653 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13657 call : function(value, fn){
13658 if(arguments.length > 2){
13659 var args = Array.prototype.slice.call(arguments, 2);
13660 args.unshift(value);
13662 return /** eval:var:value */ eval(fn).apply(window, args);
13664 /** eval:var:value */
13665 return /** eval:var:value */ eval(fn).call(window, value);
13671 * safer version of Math.toFixed..??/
13672 * @param {Number/String} value The numeric value to format
13673 * @param {Number/String} value Decimal places
13674 * @return {String} The formatted currency string
13676 toFixed : function(v, n)
13678 // why not use to fixed - precision is buggered???
13680 return Math.round(v-0);
13682 var fact = Math.pow(10,n+1);
13683 v = (Math.round((v-0)*fact))/fact;
13684 var z = (''+fact).substring(2);
13685 if (v == Math.floor(v)) {
13686 return Math.floor(v) + '.' + z;
13689 // now just padd decimals..
13690 var ps = String(v).split('.');
13691 var fd = (ps[1] + z);
13692 var r = fd.substring(0,n);
13693 var rm = fd.substring(n);
13695 return ps[0] + '.' + r;
13697 r*=1; // turn it into a number;
13699 if (String(r).length != n) {
13702 r = String(r).substring(1); // chop the end off.
13705 return ps[0] + '.' + r;
13710 * Format a number as US currency
13711 * @param {Number/String} value The numeric value to format
13712 * @return {String} The formatted currency string
13714 usMoney : function(v){
13715 return '$' + Roo.util.Format.number(v);
13720 * eventually this should probably emulate php's number_format
13721 * @param {Number/String} value The numeric value to format
13722 * @param {Number} decimals number of decimal places
13723 * @return {String} The formatted currency string
13725 number : function(v,decimals)
13727 // multiply and round.
13728 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13729 var mul = Math.pow(10, decimals);
13730 var zero = String(mul).substring(1);
13731 v = (Math.round((v-0)*mul))/mul;
13733 // if it's '0' number.. then
13735 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13737 var ps = v.split('.');
13741 var r = /(\d+)(\d{3})/;
13743 while (r.test(whole)) {
13744 whole = whole.replace(r, '$1' + ',' + '$2');
13750 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13751 // does not have decimals
13752 (decimals ? ('.' + zero) : '');
13755 return whole + sub ;
13759 * Parse a value into a formatted date using the specified format pattern.
13760 * @param {Mixed} value The value to format
13761 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13762 * @return {String} The formatted date string
13764 date : function(v, format){
13768 if(!(v instanceof Date)){
13769 v = new Date(Date.parse(v));
13771 return v.dateFormat(format || Roo.util.Format.defaults.date);
13775 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13776 * @param {String} format Any valid date format string
13777 * @return {Function} The date formatting function
13779 dateRenderer : function(format){
13780 return function(v){
13781 return Roo.util.Format.date(v, format);
13786 stripTagsRE : /<\/?[^>]+>/gi,
13789 * Strips all HTML tags
13790 * @param {Mixed} value The text from which to strip tags
13791 * @return {String} The stripped text
13793 stripTags : function(v){
13794 return !v ? v : String(v).replace(this.stripTagsRE, "");
13798 Roo.util.Format.defaults = {
13802 * Ext JS Library 1.1.1
13803 * Copyright(c) 2006-2007, Ext JS, LLC.
13805 * Originally Released Under LGPL - original licence link has changed is not relivant.
13808 * <script type="text/javascript">
13815 * @class Roo.MasterTemplate
13816 * @extends Roo.Template
13817 * Provides a template that can have child templates. The syntax is:
13819 var t = new Roo.MasterTemplate(
13820 '<select name="{name}">',
13821 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13824 t.add('options', {value: 'foo', text: 'bar'});
13825 // or you can add multiple child elements in one shot
13826 t.addAll('options', [
13827 {value: 'foo', text: 'bar'},
13828 {value: 'foo2', text: 'bar2'},
13829 {value: 'foo3', text: 'bar3'}
13831 // then append, applying the master template values
13832 t.append('my-form', {name: 'my-select'});
13834 * A name attribute for the child template is not required if you have only one child
13835 * template or you want to refer to them by index.
13837 Roo.MasterTemplate = function(){
13838 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13839 this.originalHtml = this.html;
13841 var m, re = this.subTemplateRe;
13844 while(m = re.exec(this.html)){
13845 var name = m[1], content = m[2];
13850 tpl : new Roo.Template(content)
13853 st[name] = st[subIndex];
13855 st[subIndex].tpl.compile();
13856 st[subIndex].tpl.call = this.call.createDelegate(this);
13859 this.subCount = subIndex;
13862 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13864 * The regular expression used to match sub templates
13868 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13871 * Applies the passed values to a child template.
13872 * @param {String/Number} name (optional) The name or index of the child template
13873 * @param {Array/Object} values The values to be applied to the template
13874 * @return {MasterTemplate} this
13876 add : function(name, values){
13877 if(arguments.length == 1){
13878 values = arguments[0];
13881 var s = this.subs[name];
13882 s.buffer[s.buffer.length] = s.tpl.apply(values);
13887 * Applies all the passed values to a child template.
13888 * @param {String/Number} name (optional) The name or index of the child template
13889 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13890 * @param {Boolean} reset (optional) True to reset the template first
13891 * @return {MasterTemplate} this
13893 fill : function(name, values, reset){
13895 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13903 for(var i = 0, len = values.length; i < len; i++){
13904 this.add(name, values[i]);
13910 * Resets the template for reuse
13911 * @return {MasterTemplate} this
13913 reset : function(){
13915 for(var i = 0; i < this.subCount; i++){
13921 applyTemplate : function(values){
13923 var replaceIndex = -1;
13924 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13925 return s[++replaceIndex].buffer.join("");
13927 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13930 apply : function(){
13931 return this.applyTemplate.apply(this, arguments);
13934 compile : function(){return this;}
13938 * Alias for fill().
13941 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13943 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13944 * var tpl = Roo.MasterTemplate.from('element-id');
13945 * @param {String/HTMLElement} el
13946 * @param {Object} config
13949 Roo.MasterTemplate.from = function(el, config){
13950 el = Roo.getDom(el);
13951 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13954 * Ext JS Library 1.1.1
13955 * Copyright(c) 2006-2007, Ext JS, LLC.
13957 * Originally Released Under LGPL - original licence link has changed is not relivant.
13960 * <script type="text/javascript">
13965 * @class Roo.util.CSS
13966 * Utility class for manipulating CSS rules
13969 Roo.util.CSS = function(){
13971 var doc = document;
13973 var camelRe = /(-[a-z])/gi;
13974 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13978 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13979 * tag and appended to the HEAD of the document.
13980 * @param {String|Object} cssText The text containing the css rules
13981 * @param {String} id An id to add to the stylesheet for later removal
13982 * @return {StyleSheet}
13984 createStyleSheet : function(cssText, id){
13986 var head = doc.getElementsByTagName("head")[0];
13987 var nrules = doc.createElement("style");
13988 nrules.setAttribute("type", "text/css");
13990 nrules.setAttribute("id", id);
13992 if (typeof(cssText) != 'string') {
13993 // support object maps..
13994 // not sure if this a good idea..
13995 // perhaps it should be merged with the general css handling
13996 // and handle js style props.
13997 var cssTextNew = [];
13998 for(var n in cssText) {
14000 for(var k in cssText[n]) {
14001 citems.push( k + ' : ' +cssText[n][k] + ';' );
14003 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14006 cssText = cssTextNew.join("\n");
14012 head.appendChild(nrules);
14013 ss = nrules.styleSheet;
14014 ss.cssText = cssText;
14017 nrules.appendChild(doc.createTextNode(cssText));
14019 nrules.cssText = cssText;
14021 head.appendChild(nrules);
14022 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14024 this.cacheStyleSheet(ss);
14029 * Removes a style or link tag by id
14030 * @param {String} id The id of the tag
14032 removeStyleSheet : function(id){
14033 var existing = doc.getElementById(id);
14035 existing.parentNode.removeChild(existing);
14040 * Dynamically swaps an existing stylesheet reference for a new one
14041 * @param {String} id The id of an existing link tag to remove
14042 * @param {String} url The href of the new stylesheet to include
14044 swapStyleSheet : function(id, url){
14045 this.removeStyleSheet(id);
14046 var ss = doc.createElement("link");
14047 ss.setAttribute("rel", "stylesheet");
14048 ss.setAttribute("type", "text/css");
14049 ss.setAttribute("id", id);
14050 ss.setAttribute("href", url);
14051 doc.getElementsByTagName("head")[0].appendChild(ss);
14055 * Refresh the rule cache if you have dynamically added stylesheets
14056 * @return {Object} An object (hash) of rules indexed by selector
14058 refreshCache : function(){
14059 return this.getRules(true);
14063 cacheStyleSheet : function(stylesheet){
14067 try{// try catch for cross domain access issue
14068 var ssRules = stylesheet.cssRules || stylesheet.rules;
14069 for(var j = ssRules.length-1; j >= 0; --j){
14070 rules[ssRules[j].selectorText] = ssRules[j];
14076 * Gets all css rules for the document
14077 * @param {Boolean} refreshCache true to refresh the internal cache
14078 * @return {Object} An object (hash) of rules indexed by selector
14080 getRules : function(refreshCache){
14081 if(rules == null || refreshCache){
14083 var ds = doc.styleSheets;
14084 for(var i =0, len = ds.length; i < len; i++){
14086 this.cacheStyleSheet(ds[i]);
14094 * Gets an an individual CSS rule by selector(s)
14095 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14096 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14097 * @return {CSSRule} The CSS rule or null if one is not found
14099 getRule : function(selector, refreshCache){
14100 var rs = this.getRules(refreshCache);
14101 if(!(selector instanceof Array)){
14102 return rs[selector];
14104 for(var i = 0; i < selector.length; i++){
14105 if(rs[selector[i]]){
14106 return rs[selector[i]];
14114 * Updates a rule property
14115 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14116 * @param {String} property The css property
14117 * @param {String} value The new value for the property
14118 * @return {Boolean} true If a rule was found and updated
14120 updateRule : function(selector, property, value){
14121 if(!(selector instanceof Array)){
14122 var rule = this.getRule(selector);
14124 rule.style[property.replace(camelRe, camelFn)] = value;
14128 for(var i = 0; i < selector.length; i++){
14129 if(this.updateRule(selector[i], property, value)){
14139 * Ext JS Library 1.1.1
14140 * Copyright(c) 2006-2007, Ext JS, LLC.
14142 * Originally Released Under LGPL - original licence link has changed is not relivant.
14145 * <script type="text/javascript">
14151 * @class Roo.util.ClickRepeater
14152 * @extends Roo.util.Observable
14154 * A wrapper class which can be applied to any element. Fires a "click" event while the
14155 * mouse is pressed. The interval between firings may be specified in the config but
14156 * defaults to 10 milliseconds.
14158 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14160 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14161 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14162 * Similar to an autorepeat key delay.
14163 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14164 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14165 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14166 * "interval" and "delay" are ignored. "immediate" is honored.
14167 * @cfg {Boolean} preventDefault True to prevent the default click event
14168 * @cfg {Boolean} stopDefault True to stop the default click event
14171 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14172 * 2007-02-02 jvs Renamed to ClickRepeater
14173 * 2007-02-03 jvs Modifications for FF Mac and Safari
14176 * @param {String/HTMLElement/Element} el The element to listen on
14177 * @param {Object} config
14179 Roo.util.ClickRepeater = function(el, config)
14181 this.el = Roo.get(el);
14182 this.el.unselectable();
14184 Roo.apply(this, config);
14189 * Fires when the mouse button is depressed.
14190 * @param {Roo.util.ClickRepeater} this
14192 "mousedown" : true,
14195 * Fires on a specified interval during the time the element is pressed.
14196 * @param {Roo.util.ClickRepeater} this
14201 * Fires when the mouse key is released.
14202 * @param {Roo.util.ClickRepeater} this
14207 this.el.on("mousedown", this.handleMouseDown, this);
14208 if(this.preventDefault || this.stopDefault){
14209 this.el.on("click", function(e){
14210 if(this.preventDefault){
14211 e.preventDefault();
14213 if(this.stopDefault){
14219 // allow inline handler
14221 this.on("click", this.handler, this.scope || this);
14224 Roo.util.ClickRepeater.superclass.constructor.call(this);
14227 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14230 preventDefault : true,
14231 stopDefault : false,
14235 handleMouseDown : function(){
14236 clearTimeout(this.timer);
14238 if(this.pressClass){
14239 this.el.addClass(this.pressClass);
14241 this.mousedownTime = new Date();
14243 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14244 this.el.on("mouseout", this.handleMouseOut, this);
14246 this.fireEvent("mousedown", this);
14247 this.fireEvent("click", this);
14249 this.timer = this.click.defer(this.delay || this.interval, this);
14253 click : function(){
14254 this.fireEvent("click", this);
14255 this.timer = this.click.defer(this.getInterval(), this);
14259 getInterval: function(){
14260 if(!this.accelerate){
14261 return this.interval;
14263 var pressTime = this.mousedownTime.getElapsed();
14264 if(pressTime < 500){
14266 }else if(pressTime < 1700){
14268 }else if(pressTime < 2600){
14270 }else if(pressTime < 3500){
14272 }else if(pressTime < 4400){
14274 }else if(pressTime < 5300){
14276 }else if(pressTime < 6200){
14284 handleMouseOut : function(){
14285 clearTimeout(this.timer);
14286 if(this.pressClass){
14287 this.el.removeClass(this.pressClass);
14289 this.el.on("mouseover", this.handleMouseReturn, this);
14293 handleMouseReturn : function(){
14294 this.el.un("mouseover", this.handleMouseReturn);
14295 if(this.pressClass){
14296 this.el.addClass(this.pressClass);
14302 handleMouseUp : function(){
14303 clearTimeout(this.timer);
14304 this.el.un("mouseover", this.handleMouseReturn);
14305 this.el.un("mouseout", this.handleMouseOut);
14306 Roo.get(document).un("mouseup", this.handleMouseUp);
14307 this.el.removeClass(this.pressClass);
14308 this.fireEvent("mouseup", this);
14312 * Ext JS Library 1.1.1
14313 * Copyright(c) 2006-2007, Ext JS, LLC.
14315 * Originally Released Under LGPL - original licence link has changed is not relivant.
14318 * <script type="text/javascript">
14323 * @class Roo.KeyNav
14324 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14325 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14326 * way to implement custom navigation schemes for any UI component.</p>
14327 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14328 * pageUp, pageDown, del, home, end. Usage:</p>
14330 var nav = new Roo.KeyNav("my-element", {
14331 "left" : function(e){
14332 this.moveLeft(e.ctrlKey);
14334 "right" : function(e){
14335 this.moveRight(e.ctrlKey);
14337 "enter" : function(e){
14344 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14345 * @param {Object} config The config
14347 Roo.KeyNav = function(el, config){
14348 this.el = Roo.get(el);
14349 Roo.apply(this, config);
14350 if(!this.disabled){
14351 this.disabled = true;
14356 Roo.KeyNav.prototype = {
14358 * @cfg {Boolean} disabled
14359 * True to disable this KeyNav instance (defaults to false)
14363 * @cfg {String} defaultEventAction
14364 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14365 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14366 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14368 defaultEventAction: "stopEvent",
14370 * @cfg {Boolean} forceKeyDown
14371 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14372 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14373 * handle keydown instead of keypress.
14375 forceKeyDown : false,
14378 prepareEvent : function(e){
14379 var k = e.getKey();
14380 var h = this.keyToHandler[k];
14381 //if(h && this[h]){
14382 // e.stopPropagation();
14384 if(Roo.isSafari && h && k >= 37 && k <= 40){
14390 relay : function(e){
14391 var k = e.getKey();
14392 var h = this.keyToHandler[k];
14394 if(this.doRelay(e, this[h], h) !== true){
14395 e[this.defaultEventAction]();
14401 doRelay : function(e, h, hname){
14402 return h.call(this.scope || this, e);
14405 // possible handlers
14419 // quick lookup hash
14436 * Enable this KeyNav
14438 enable: function(){
14440 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14441 // the EventObject will normalize Safari automatically
14442 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14443 this.el.on("keydown", this.relay, this);
14445 this.el.on("keydown", this.prepareEvent, this);
14446 this.el.on("keypress", this.relay, this);
14448 this.disabled = false;
14453 * Disable this KeyNav
14455 disable: function(){
14456 if(!this.disabled){
14457 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14458 this.el.un("keydown", this.relay);
14460 this.el.un("keydown", this.prepareEvent);
14461 this.el.un("keypress", this.relay);
14463 this.disabled = true;
14468 * Ext JS Library 1.1.1
14469 * Copyright(c) 2006-2007, Ext JS, LLC.
14471 * Originally Released Under LGPL - original licence link has changed is not relivant.
14474 * <script type="text/javascript">
14479 * @class Roo.KeyMap
14480 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14481 * The constructor accepts the same config object as defined by {@link #addBinding}.
14482 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14483 * combination it will call the function with this signature (if the match is a multi-key
14484 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14485 * A KeyMap can also handle a string representation of keys.<br />
14488 // map one key by key code
14489 var map = new Roo.KeyMap("my-element", {
14490 key: 13, // or Roo.EventObject.ENTER
14495 // map multiple keys to one action by string
14496 var map = new Roo.KeyMap("my-element", {
14502 // map multiple keys to multiple actions by strings and array of codes
14503 var map = new Roo.KeyMap("my-element", [
14506 fn: function(){ alert("Return was pressed"); }
14509 fn: function(){ alert('a, b or c was pressed'); }
14514 fn: function(){ alert('Control + shift + tab was pressed.'); }
14518 * <b>Note: A KeyMap starts enabled</b>
14520 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14521 * @param {Object} config The config (see {@link #addBinding})
14522 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14524 Roo.KeyMap = function(el, config, eventName){
14525 this.el = Roo.get(el);
14526 this.eventName = eventName || "keydown";
14527 this.bindings = [];
14529 this.addBinding(config);
14534 Roo.KeyMap.prototype = {
14536 * True to stop the event from bubbling and prevent the default browser action if the
14537 * key was handled by the KeyMap (defaults to false)
14543 * Add a new binding to this KeyMap. The following config object properties are supported:
14545 Property Type Description
14546 ---------- --------------- ----------------------------------------------------------------------
14547 key String/Array A single keycode or an array of keycodes to handle
14548 shift Boolean True to handle key only when shift is pressed (defaults to false)
14549 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14550 alt Boolean True to handle key only when alt is pressed (defaults to false)
14551 fn Function The function to call when KeyMap finds the expected key combination
14552 scope Object The scope of the callback function
14558 var map = new Roo.KeyMap(document, {
14559 key: Roo.EventObject.ENTER,
14564 //Add a new binding to the existing KeyMap later
14572 * @param {Object/Array} config A single KeyMap config or an array of configs
14574 addBinding : function(config){
14575 if(config instanceof Array){
14576 for(var i = 0, len = config.length; i < len; i++){
14577 this.addBinding(config[i]);
14581 var keyCode = config.key,
14582 shift = config.shift,
14583 ctrl = config.ctrl,
14586 scope = config.scope;
14587 if(typeof keyCode == "string"){
14589 var keyString = keyCode.toUpperCase();
14590 for(var j = 0, len = keyString.length; j < len; j++){
14591 ks.push(keyString.charCodeAt(j));
14595 var keyArray = keyCode instanceof Array;
14596 var handler = function(e){
14597 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14598 var k = e.getKey();
14600 for(var i = 0, len = keyCode.length; i < len; i++){
14601 if(keyCode[i] == k){
14602 if(this.stopEvent){
14605 fn.call(scope || window, k, e);
14611 if(this.stopEvent){
14614 fn.call(scope || window, k, e);
14619 this.bindings.push(handler);
14623 * Shorthand for adding a single key listener
14624 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14625 * following options:
14626 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14627 * @param {Function} fn The function to call
14628 * @param {Object} scope (optional) The scope of the function
14630 on : function(key, fn, scope){
14631 var keyCode, shift, ctrl, alt;
14632 if(typeof key == "object" && !(key instanceof Array)){
14651 handleKeyDown : function(e){
14652 if(this.enabled){ //just in case
14653 var b = this.bindings;
14654 for(var i = 0, len = b.length; i < len; i++){
14655 b[i].call(this, e);
14661 * Returns true if this KeyMap is enabled
14662 * @return {Boolean}
14664 isEnabled : function(){
14665 return this.enabled;
14669 * Enables this KeyMap
14671 enable: function(){
14673 this.el.on(this.eventName, this.handleKeyDown, this);
14674 this.enabled = true;
14679 * Disable this KeyMap
14681 disable: function(){
14683 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14684 this.enabled = false;
14689 * Ext JS Library 1.1.1
14690 * Copyright(c) 2006-2007, Ext JS, LLC.
14692 * Originally Released Under LGPL - original licence link has changed is not relivant.
14695 * <script type="text/javascript">
14700 * @class Roo.util.TextMetrics
14701 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14702 * wide, in pixels, a given block of text will be.
14705 Roo.util.TextMetrics = function(){
14709 * Measures the size of the specified text
14710 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14711 * that can affect the size of the rendered text
14712 * @param {String} text The text to measure
14713 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14714 * in order to accurately measure the text height
14715 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14717 measure : function(el, text, fixedWidth){
14719 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14722 shared.setFixedWidth(fixedWidth || 'auto');
14723 return shared.getSize(text);
14727 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14728 * the overhead of multiple calls to initialize the style properties on each measurement.
14729 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14730 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14731 * in order to accurately measure the text height
14732 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14734 createInstance : function(el, fixedWidth){
14735 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14742 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14743 var ml = new Roo.Element(document.createElement('div'));
14744 document.body.appendChild(ml.dom);
14745 ml.position('absolute');
14746 ml.setLeftTop(-1000, -1000);
14750 ml.setWidth(fixedWidth);
14755 * Returns the size of the specified text based on the internal element's style and width properties
14756 * @memberOf Roo.util.TextMetrics.Instance#
14757 * @param {String} text The text to measure
14758 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14760 getSize : function(text){
14762 var s = ml.getSize();
14768 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14769 * that can affect the size of the rendered text
14770 * @memberOf Roo.util.TextMetrics.Instance#
14771 * @param {String/HTMLElement} el The element, dom node or id
14773 bind : function(el){
14775 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14780 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14781 * to set a fixed width in order to accurately measure the text height.
14782 * @memberOf Roo.util.TextMetrics.Instance#
14783 * @param {Number} width The width to set on the element
14785 setFixedWidth : function(width){
14786 ml.setWidth(width);
14790 * Returns the measured width of the specified text
14791 * @memberOf Roo.util.TextMetrics.Instance#
14792 * @param {String} text The text to measure
14793 * @return {Number} width The width in pixels
14795 getWidth : function(text){
14796 ml.dom.style.width = 'auto';
14797 return this.getSize(text).width;
14801 * Returns the measured height of the specified text. For multiline text, be sure to call
14802 * {@link #setFixedWidth} if necessary.
14803 * @memberOf Roo.util.TextMetrics.Instance#
14804 * @param {String} text The text to measure
14805 * @return {Number} height The height in pixels
14807 getHeight : function(text){
14808 return this.getSize(text).height;
14812 instance.bind(bindTo);
14817 // backwards compat
14818 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14820 * Ext JS Library 1.1.1
14821 * Copyright(c) 2006-2007, Ext JS, LLC.
14823 * Originally Released Under LGPL - original licence link has changed is not relivant.
14826 * <script type="text/javascript">
14830 * @class Roo.state.Provider
14831 * Abstract base class for state provider implementations. This class provides methods
14832 * for encoding and decoding <b>typed</b> variables including dates and defines the
14833 * Provider interface.
14835 Roo.state.Provider = function(){
14837 * @event statechange
14838 * Fires when a state change occurs.
14839 * @param {Provider} this This state provider
14840 * @param {String} key The state key which was changed
14841 * @param {String} value The encoded value for the state
14844 "statechange": true
14847 Roo.state.Provider.superclass.constructor.call(this);
14849 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14851 * Returns the current value for a key
14852 * @param {String} name The key name
14853 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14854 * @return {Mixed} The state data
14856 get : function(name, defaultValue){
14857 return typeof this.state[name] == "undefined" ?
14858 defaultValue : this.state[name];
14862 * Clears a value from the state
14863 * @param {String} name The key name
14865 clear : function(name){
14866 delete this.state[name];
14867 this.fireEvent("statechange", this, name, null);
14871 * Sets the value for a key
14872 * @param {String} name The key name
14873 * @param {Mixed} value The value to set
14875 set : function(name, value){
14876 this.state[name] = value;
14877 this.fireEvent("statechange", this, name, value);
14881 * Decodes a string previously encoded with {@link #encodeValue}.
14882 * @param {String} value The value to decode
14883 * @return {Mixed} The decoded value
14885 decodeValue : function(cookie){
14886 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14887 var matches = re.exec(unescape(cookie));
14888 if(!matches || !matches[1]) {
14889 return; // non state cookie
14891 var type = matches[1];
14892 var v = matches[2];
14895 return parseFloat(v);
14897 return new Date(Date.parse(v));
14902 var values = v.split("^");
14903 for(var i = 0, len = values.length; i < len; i++){
14904 all.push(this.decodeValue(values[i]));
14909 var values = v.split("^");
14910 for(var i = 0, len = values.length; i < len; i++){
14911 var kv = values[i].split("=");
14912 all[kv[0]] = this.decodeValue(kv[1]);
14921 * Encodes a value including type information. Decode with {@link #decodeValue}.
14922 * @param {Mixed} value The value to encode
14923 * @return {String} The encoded value
14925 encodeValue : function(v){
14927 if(typeof v == "number"){
14929 }else if(typeof v == "boolean"){
14930 enc = "b:" + (v ? "1" : "0");
14931 }else if(v instanceof Date){
14932 enc = "d:" + v.toGMTString();
14933 }else if(v instanceof Array){
14935 for(var i = 0, len = v.length; i < len; i++){
14936 flat += this.encodeValue(v[i]);
14942 }else if(typeof v == "object"){
14945 if(typeof v[key] != "function"){
14946 flat += key + "=" + this.encodeValue(v[key]) + "^";
14949 enc = "o:" + flat.substring(0, flat.length-1);
14953 return escape(enc);
14959 * Ext JS Library 1.1.1
14960 * Copyright(c) 2006-2007, Ext JS, LLC.
14962 * Originally Released Under LGPL - original licence link has changed is not relivant.
14965 * <script type="text/javascript">
14968 * @class Roo.state.Manager
14969 * This is the global state manager. By default all components that are "state aware" check this class
14970 * for state information if you don't pass them a custom state provider. In order for this class
14971 * to be useful, it must be initialized with a provider when your application initializes.
14973 // in your initialization function
14975 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14977 // supposed you have a {@link Roo.BorderLayout}
14978 var layout = new Roo.BorderLayout(...);
14979 layout.restoreState();
14980 // or a {Roo.BasicDialog}
14981 var dialog = new Roo.BasicDialog(...);
14982 dialog.restoreState();
14986 Roo.state.Manager = function(){
14987 var provider = new Roo.state.Provider();
14991 * Configures the default state provider for your application
14992 * @param {Provider} stateProvider The state provider to set
14994 setProvider : function(stateProvider){
14995 provider = stateProvider;
14999 * Returns the current value for a key
15000 * @param {String} name The key name
15001 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15002 * @return {Mixed} The state data
15004 get : function(key, defaultValue){
15005 return provider.get(key, defaultValue);
15009 * Sets the value for a key
15010 * @param {String} name The key name
15011 * @param {Mixed} value The state data
15013 set : function(key, value){
15014 provider.set(key, value);
15018 * Clears a value from the state
15019 * @param {String} name The key name
15021 clear : function(key){
15022 provider.clear(key);
15026 * Gets the currently configured state provider
15027 * @return {Provider} The state provider
15029 getProvider : function(){
15036 * Ext JS Library 1.1.1
15037 * Copyright(c) 2006-2007, Ext JS, LLC.
15039 * Originally Released Under LGPL - original licence link has changed is not relivant.
15042 * <script type="text/javascript">
15045 * @class Roo.state.CookieProvider
15046 * @extends Roo.state.Provider
15047 * The default Provider implementation which saves state via cookies.
15050 var cp = new Roo.state.CookieProvider({
15052 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15053 domain: "roojs.com"
15055 Roo.state.Manager.setProvider(cp);
15057 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15058 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15059 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
15060 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15061 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15062 * domain the page is running on including the 'www' like 'www.roojs.com')
15063 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15065 * Create a new CookieProvider
15066 * @param {Object} config The configuration object
15068 Roo.state.CookieProvider = function(config){
15069 Roo.state.CookieProvider.superclass.constructor.call(this);
15071 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15072 this.domain = null;
15073 this.secure = false;
15074 Roo.apply(this, config);
15075 this.state = this.readCookies();
15078 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15080 set : function(name, value){
15081 if(typeof value == "undefined" || value === null){
15085 this.setCookie(name, value);
15086 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15090 clear : function(name){
15091 this.clearCookie(name);
15092 Roo.state.CookieProvider.superclass.clear.call(this, name);
15096 readCookies : function(){
15098 var c = document.cookie + ";";
15099 var re = /\s?(.*?)=(.*?);/g;
15101 while((matches = re.exec(c)) != null){
15102 var name = matches[1];
15103 var value = matches[2];
15104 if(name && name.substring(0,3) == "ys-"){
15105 cookies[name.substr(3)] = this.decodeValue(value);
15112 setCookie : function(name, value){
15113 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15114 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15115 ((this.path == null) ? "" : ("; path=" + this.path)) +
15116 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15117 ((this.secure == true) ? "; secure" : "");
15121 clearCookie : function(name){
15122 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15123 ((this.path == null) ? "" : ("; path=" + this.path)) +
15124 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15125 ((this.secure == true) ? "; secure" : "");
15129 * Ext JS Library 1.1.1
15130 * Copyright(c) 2006-2007, Ext JS, LLC.
15132 * Originally Released Under LGPL - original licence link has changed is not relivant.
15135 * <script type="text/javascript">
15140 * @class Roo.ComponentMgr
15141 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15144 Roo.ComponentMgr = function(){
15145 var all = new Roo.util.MixedCollection();
15149 * Registers a component.
15150 * @param {Roo.Component} c The component
15152 register : function(c){
15157 * Unregisters a component.
15158 * @param {Roo.Component} c The component
15160 unregister : function(c){
15165 * Returns a component by id
15166 * @param {String} id The component id
15168 get : function(id){
15169 return all.get(id);
15173 * Registers a function that will be called when a specified component is added to ComponentMgr
15174 * @param {String} id The component id
15175 * @param {Funtction} fn The callback function
15176 * @param {Object} scope The scope of the callback
15178 onAvailable : function(id, fn, scope){
15179 all.on("add", function(index, o){
15181 fn.call(scope || o, o);
15182 all.un("add", fn, scope);
15189 * Ext JS Library 1.1.1
15190 * Copyright(c) 2006-2007, Ext JS, LLC.
15192 * Originally Released Under LGPL - original licence link has changed is not relivant.
15195 * <script type="text/javascript">
15199 * @class Roo.Component
15200 * @extends Roo.util.Observable
15201 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15202 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15203 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15204 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15205 * All visual components (widgets) that require rendering into a layout should subclass Component.
15207 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15208 * 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
15209 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15211 Roo.Component = function(config){
15212 config = config || {};
15213 if(config.tagName || config.dom || typeof config == "string"){ // element object
15214 config = {el: config, id: config.id || config};
15216 this.initialConfig = config;
15218 Roo.apply(this, config);
15222 * Fires after the component is disabled.
15223 * @param {Roo.Component} this
15228 * Fires after the component is enabled.
15229 * @param {Roo.Component} this
15233 * @event beforeshow
15234 * Fires before the component is shown. Return false to stop the show.
15235 * @param {Roo.Component} this
15240 * Fires after the component is shown.
15241 * @param {Roo.Component} this
15245 * @event beforehide
15246 * Fires before the component is hidden. Return false to stop the hide.
15247 * @param {Roo.Component} this
15252 * Fires after the component is hidden.
15253 * @param {Roo.Component} this
15257 * @event beforerender
15258 * Fires before the component is rendered. Return false to stop the render.
15259 * @param {Roo.Component} this
15261 beforerender : true,
15264 * Fires after the component is rendered.
15265 * @param {Roo.Component} this
15269 * @event beforedestroy
15270 * Fires before the component is destroyed. Return false to stop the destroy.
15271 * @param {Roo.Component} this
15273 beforedestroy : true,
15276 * Fires after the component is destroyed.
15277 * @param {Roo.Component} this
15282 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15284 Roo.ComponentMgr.register(this);
15285 Roo.Component.superclass.constructor.call(this);
15286 this.initComponent();
15287 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15288 this.render(this.renderTo);
15289 delete this.renderTo;
15294 Roo.Component.AUTO_ID = 1000;
15296 Roo.extend(Roo.Component, Roo.util.Observable, {
15298 * @scope Roo.Component.prototype
15300 * true if this component is hidden. Read-only.
15305 * true if this component is disabled. Read-only.
15310 * true if this component has been rendered. Read-only.
15314 /** @cfg {String} disableClass
15315 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15317 disabledClass : "x-item-disabled",
15318 /** @cfg {Boolean} allowDomMove
15319 * Whether the component can move the Dom node when rendering (defaults to true).
15321 allowDomMove : true,
15322 /** @cfg {String} hideMode (display|visibility)
15323 * How this component should hidden. Supported values are
15324 * "visibility" (css visibility), "offsets" (negative offset position) and
15325 * "display" (css display) - defaults to "display".
15327 hideMode: 'display',
15330 ctype : "Roo.Component",
15333 * @cfg {String} actionMode
15334 * which property holds the element that used for hide() / show() / disable() / enable()
15340 getActionEl : function(){
15341 return this[this.actionMode];
15344 initComponent : Roo.emptyFn,
15346 * If this is a lazy rendering component, render it to its container element.
15347 * @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.
15349 render : function(container, position){
15350 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15351 if(!container && this.el){
15352 this.el = Roo.get(this.el);
15353 container = this.el.dom.parentNode;
15354 this.allowDomMove = false;
15356 this.container = Roo.get(container);
15357 this.rendered = true;
15358 if(position !== undefined){
15359 if(typeof position == 'number'){
15360 position = this.container.dom.childNodes[position];
15362 position = Roo.getDom(position);
15365 this.onRender(this.container, position || null);
15367 this.el.addClass(this.cls);
15371 this.el.applyStyles(this.style);
15374 this.fireEvent("render", this);
15375 this.afterRender(this.container);
15387 // default function is not really useful
15388 onRender : function(ct, position){
15390 this.el = Roo.get(this.el);
15391 if(this.allowDomMove !== false){
15392 ct.dom.insertBefore(this.el.dom, position);
15398 getAutoCreate : function(){
15399 var cfg = typeof this.autoCreate == "object" ?
15400 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15401 if(this.id && !cfg.id){
15408 afterRender : Roo.emptyFn,
15411 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15412 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15414 destroy : function(){
15415 if(this.fireEvent("beforedestroy", this) !== false){
15416 this.purgeListeners();
15417 this.beforeDestroy();
15419 this.el.removeAllListeners();
15421 if(this.actionMode == "container"){
15422 this.container.remove();
15426 Roo.ComponentMgr.unregister(this);
15427 this.fireEvent("destroy", this);
15432 beforeDestroy : function(){
15437 onDestroy : function(){
15442 * Returns the underlying {@link Roo.Element}.
15443 * @return {Roo.Element} The element
15445 getEl : function(){
15450 * Returns the id of this component.
15453 getId : function(){
15458 * Try to focus this component.
15459 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15460 * @return {Roo.Component} this
15462 focus : function(selectText){
15465 if(selectText === true){
15466 this.el.dom.select();
15481 * Disable this component.
15482 * @return {Roo.Component} this
15484 disable : function(){
15488 this.disabled = true;
15489 this.fireEvent("disable", this);
15494 onDisable : function(){
15495 this.getActionEl().addClass(this.disabledClass);
15496 this.el.dom.disabled = true;
15500 * Enable this component.
15501 * @return {Roo.Component} this
15503 enable : function(){
15507 this.disabled = false;
15508 this.fireEvent("enable", this);
15513 onEnable : function(){
15514 this.getActionEl().removeClass(this.disabledClass);
15515 this.el.dom.disabled = false;
15519 * Convenience function for setting disabled/enabled by boolean.
15520 * @param {Boolean} disabled
15522 setDisabled : function(disabled){
15523 this[disabled ? "disable" : "enable"]();
15527 * Show this component.
15528 * @return {Roo.Component} this
15531 if(this.fireEvent("beforeshow", this) !== false){
15532 this.hidden = false;
15536 this.fireEvent("show", this);
15542 onShow : function(){
15543 var ae = this.getActionEl();
15544 if(this.hideMode == 'visibility'){
15545 ae.dom.style.visibility = "visible";
15546 }else if(this.hideMode == 'offsets'){
15547 ae.removeClass('x-hidden');
15549 ae.dom.style.display = "";
15554 * Hide this component.
15555 * @return {Roo.Component} this
15558 if(this.fireEvent("beforehide", this) !== false){
15559 this.hidden = true;
15563 this.fireEvent("hide", this);
15569 onHide : function(){
15570 var ae = this.getActionEl();
15571 if(this.hideMode == 'visibility'){
15572 ae.dom.style.visibility = "hidden";
15573 }else if(this.hideMode == 'offsets'){
15574 ae.addClass('x-hidden');
15576 ae.dom.style.display = "none";
15581 * Convenience function to hide or show this component by boolean.
15582 * @param {Boolean} visible True to show, false to hide
15583 * @return {Roo.Component} this
15585 setVisible: function(visible){
15595 * Returns true if this component is visible.
15597 isVisible : function(){
15598 return this.getActionEl().isVisible();
15601 cloneConfig : function(overrides){
15602 overrides = overrides || {};
15603 var id = overrides.id || Roo.id();
15604 var cfg = Roo.applyIf(overrides, this.initialConfig);
15605 cfg.id = id; // prevent dup id
15606 return new this.constructor(cfg);
15610 * Ext JS Library 1.1.1
15611 * Copyright(c) 2006-2007, Ext JS, LLC.
15613 * Originally Released Under LGPL - original licence link has changed is not relivant.
15616 * <script type="text/javascript">
15620 * @class Roo.BoxComponent
15621 * @extends Roo.Component
15622 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15623 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15624 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15625 * layout containers.
15627 * @param {Roo.Element/String/Object} config The configuration options.
15629 Roo.BoxComponent = function(config){
15630 Roo.Component.call(this, config);
15634 * Fires after the component is resized.
15635 * @param {Roo.Component} this
15636 * @param {Number} adjWidth The box-adjusted width that was set
15637 * @param {Number} adjHeight The box-adjusted height that was set
15638 * @param {Number} rawWidth The width that was originally specified
15639 * @param {Number} rawHeight The height that was originally specified
15644 * Fires after the component is moved.
15645 * @param {Roo.Component} this
15646 * @param {Number} x The new x position
15647 * @param {Number} y The new y position
15653 Roo.extend(Roo.BoxComponent, Roo.Component, {
15654 // private, set in afterRender to signify that the component has been rendered
15656 // private, used to defer height settings to subclasses
15657 deferHeight: false,
15658 /** @cfg {Number} width
15659 * width (optional) size of component
15661 /** @cfg {Number} height
15662 * height (optional) size of component
15666 * Sets the width and height of the component. This method fires the resize event. This method can accept
15667 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15668 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15669 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15670 * @return {Roo.BoxComponent} this
15672 setSize : function(w, h){
15673 // support for standard size objects
15674 if(typeof w == 'object'){
15679 if(!this.boxReady){
15685 // prevent recalcs when not needed
15686 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15689 this.lastSize = {width: w, height: h};
15691 var adj = this.adjustSize(w, h);
15692 var aw = adj.width, ah = adj.height;
15693 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15694 var rz = this.getResizeEl();
15695 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15696 rz.setSize(aw, ah);
15697 }else if(!this.deferHeight && ah !== undefined){
15699 }else if(aw !== undefined){
15702 this.onResize(aw, ah, w, h);
15703 this.fireEvent('resize', this, aw, ah, w, h);
15709 * Gets the current size of the component's underlying element.
15710 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15712 getSize : function(){
15713 return this.el.getSize();
15717 * Gets the current XY position of the component's underlying element.
15718 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15719 * @return {Array} The XY position of the element (e.g., [100, 200])
15721 getPosition : function(local){
15722 if(local === true){
15723 return [this.el.getLeft(true), this.el.getTop(true)];
15725 return this.xy || this.el.getXY();
15729 * Gets the current box measurements of the component's underlying element.
15730 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15731 * @returns {Object} box An object in the format {x, y, width, height}
15733 getBox : function(local){
15734 var s = this.el.getSize();
15736 s.x = this.el.getLeft(true);
15737 s.y = this.el.getTop(true);
15739 var xy = this.xy || this.el.getXY();
15747 * Sets the current box measurements of the component's underlying element.
15748 * @param {Object} box An object in the format {x, y, width, height}
15749 * @returns {Roo.BoxComponent} this
15751 updateBox : function(box){
15752 this.setSize(box.width, box.height);
15753 this.setPagePosition(box.x, box.y);
15758 getResizeEl : function(){
15759 return this.resizeEl || this.el;
15763 getPositionEl : function(){
15764 return this.positionEl || this.el;
15768 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15769 * This method fires the move event.
15770 * @param {Number} left The new left
15771 * @param {Number} top The new top
15772 * @returns {Roo.BoxComponent} this
15774 setPosition : function(x, y){
15777 if(!this.boxReady){
15780 var adj = this.adjustPosition(x, y);
15781 var ax = adj.x, ay = adj.y;
15783 var el = this.getPositionEl();
15784 if(ax !== undefined || ay !== undefined){
15785 if(ax !== undefined && ay !== undefined){
15786 el.setLeftTop(ax, ay);
15787 }else if(ax !== undefined){
15789 }else if(ay !== undefined){
15792 this.onPosition(ax, ay);
15793 this.fireEvent('move', this, ax, ay);
15799 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15800 * This method fires the move event.
15801 * @param {Number} x The new x position
15802 * @param {Number} y The new y position
15803 * @returns {Roo.BoxComponent} this
15805 setPagePosition : function(x, y){
15808 if(!this.boxReady){
15811 if(x === undefined || y === undefined){ // cannot translate undefined points
15814 var p = this.el.translatePoints(x, y);
15815 this.setPosition(p.left, p.top);
15820 onRender : function(ct, position){
15821 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15823 this.resizeEl = Roo.get(this.resizeEl);
15825 if(this.positionEl){
15826 this.positionEl = Roo.get(this.positionEl);
15831 afterRender : function(){
15832 Roo.BoxComponent.superclass.afterRender.call(this);
15833 this.boxReady = true;
15834 this.setSize(this.width, this.height);
15835 if(this.x || this.y){
15836 this.setPosition(this.x, this.y);
15838 if(this.pageX || this.pageY){
15839 this.setPagePosition(this.pageX, this.pageY);
15844 * Force the component's size to recalculate based on the underlying element's current height and width.
15845 * @returns {Roo.BoxComponent} this
15847 syncSize : function(){
15848 delete this.lastSize;
15849 this.setSize(this.el.getWidth(), this.el.getHeight());
15854 * Called after the component is resized, this method is empty by default but can be implemented by any
15855 * subclass that needs to perform custom logic after a resize occurs.
15856 * @param {Number} adjWidth The box-adjusted width that was set
15857 * @param {Number} adjHeight The box-adjusted height that was set
15858 * @param {Number} rawWidth The width that was originally specified
15859 * @param {Number} rawHeight The height that was originally specified
15861 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15866 * Called after the component is moved, this method is empty by default but can be implemented by any
15867 * subclass that needs to perform custom logic after a move occurs.
15868 * @param {Number} x The new x position
15869 * @param {Number} y The new y position
15871 onPosition : function(x, y){
15876 adjustSize : function(w, h){
15877 if(this.autoWidth){
15880 if(this.autoHeight){
15883 return {width : w, height: h};
15887 adjustPosition : function(x, y){
15888 return {x : x, y: y};
15891 * Original code for Roojs - LGPL
15892 * <script type="text/javascript">
15896 * @class Roo.XComponent
15897 * A delayed Element creator...
15898 * Or a way to group chunks of interface together.
15899 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15900 * used in conjunction with XComponent.build() it will create an instance of each element,
15901 * then call addxtype() to build the User interface.
15903 * Mypart.xyx = new Roo.XComponent({
15905 parent : 'Mypart.xyz', // empty == document.element.!!
15909 disabled : function() {}
15911 tree : function() { // return an tree of xtype declared components
15915 xtype : 'NestedLayoutPanel',
15922 * It can be used to build a big heiracy, with parent etc.
15923 * or you can just use this to render a single compoent to a dom element
15924 * MYPART.render(Roo.Element | String(id) | dom_element )
15931 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15932 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15934 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15936 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15937 * - if mulitple topModules exist, the last one is defined as the top module.
15941 * When the top level or multiple modules are to embedded into a existing HTML page,
15942 * the parent element can container '#id' of the element where the module will be drawn.
15946 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15947 * it relies more on a include mechanism, where sub modules are included into an outer page.
15948 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15950 * Bootstrap Roo Included elements
15952 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15953 * hence confusing the component builder as it thinks there are multiple top level elements.
15957 * @extends Roo.util.Observable
15959 * @param cfg {Object} configuration of component
15962 Roo.XComponent = function(cfg) {
15963 Roo.apply(this, cfg);
15967 * Fires when this the componnt is built
15968 * @param {Roo.XComponent} c the component
15973 this.region = this.region || 'center'; // default..
15974 Roo.XComponent.register(this);
15975 this.modules = false;
15976 this.el = false; // where the layout goes..
15980 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15983 * The created element (with Roo.factory())
15984 * @type {Roo.Layout}
15990 * for BC - use el in new code
15991 * @type {Roo.Layout}
15997 * for BC - use el in new code
15998 * @type {Roo.Layout}
16003 * @cfg {Function|boolean} disabled
16004 * If this module is disabled by some rule, return true from the funtion
16009 * @cfg {String} parent
16010 * Name of parent element which it get xtype added to..
16015 * @cfg {String} order
16016 * Used to set the order in which elements are created (usefull for multiple tabs)
16021 * @cfg {String} name
16022 * String to display while loading.
16026 * @cfg {String} region
16027 * Region to render component to (defaults to center)
16032 * @cfg {Array} items
16033 * A single item array - the first element is the root of the tree..
16034 * It's done this way to stay compatible with the Xtype system...
16040 * The method that retuns the tree of parts that make up this compoennt
16047 * render element to dom or tree
16048 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16051 render : function(el)
16055 var hp = this.parent ? 1 : 0;
16056 Roo.debug && Roo.log(this);
16058 var tree = this._tree ? this._tree() : this.tree();
16061 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16062 // if parent is a '#.....' string, then let's use that..
16063 var ename = this.parent.substr(1);
16064 this.parent = false;
16065 Roo.debug && Roo.log(ename);
16067 case 'bootstrap-body':
16068 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
16069 // this is the BorderLayout standard?
16070 this.parent = { el : true };
16073 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
16074 // need to insert stuff...
16076 el : new Roo.bootstrap.layout.Border({
16077 el : document.body,
16083 tabPosition: 'top',
16084 //resizeTabs: true,
16085 alwaysShowTabs: true,
16095 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16096 this.parent = { el : new Roo.bootstrap.Body() };
16097 Roo.debug && Roo.log("setting el to doc body");
16100 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16104 this.parent = { el : true};
16107 el = Roo.get(ename);
16108 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16109 this.parent = { el : true};
16116 if (!el && !this.parent) {
16117 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16122 Roo.debug && Roo.log("EL:");
16123 Roo.debug && Roo.log(el);
16124 Roo.debug && Roo.log("this.parent.el:");
16125 Roo.debug && Roo.log(this.parent.el);
16128 // altertive root elements ??? - we need a better way to indicate these.
16129 var is_alt = Roo.XComponent.is_alt ||
16130 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16131 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16132 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16136 if (!this.parent && is_alt) {
16137 //el = Roo.get(document.body);
16138 this.parent = { el : true };
16143 if (!this.parent) {
16145 Roo.debug && Roo.log("no parent - creating one");
16147 el = el ? Roo.get(el) : false;
16149 if (typeof(Roo.BorderLayout) == 'undefined' ) {
16152 el : new Roo.bootstrap.layout.Border({
16153 el: el || document.body,
16159 tabPosition: 'top',
16160 //resizeTabs: true,
16161 alwaysShowTabs: false,
16164 overflow: 'visible'
16170 // it's a top level one..
16172 el : new Roo.BorderLayout(el || document.body, {
16177 tabPosition: 'top',
16178 //resizeTabs: true,
16179 alwaysShowTabs: el && hp? false : true,
16180 hideTabs: el || !hp ? true : false,
16188 if (!this.parent.el) {
16189 // probably an old style ctor, which has been disabled.
16193 // The 'tree' method is '_tree now'
16195 tree.region = tree.region || this.region;
16196 var is_body = false;
16197 if (this.parent.el === true) {
16198 // bootstrap... - body..
16202 this.parent.el = Roo.factory(tree);
16206 this.el = this.parent.el.addxtype(tree, undefined, is_body);
16207 this.fireEvent('built', this);
16209 this.panel = this.el;
16210 this.layout = this.panel.layout;
16211 this.parentLayout = this.parent.layout || false;
16217 Roo.apply(Roo.XComponent, {
16219 * @property hideProgress
16220 * true to disable the building progress bar.. usefull on single page renders.
16223 hideProgress : false,
16225 * @property buildCompleted
16226 * True when the builder has completed building the interface.
16229 buildCompleted : false,
16232 * @property topModule
16233 * the upper most module - uses document.element as it's constructor.
16240 * @property modules
16241 * array of modules to be created by registration system.
16242 * @type {Array} of Roo.XComponent
16247 * @property elmodules
16248 * array of modules to be created by which use #ID
16249 * @type {Array} of Roo.XComponent
16256 * Is an alternative Root - normally used by bootstrap or other systems,
16257 * where the top element in the tree can wrap 'body'
16258 * @type {boolean} (default false)
16263 * @property build_from_html
16264 * Build elements from html - used by bootstrap HTML stuff
16265 * - this is cleared after build is completed
16266 * @type {boolean} (default false)
16269 build_from_html : false,
16271 * Register components to be built later.
16273 * This solves the following issues
16274 * - Building is not done on page load, but after an authentication process has occured.
16275 * - Interface elements are registered on page load
16276 * - Parent Interface elements may not be loaded before child, so this handles that..
16283 module : 'Pman.Tab.projectMgr',
16285 parent : 'Pman.layout',
16286 disabled : false, // or use a function..
16289 * * @param {Object} details about module
16291 register : function(obj) {
16293 Roo.XComponent.event.fireEvent('register', obj);
16294 switch(typeof(obj.disabled) ) {
16300 if ( obj.disabled() ) {
16306 if (obj.disabled) {
16312 this.modules.push(obj);
16316 * convert a string to an object..
16317 * eg. 'AAA.BBB' -> finds AAA.BBB
16321 toObject : function(str)
16323 if (!str || typeof(str) == 'object') {
16326 if (str.substring(0,1) == '#') {
16330 var ar = str.split('.');
16335 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16337 throw "Module not found : " + str;
16341 throw "Module not found : " + str;
16343 Roo.each(ar, function(e) {
16344 if (typeof(o[e]) == 'undefined') {
16345 throw "Module not found : " + str;
16356 * move modules into their correct place in the tree..
16359 preBuild : function ()
16362 Roo.each(this.modules , function (obj)
16364 Roo.XComponent.event.fireEvent('beforebuild', obj);
16366 var opar = obj.parent;
16368 obj.parent = this.toObject(opar);
16370 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16375 Roo.debug && Roo.log("GOT top level module");
16376 Roo.debug && Roo.log(obj);
16377 obj.modules = new Roo.util.MixedCollection(false,
16378 function(o) { return o.order + '' }
16380 this.topModule = obj;
16383 // parent is a string (usually a dom element name..)
16384 if (typeof(obj.parent) == 'string') {
16385 this.elmodules.push(obj);
16388 if (obj.parent.constructor != Roo.XComponent) {
16389 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16391 if (!obj.parent.modules) {
16392 obj.parent.modules = new Roo.util.MixedCollection(false,
16393 function(o) { return o.order + '' }
16396 if (obj.parent.disabled) {
16397 obj.disabled = true;
16399 obj.parent.modules.add(obj);
16404 * make a list of modules to build.
16405 * @return {Array} list of modules.
16408 buildOrder : function()
16411 var cmp = function(a,b) {
16412 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16414 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16415 throw "No top level modules to build";
16418 // make a flat list in order of modules to build.
16419 var mods = this.topModule ? [ this.topModule ] : [];
16422 // elmodules (is a list of DOM based modules )
16423 Roo.each(this.elmodules, function(e) {
16425 if (!this.topModule &&
16426 typeof(e.parent) == 'string' &&
16427 e.parent.substring(0,1) == '#' &&
16428 Roo.get(e.parent.substr(1))
16431 _this.topModule = e;
16437 // add modules to their parents..
16438 var addMod = function(m) {
16439 Roo.debug && Roo.log("build Order: add: " + m.name);
16442 if (m.modules && !m.disabled) {
16443 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16444 m.modules.keySort('ASC', cmp );
16445 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16447 m.modules.each(addMod);
16449 Roo.debug && Roo.log("build Order: no child modules");
16451 // not sure if this is used any more..
16453 m.finalize.name = m.name + " (clean up) ";
16454 mods.push(m.finalize);
16458 if (this.topModule && this.topModule.modules) {
16459 this.topModule.modules.keySort('ASC', cmp );
16460 this.topModule.modules.each(addMod);
16466 * Build the registered modules.
16467 * @param {Object} parent element.
16468 * @param {Function} optional method to call after module has been added.
16472 build : function(opts)
16475 if (typeof(opts) != 'undefined') {
16476 Roo.apply(this,opts);
16480 var mods = this.buildOrder();
16482 //this.allmods = mods;
16483 //Roo.debug && Roo.log(mods);
16485 if (!mods.length) { // should not happen
16486 throw "NO modules!!!";
16490 var msg = "Building Interface...";
16491 // flash it up as modal - so we store the mask!?
16492 if (!this.hideProgress && Roo.MessageBox) {
16493 Roo.MessageBox.show({ title: 'loading' });
16494 Roo.MessageBox.show({
16495 title: "Please wait...",
16504 var total = mods.length;
16507 var progressRun = function() {
16508 if (!mods.length) {
16509 Roo.debug && Roo.log('hide?');
16510 if (!this.hideProgress && Roo.MessageBox) {
16511 Roo.MessageBox.hide();
16513 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16515 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16521 var m = mods.shift();
16524 Roo.debug && Roo.log(m);
16525 // not sure if this is supported any more.. - modules that are are just function
16526 if (typeof(m) == 'function') {
16528 return progressRun.defer(10, _this);
16532 msg = "Building Interface " + (total - mods.length) +
16534 (m.name ? (' - ' + m.name) : '');
16535 Roo.debug && Roo.log(msg);
16536 if (!_this.hideProgress && Roo.MessageBox) {
16537 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16541 // is the module disabled?
16542 var disabled = (typeof(m.disabled) == 'function') ?
16543 m.disabled.call(m.module.disabled) : m.disabled;
16547 return progressRun(); // we do not update the display!
16555 // it's 10 on top level, and 1 on others??? why...
16556 return progressRun.defer(10, _this);
16559 progressRun.defer(1, _this);
16573 * wrapper for event.on - aliased later..
16574 * Typically use to register a event handler for register:
16576 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16585 Roo.XComponent.event = new Roo.util.Observable({
16589 * Fires when an Component is registered,
16590 * set the disable property on the Component to stop registration.
16591 * @param {Roo.XComponent} c the component being registerd.
16596 * @event beforebuild
16597 * Fires before each Component is built
16598 * can be used to apply permissions.
16599 * @param {Roo.XComponent} c the component being registerd.
16602 'beforebuild' : true,
16604 * @event buildcomplete
16605 * Fires on the top level element when all elements have been built
16606 * @param {Roo.XComponent} the top level component.
16608 'buildcomplete' : true
16613 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16616 * marked - a markdown parser
16617 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16618 * https://github.com/chjj/marked
16624 * Roo.Markdown - is a very crude wrapper around marked..
16628 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16630 * Note: move the sample code to the bottom of this
16631 * file before uncommenting it.
16636 Roo.Markdown.toHtml = function(text) {
16638 var c = new Roo.Markdown.marked.setOptions({
16639 renderer: new Roo.Markdown.marked.Renderer(),
16650 text = text.replace(/\\\n/g,' ');
16651 return Roo.Markdown.marked(text);
16656 // Wraps all "globals" so that the only thing
16657 // exposed is makeHtml().
16662 * Block-Level Grammar
16667 code: /^( {4}[^\n]+\n*)+/,
16669 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16670 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16672 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16673 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16674 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16675 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16676 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16678 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16682 block.bullet = /(?:[*+-]|\d+\.)/;
16683 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16684 block.item = replace(block.item, 'gm')
16685 (/bull/g, block.bullet)
16688 block.list = replace(block.list)
16689 (/bull/g, block.bullet)
16690 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16691 ('def', '\\n+(?=' + block.def.source + ')')
16694 block.blockquote = replace(block.blockquote)
16698 block._tag = '(?!(?:'
16699 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16700 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16701 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16703 block.html = replace(block.html)
16704 ('comment', /<!--[\s\S]*?-->/)
16705 ('closed', /<(tag)[\s\S]+?<\/\1>/)
16706 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16707 (/tag/g, block._tag)
16710 block.paragraph = replace(block.paragraph)
16712 ('heading', block.heading)
16713 ('lheading', block.lheading)
16714 ('blockquote', block.blockquote)
16715 ('tag', '<' + block._tag)
16720 * Normal Block Grammar
16723 block.normal = merge({}, block);
16726 * GFM Block Grammar
16729 block.gfm = merge({}, block.normal, {
16730 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16732 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16735 block.gfm.paragraph = replace(block.paragraph)
16737 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16738 + block.list.source.replace('\\1', '\\3') + '|')
16742 * GFM + Tables Block Grammar
16745 block.tables = merge({}, block.gfm, {
16746 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16747 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16754 function Lexer(options) {
16756 this.tokens.links = {};
16757 this.options = options || marked.defaults;
16758 this.rules = block.normal;
16760 if (this.options.gfm) {
16761 if (this.options.tables) {
16762 this.rules = block.tables;
16764 this.rules = block.gfm;
16770 * Expose Block Rules
16773 Lexer.rules = block;
16776 * Static Lex Method
16779 Lexer.lex = function(src, options) {
16780 var lexer = new Lexer(options);
16781 return lexer.lex(src);
16788 Lexer.prototype.lex = function(src) {
16790 .replace(/\r\n|\r/g, '\n')
16791 .replace(/\t/g, ' ')
16792 .replace(/\u00a0/g, ' ')
16793 .replace(/\u2424/g, '\n');
16795 return this.token(src, true);
16802 Lexer.prototype.token = function(src, top, bq) {
16803 var src = src.replace(/^ +$/gm, '')
16816 if (cap = this.rules.newline.exec(src)) {
16817 src = src.substring(cap[0].length);
16818 if (cap[0].length > 1) {
16826 if (cap = this.rules.code.exec(src)) {
16827 src = src.substring(cap[0].length);
16828 cap = cap[0].replace(/^ {4}/gm, '');
16831 text: !this.options.pedantic
16832 ? cap.replace(/\n+$/, '')
16839 if (cap = this.rules.fences.exec(src)) {
16840 src = src.substring(cap[0].length);
16850 if (cap = this.rules.heading.exec(src)) {
16851 src = src.substring(cap[0].length);
16854 depth: cap[1].length,
16860 // table no leading pipe (gfm)
16861 if (top && (cap = this.rules.nptable.exec(src))) {
16862 src = src.substring(cap[0].length);
16866 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16867 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16868 cells: cap[3].replace(/\n$/, '').split('\n')
16871 for (i = 0; i < item.align.length; i++) {
16872 if (/^ *-+: *$/.test(item.align[i])) {
16873 item.align[i] = 'right';
16874 } else if (/^ *:-+: *$/.test(item.align[i])) {
16875 item.align[i] = 'center';
16876 } else if (/^ *:-+ *$/.test(item.align[i])) {
16877 item.align[i] = 'left';
16879 item.align[i] = null;
16883 for (i = 0; i < item.cells.length; i++) {
16884 item.cells[i] = item.cells[i].split(/ *\| */);
16887 this.tokens.push(item);
16893 if (cap = this.rules.lheading.exec(src)) {
16894 src = src.substring(cap[0].length);
16897 depth: cap[2] === '=' ? 1 : 2,
16904 if (cap = this.rules.hr.exec(src)) {
16905 src = src.substring(cap[0].length);
16913 if (cap = this.rules.blockquote.exec(src)) {
16914 src = src.substring(cap[0].length);
16917 type: 'blockquote_start'
16920 cap = cap[0].replace(/^ *> ?/gm, '');
16922 // Pass `top` to keep the current
16923 // "toplevel" state. This is exactly
16924 // how markdown.pl works.
16925 this.token(cap, top, true);
16928 type: 'blockquote_end'
16935 if (cap = this.rules.list.exec(src)) {
16936 src = src.substring(cap[0].length);
16940 type: 'list_start',
16941 ordered: bull.length > 1
16944 // Get each top-level item.
16945 cap = cap[0].match(this.rules.item);
16951 for (; i < l; i++) {
16954 // Remove the list item's bullet
16955 // so it is seen as the next token.
16956 space = item.length;
16957 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16959 // Outdent whatever the
16960 // list item contains. Hacky.
16961 if (~item.indexOf('\n ')) {
16962 space -= item.length;
16963 item = !this.options.pedantic
16964 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16965 : item.replace(/^ {1,4}/gm, '');
16968 // Determine whether the next list item belongs here.
16969 // Backpedal if it does not belong in this list.
16970 if (this.options.smartLists && i !== l - 1) {
16971 b = block.bullet.exec(cap[i + 1])[0];
16972 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
16973 src = cap.slice(i + 1).join('\n') + src;
16978 // Determine whether item is loose or not.
16979 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
16980 // for discount behavior.
16981 loose = next || /\n\n(?!\s*$)/.test(item);
16983 next = item.charAt(item.length - 1) === '\n';
16984 if (!loose) { loose = next; }
16989 ? 'loose_item_start'
16990 : 'list_item_start'
16994 this.token(item, false, bq);
16997 type: 'list_item_end'
17009 if (cap = this.rules.html.exec(src)) {
17010 src = src.substring(cap[0].length);
17012 type: this.options.sanitize
17015 pre: !this.options.sanitizer
17016 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17023 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17024 src = src.substring(cap[0].length);
17025 this.tokens.links[cap[1].toLowerCase()] = {
17033 if (top && (cap = this.rules.table.exec(src))) {
17034 src = src.substring(cap[0].length);
17038 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17039 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17040 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17043 for (i = 0; i < item.align.length; i++) {
17044 if (/^ *-+: *$/.test(item.align[i])) {
17045 item.align[i] = 'right';
17046 } else if (/^ *:-+: *$/.test(item.align[i])) {
17047 item.align[i] = 'center';
17048 } else if (/^ *:-+ *$/.test(item.align[i])) {
17049 item.align[i] = 'left';
17051 item.align[i] = null;
17055 for (i = 0; i < item.cells.length; i++) {
17056 item.cells[i] = item.cells[i]
17057 .replace(/^ *\| *| *\| *$/g, '')
17061 this.tokens.push(item);
17066 // top-level paragraph
17067 if (top && (cap = this.rules.paragraph.exec(src))) {
17068 src = src.substring(cap[0].length);
17071 text: cap[1].charAt(cap[1].length - 1) === '\n'
17072 ? cap[1].slice(0, -1)
17079 if (cap = this.rules.text.exec(src)) {
17080 // Top-level should never reach here.
17081 src = src.substring(cap[0].length);
17091 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17095 return this.tokens;
17099 * Inline-Level Grammar
17103 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17104 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17106 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17107 link: /^!?\[(inside)\]\(href\)/,
17108 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17109 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17110 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17111 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17112 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17113 br: /^ {2,}\n(?!\s*$)/,
17115 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17118 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17119 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17121 inline.link = replace(inline.link)
17122 ('inside', inline._inside)
17123 ('href', inline._href)
17126 inline.reflink = replace(inline.reflink)
17127 ('inside', inline._inside)
17131 * Normal Inline Grammar
17134 inline.normal = merge({}, inline);
17137 * Pedantic Inline Grammar
17140 inline.pedantic = merge({}, inline.normal, {
17141 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17142 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17146 * GFM Inline Grammar
17149 inline.gfm = merge({}, inline.normal, {
17150 escape: replace(inline.escape)('])', '~|])')(),
17151 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17152 del: /^~~(?=\S)([\s\S]*?\S)~~/,
17153 text: replace(inline.text)
17155 ('|', '|https?://|')
17160 * GFM + Line Breaks Inline Grammar
17163 inline.breaks = merge({}, inline.gfm, {
17164 br: replace(inline.br)('{2,}', '*')(),
17165 text: replace(inline.gfm.text)('{2,}', '*')()
17169 * Inline Lexer & Compiler
17172 function InlineLexer(links, options) {
17173 this.options = options || marked.defaults;
17174 this.links = links;
17175 this.rules = inline.normal;
17176 this.renderer = this.options.renderer || new Renderer;
17177 this.renderer.options = this.options;
17181 Error('Tokens array requires a `links` property.');
17184 if (this.options.gfm) {
17185 if (this.options.breaks) {
17186 this.rules = inline.breaks;
17188 this.rules = inline.gfm;
17190 } else if (this.options.pedantic) {
17191 this.rules = inline.pedantic;
17196 * Expose Inline Rules
17199 InlineLexer.rules = inline;
17202 * Static Lexing/Compiling Method
17205 InlineLexer.output = function(src, links, options) {
17206 var inline = new InlineLexer(links, options);
17207 return inline.output(src);
17214 InlineLexer.prototype.output = function(src) {
17223 if (cap = this.rules.escape.exec(src)) {
17224 src = src.substring(cap[0].length);
17230 if (cap = this.rules.autolink.exec(src)) {
17231 src = src.substring(cap[0].length);
17232 if (cap[2] === '@') {
17233 text = cap[1].charAt(6) === ':'
17234 ? this.mangle(cap[1].substring(7))
17235 : this.mangle(cap[1]);
17236 href = this.mangle('mailto:') + text;
17238 text = escape(cap[1]);
17241 out += this.renderer.link(href, null, text);
17246 if (!this.inLink && (cap = this.rules.url.exec(src))) {
17247 src = src.substring(cap[0].length);
17248 text = escape(cap[1]);
17250 out += this.renderer.link(href, null, text);
17255 if (cap = this.rules.tag.exec(src)) {
17256 if (!this.inLink && /^<a /i.test(cap[0])) {
17257 this.inLink = true;
17258 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17259 this.inLink = false;
17261 src = src.substring(cap[0].length);
17262 out += this.options.sanitize
17263 ? this.options.sanitizer
17264 ? this.options.sanitizer(cap[0])
17271 if (cap = this.rules.link.exec(src)) {
17272 src = src.substring(cap[0].length);
17273 this.inLink = true;
17274 out += this.outputLink(cap, {
17278 this.inLink = false;
17283 if ((cap = this.rules.reflink.exec(src))
17284 || (cap = this.rules.nolink.exec(src))) {
17285 src = src.substring(cap[0].length);
17286 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17287 link = this.links[link.toLowerCase()];
17288 if (!link || !link.href) {
17289 out += cap[0].charAt(0);
17290 src = cap[0].substring(1) + src;
17293 this.inLink = true;
17294 out += this.outputLink(cap, link);
17295 this.inLink = false;
17300 if (cap = this.rules.strong.exec(src)) {
17301 src = src.substring(cap[0].length);
17302 out += this.renderer.strong(this.output(cap[2] || cap[1]));
17307 if (cap = this.rules.em.exec(src)) {
17308 src = src.substring(cap[0].length);
17309 out += this.renderer.em(this.output(cap[2] || cap[1]));
17314 if (cap = this.rules.code.exec(src)) {
17315 src = src.substring(cap[0].length);
17316 out += this.renderer.codespan(escape(cap[2], true));
17321 if (cap = this.rules.br.exec(src)) {
17322 src = src.substring(cap[0].length);
17323 out += this.renderer.br();
17328 if (cap = this.rules.del.exec(src)) {
17329 src = src.substring(cap[0].length);
17330 out += this.renderer.del(this.output(cap[1]));
17335 if (cap = this.rules.text.exec(src)) {
17336 src = src.substring(cap[0].length);
17337 out += this.renderer.text(escape(this.smartypants(cap[0])));
17343 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17354 InlineLexer.prototype.outputLink = function(cap, link) {
17355 var href = escape(link.href)
17356 , title = link.title ? escape(link.title) : null;
17358 return cap[0].charAt(0) !== '!'
17359 ? this.renderer.link(href, title, this.output(cap[1]))
17360 : this.renderer.image(href, title, escape(cap[1]));
17364 * Smartypants Transformations
17367 InlineLexer.prototype.smartypants = function(text) {
17368 if (!this.options.smartypants) { return text; }
17371 .replace(/---/g, '\u2014')
17373 .replace(/--/g, '\u2013')
17375 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17376 // closing singles & apostrophes
17377 .replace(/'/g, '\u2019')
17379 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17381 .replace(/"/g, '\u201d')
17383 .replace(/\.{3}/g, '\u2026');
17390 InlineLexer.prototype.mangle = function(text) {
17391 if (!this.options.mangle) { return text; }
17397 for (; i < l; i++) {
17398 ch = text.charCodeAt(i);
17399 if (Math.random() > 0.5) {
17400 ch = 'x' + ch.toString(16);
17402 out += '&#' + ch + ';';
17412 function Renderer(options) {
17413 this.options = options || {};
17416 Renderer.prototype.code = function(code, lang, escaped) {
17417 if (this.options.highlight) {
17418 var out = this.options.highlight(code, lang);
17419 if (out != null && out !== code) {
17424 // hack!!! - it's already escapeD?
17429 return '<pre><code>'
17430 + (escaped ? code : escape(code, true))
17431 + '\n</code></pre>';
17434 return '<pre><code class="'
17435 + this.options.langPrefix
17436 + escape(lang, true)
17438 + (escaped ? code : escape(code, true))
17439 + '\n</code></pre>\n';
17442 Renderer.prototype.blockquote = function(quote) {
17443 return '<blockquote>\n' + quote + '</blockquote>\n';
17446 Renderer.prototype.html = function(html) {
17450 Renderer.prototype.heading = function(text, level, raw) {
17454 + this.options.headerPrefix
17455 + raw.toLowerCase().replace(/[^\w]+/g, '-')
17463 Renderer.prototype.hr = function() {
17464 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17467 Renderer.prototype.list = function(body, ordered) {
17468 var type = ordered ? 'ol' : 'ul';
17469 return '<' + type + '>\n' + body + '</' + type + '>\n';
17472 Renderer.prototype.listitem = function(text) {
17473 return '<li>' + text + '</li>\n';
17476 Renderer.prototype.paragraph = function(text) {
17477 return '<p>' + text + '</p>\n';
17480 Renderer.prototype.table = function(header, body) {
17481 return '<table class="table table-striped">\n'
17491 Renderer.prototype.tablerow = function(content) {
17492 return '<tr>\n' + content + '</tr>\n';
17495 Renderer.prototype.tablecell = function(content, flags) {
17496 var type = flags.header ? 'th' : 'td';
17497 var tag = flags.align
17498 ? '<' + type + ' style="text-align:' + flags.align + '">'
17499 : '<' + type + '>';
17500 return tag + content + '</' + type + '>\n';
17503 // span level renderer
17504 Renderer.prototype.strong = function(text) {
17505 return '<strong>' + text + '</strong>';
17508 Renderer.prototype.em = function(text) {
17509 return '<em>' + text + '</em>';
17512 Renderer.prototype.codespan = function(text) {
17513 return '<code>' + text + '</code>';
17516 Renderer.prototype.br = function() {
17517 return this.options.xhtml ? '<br/>' : '<br>';
17520 Renderer.prototype.del = function(text) {
17521 return '<del>' + text + '</del>';
17524 Renderer.prototype.link = function(href, title, text) {
17525 if (this.options.sanitize) {
17527 var prot = decodeURIComponent(unescape(href))
17528 .replace(/[^\w:]/g, '')
17533 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17537 var out = '<a href="' + href + '"';
17539 out += ' title="' + title + '"';
17541 out += '>' + text + '</a>';
17545 Renderer.prototype.image = function(href, title, text) {
17546 var out = '<img src="' + href + '" alt="' + text + '"';
17548 out += ' title="' + title + '"';
17550 out += this.options.xhtml ? '/>' : '>';
17554 Renderer.prototype.text = function(text) {
17559 * Parsing & Compiling
17562 function Parser(options) {
17565 this.options = options || marked.defaults;
17566 this.options.renderer = this.options.renderer || new Renderer;
17567 this.renderer = this.options.renderer;
17568 this.renderer.options = this.options;
17572 * Static Parse Method
17575 Parser.parse = function(src, options, renderer) {
17576 var parser = new Parser(options, renderer);
17577 return parser.parse(src);
17584 Parser.prototype.parse = function(src) {
17585 this.inline = new InlineLexer(src.links, this.options, this.renderer);
17586 this.tokens = src.reverse();
17589 while (this.next()) {
17600 Parser.prototype.next = function() {
17601 return this.token = this.tokens.pop();
17605 * Preview Next Token
17608 Parser.prototype.peek = function() {
17609 return this.tokens[this.tokens.length - 1] || 0;
17613 * Parse Text Tokens
17616 Parser.prototype.parseText = function() {
17617 var body = this.token.text;
17619 while (this.peek().type === 'text') {
17620 body += '\n' + this.next().text;
17623 return this.inline.output(body);
17627 * Parse Current Token
17630 Parser.prototype.tok = function() {
17631 switch (this.token.type) {
17636 return this.renderer.hr();
17639 return this.renderer.heading(
17640 this.inline.output(this.token.text),
17645 return this.renderer.code(this.token.text,
17647 this.token.escaped);
17660 for (i = 0; i < this.token.header.length; i++) {
17661 flags = { header: true, align: this.token.align[i] };
17662 cell += this.renderer.tablecell(
17663 this.inline.output(this.token.header[i]),
17664 { header: true, align: this.token.align[i] }
17667 header += this.renderer.tablerow(cell);
17669 for (i = 0; i < this.token.cells.length; i++) {
17670 row = this.token.cells[i];
17673 for (j = 0; j < row.length; j++) {
17674 cell += this.renderer.tablecell(
17675 this.inline.output(row[j]),
17676 { header: false, align: this.token.align[j] }
17680 body += this.renderer.tablerow(cell);
17682 return this.renderer.table(header, body);
17684 case 'blockquote_start': {
17687 while (this.next().type !== 'blockquote_end') {
17688 body += this.tok();
17691 return this.renderer.blockquote(body);
17693 case 'list_start': {
17695 , ordered = this.token.ordered;
17697 while (this.next().type !== 'list_end') {
17698 body += this.tok();
17701 return this.renderer.list(body, ordered);
17703 case 'list_item_start': {
17706 while (this.next().type !== 'list_item_end') {
17707 body += this.token.type === 'text'
17712 return this.renderer.listitem(body);
17714 case 'loose_item_start': {
17717 while (this.next().type !== 'list_item_end') {
17718 body += this.tok();
17721 return this.renderer.listitem(body);
17724 var html = !this.token.pre && !this.options.pedantic
17725 ? this.inline.output(this.token.text)
17727 return this.renderer.html(html);
17729 case 'paragraph': {
17730 return this.renderer.paragraph(this.inline.output(this.token.text));
17733 return this.renderer.paragraph(this.parseText());
17742 function escape(html, encode) {
17744 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17745 .replace(/</g, '<')
17746 .replace(/>/g, '>')
17747 .replace(/"/g, '"')
17748 .replace(/'/g, ''');
17751 function unescape(html) {
17752 // explicitly match decimal, hex, and named HTML entities
17753 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17754 n = n.toLowerCase();
17755 if (n === 'colon') { return ':'; }
17756 if (n.charAt(0) === '#') {
17757 return n.charAt(1) === 'x'
17758 ? String.fromCharCode(parseInt(n.substring(2), 16))
17759 : String.fromCharCode(+n.substring(1));
17765 function replace(regex, opt) {
17766 regex = regex.source;
17768 return function self(name, val) {
17769 if (!name) { return new RegExp(regex, opt); }
17770 val = val.source || val;
17771 val = val.replace(/(^|[^\[])\^/g, '$1');
17772 regex = regex.replace(name, val);
17780 function merge(obj) {
17785 for (; i < arguments.length; i++) {
17786 target = arguments[i];
17787 for (key in target) {
17788 if (Object.prototype.hasOwnProperty.call(target, key)) {
17789 obj[key] = target[key];
17802 function marked(src, opt, callback) {
17803 if (callback || typeof opt === 'function') {
17809 opt = merge({}, marked.defaults, opt || {});
17811 var highlight = opt.highlight
17817 tokens = Lexer.lex(src, opt)
17819 return callback(e);
17822 pending = tokens.length;
17824 var done = function(err) {
17826 opt.highlight = highlight;
17827 return callback(err);
17833 out = Parser.parse(tokens, opt);
17838 opt.highlight = highlight;
17842 : callback(null, out);
17845 if (!highlight || highlight.length < 3) {
17849 delete opt.highlight;
17851 if (!pending) { return done(); }
17853 for (; i < tokens.length; i++) {
17855 if (token.type !== 'code') {
17856 return --pending || done();
17858 return highlight(token.text, token.lang, function(err, code) {
17859 if (err) { return done(err); }
17860 if (code == null || code === token.text) {
17861 return --pending || done();
17864 token.escaped = true;
17865 --pending || done();
17873 if (opt) { opt = merge({}, marked.defaults, opt); }
17874 return Parser.parse(Lexer.lex(src, opt), opt);
17876 e.message += '\nPlease report this to https://github.com/chjj/marked.';
17877 if ((opt || marked.defaults).silent) {
17878 return '<p>An error occured:</p><pre>'
17879 + escape(e.message + '', true)
17891 marked.setOptions = function(opt) {
17892 merge(marked.defaults, opt);
17896 marked.defaults = {
17907 langPrefix: 'lang-',
17908 smartypants: false,
17910 renderer: new Renderer,
17918 marked.Parser = Parser;
17919 marked.parser = Parser.parse;
17921 marked.Renderer = Renderer;
17923 marked.Lexer = Lexer;
17924 marked.lexer = Lexer.lex;
17926 marked.InlineLexer = InlineLexer;
17927 marked.inlineLexer = InlineLexer.output;
17929 marked.parse = marked;
17931 Roo.Markdown.marked = marked;
17935 * Ext JS Library 1.1.1
17936 * Copyright(c) 2006-2007, Ext JS, LLC.
17938 * Originally Released Under LGPL - original licence link has changed is not relivant.
17941 * <script type="text/javascript">
17947 * These classes are derivatives of the similarly named classes in the YUI Library.
17948 * The original license:
17949 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17950 * Code licensed under the BSD License:
17951 * http://developer.yahoo.net/yui/license.txt
17956 var Event=Roo.EventManager;
17957 var Dom=Roo.lib.Dom;
17960 * @class Roo.dd.DragDrop
17961 * @extends Roo.util.Observable
17962 * Defines the interface and base operation of items that that can be
17963 * dragged or can be drop targets. It was designed to be extended, overriding
17964 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17965 * Up to three html elements can be associated with a DragDrop instance:
17967 * <li>linked element: the element that is passed into the constructor.
17968 * This is the element which defines the boundaries for interaction with
17969 * other DragDrop objects.</li>
17970 * <li>handle element(s): The drag operation only occurs if the element that
17971 * was clicked matches a handle element. By default this is the linked
17972 * element, but there are times that you will want only a portion of the
17973 * linked element to initiate the drag operation, and the setHandleElId()
17974 * method provides a way to define this.</li>
17975 * <li>drag element: this represents the element that would be moved along
17976 * with the cursor during a drag operation. By default, this is the linked
17977 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
17978 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
17981 * This class should not be instantiated until the onload event to ensure that
17982 * the associated elements are available.
17983 * The following would define a DragDrop obj that would interact with any
17984 * other DragDrop obj in the "group1" group:
17986 * dd = new Roo.dd.DragDrop("div1", "group1");
17988 * Since none of the event handlers have been implemented, nothing would
17989 * actually happen if you were to run the code above. Normally you would
17990 * override this class or one of the default implementations, but you can
17991 * also override the methods you want on an instance of the class...
17993 * dd.onDragDrop = function(e, id) {
17994 * alert("dd was dropped on " + id);
17998 * @param {String} id of the element that is linked to this instance
17999 * @param {String} sGroup the group of related DragDrop objects
18000 * @param {object} config an object containing configurable attributes
18001 * Valid properties for DragDrop:
18002 * padding, isTarget, maintainOffset, primaryButtonOnly
18004 Roo.dd.DragDrop = function(id, sGroup, config) {
18006 this.init(id, sGroup, config);
18011 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18014 * The id of the element associated with this object. This is what we
18015 * refer to as the "linked element" because the size and position of
18016 * this element is used to determine when the drag and drop objects have
18024 * Configuration attributes passed into the constructor
18031 * The id of the element that will be dragged. By default this is same
18032 * as the linked element , but could be changed to another element. Ex:
18034 * @property dragElId
18041 * the id of the element that initiates the drag operation. By default
18042 * this is the linked element, but could be changed to be a child of this
18043 * element. This lets us do things like only starting the drag when the
18044 * header element within the linked html element is clicked.
18045 * @property handleElId
18052 * An associative array of HTML tags that will be ignored if clicked.
18053 * @property invalidHandleTypes
18054 * @type {string: string}
18056 invalidHandleTypes: null,
18059 * An associative array of ids for elements that will be ignored if clicked
18060 * @property invalidHandleIds
18061 * @type {string: string}
18063 invalidHandleIds: null,
18066 * An indexted array of css class names for elements that will be ignored
18068 * @property invalidHandleClasses
18071 invalidHandleClasses: null,
18074 * The linked element's absolute X position at the time the drag was
18076 * @property startPageX
18083 * The linked element's absolute X position at the time the drag was
18085 * @property startPageY
18092 * The group defines a logical collection of DragDrop objects that are
18093 * related. Instances only get events when interacting with other
18094 * DragDrop object in the same group. This lets us define multiple
18095 * groups using a single DragDrop subclass if we want.
18097 * @type {string: string}
18102 * Individual drag/drop instances can be locked. This will prevent
18103 * onmousedown start drag.
18111 * Lock this instance
18114 lock: function() { this.locked = true; },
18117 * Unlock this instace
18120 unlock: function() { this.locked = false; },
18123 * By default, all insances can be a drop target. This can be disabled by
18124 * setting isTarget to false.
18131 * The padding configured for this drag and drop object for calculating
18132 * the drop zone intersection with this object.
18139 * Cached reference to the linked element
18140 * @property _domRef
18146 * Internal typeof flag
18147 * @property __ygDragDrop
18150 __ygDragDrop: true,
18153 * Set to true when horizontal contraints are applied
18154 * @property constrainX
18161 * Set to true when vertical contraints are applied
18162 * @property constrainY
18169 * The left constraint
18177 * The right constraint
18185 * The up constraint
18194 * The down constraint
18202 * Maintain offsets when we resetconstraints. Set to true when you want
18203 * the position of the element relative to its parent to stay the same
18204 * when the page changes
18206 * @property maintainOffset
18209 maintainOffset: false,
18212 * Array of pixel locations the element will snap to if we specified a
18213 * horizontal graduation/interval. This array is generated automatically
18214 * when you define a tick interval.
18221 * Array of pixel locations the element will snap to if we specified a
18222 * vertical graduation/interval. This array is generated automatically
18223 * when you define a tick interval.
18230 * By default the drag and drop instance will only respond to the primary
18231 * button click (left button for a right-handed mouse). Set to true to
18232 * allow drag and drop to start with any mouse click that is propogated
18234 * @property primaryButtonOnly
18237 primaryButtonOnly: true,
18240 * The availabe property is false until the linked dom element is accessible.
18241 * @property available
18247 * By default, drags can only be initiated if the mousedown occurs in the
18248 * region the linked element is. This is done in part to work around a
18249 * bug in some browsers that mis-report the mousedown if the previous
18250 * mouseup happened outside of the window. This property is set to true
18251 * if outer handles are defined.
18253 * @property hasOuterHandles
18257 hasOuterHandles: false,
18260 * Code that executes immediately before the startDrag event
18261 * @method b4StartDrag
18264 b4StartDrag: function(x, y) { },
18267 * Abstract method called after a drag/drop object is clicked
18268 * and the drag or mousedown time thresholds have beeen met.
18269 * @method startDrag
18270 * @param {int} X click location
18271 * @param {int} Y click location
18273 startDrag: function(x, y) { /* override this */ },
18276 * Code that executes immediately before the onDrag event
18280 b4Drag: function(e) { },
18283 * Abstract method called during the onMouseMove event while dragging an
18286 * @param {Event} e the mousemove event
18288 onDrag: function(e) { /* override this */ },
18291 * Abstract method called when this element fist begins hovering over
18292 * another DragDrop obj
18293 * @method onDragEnter
18294 * @param {Event} e the mousemove event
18295 * @param {String|DragDrop[]} id In POINT mode, the element
18296 * id this is hovering over. In INTERSECT mode, an array of one or more
18297 * dragdrop items being hovered over.
18299 onDragEnter: function(e, id) { /* override this */ },
18302 * Code that executes immediately before the onDragOver event
18303 * @method b4DragOver
18306 b4DragOver: function(e) { },
18309 * Abstract method called when this element is hovering over another
18311 * @method onDragOver
18312 * @param {Event} e the mousemove event
18313 * @param {String|DragDrop[]} id In POINT mode, the element
18314 * id this is hovering over. In INTERSECT mode, an array of dd items
18315 * being hovered over.
18317 onDragOver: function(e, id) { /* override this */ },
18320 * Code that executes immediately before the onDragOut event
18321 * @method b4DragOut
18324 b4DragOut: function(e) { },
18327 * Abstract method called when we are no longer hovering over an element
18328 * @method onDragOut
18329 * @param {Event} e the mousemove event
18330 * @param {String|DragDrop[]} id In POINT mode, the element
18331 * id this was hovering over. In INTERSECT mode, an array of dd items
18332 * that the mouse is no longer over.
18334 onDragOut: function(e, id) { /* override this */ },
18337 * Code that executes immediately before the onDragDrop event
18338 * @method b4DragDrop
18341 b4DragDrop: function(e) { },
18344 * Abstract method called when this item is dropped on another DragDrop
18346 * @method onDragDrop
18347 * @param {Event} e the mouseup event
18348 * @param {String|DragDrop[]} id In POINT mode, the element
18349 * id this was dropped on. In INTERSECT mode, an array of dd items this
18352 onDragDrop: function(e, id) { /* override this */ },
18355 * Abstract method called when this item is dropped on an area with no
18357 * @method onInvalidDrop
18358 * @param {Event} e the mouseup event
18360 onInvalidDrop: function(e) { /* override this */ },
18363 * Code that executes immediately before the endDrag event
18364 * @method b4EndDrag
18367 b4EndDrag: function(e) { },
18370 * Fired when we are done dragging the object
18372 * @param {Event} e the mouseup event
18374 endDrag: function(e) { /* override this */ },
18377 * Code executed immediately before the onMouseDown event
18378 * @method b4MouseDown
18379 * @param {Event} e the mousedown event
18382 b4MouseDown: function(e) { },
18385 * Event handler that fires when a drag/drop obj gets a mousedown
18386 * @method onMouseDown
18387 * @param {Event} e the mousedown event
18389 onMouseDown: function(e) { /* override this */ },
18392 * Event handler that fires when a drag/drop obj gets a mouseup
18393 * @method onMouseUp
18394 * @param {Event} e the mouseup event
18396 onMouseUp: function(e) { /* override this */ },
18399 * Override the onAvailable method to do what is needed after the initial
18400 * position was determined.
18401 * @method onAvailable
18403 onAvailable: function () {
18407 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18410 defaultPadding : {left:0, right:0, top:0, bottom:0},
18413 * Initializes the drag drop object's constraints to restrict movement to a certain element.
18417 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18418 { dragElId: "existingProxyDiv" });
18419 dd.startDrag = function(){
18420 this.constrainTo("parent-id");
18423 * Or you can initalize it using the {@link Roo.Element} object:
18425 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18426 startDrag : function(){
18427 this.constrainTo("parent-id");
18431 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18432 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18433 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18434 * an object containing the sides to pad. For example: {right:10, bottom:10}
18435 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18437 constrainTo : function(constrainTo, pad, inContent){
18438 if(typeof pad == "number"){
18439 pad = {left: pad, right:pad, top:pad, bottom:pad};
18441 pad = pad || this.defaultPadding;
18442 var b = Roo.get(this.getEl()).getBox();
18443 var ce = Roo.get(constrainTo);
18444 var s = ce.getScroll();
18445 var c, cd = ce.dom;
18446 if(cd == document.body){
18447 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18450 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18454 var topSpace = b.y - c.y;
18455 var leftSpace = b.x - c.x;
18457 this.resetConstraints();
18458 this.setXConstraint(leftSpace - (pad.left||0), // left
18459 c.width - leftSpace - b.width - (pad.right||0) //right
18461 this.setYConstraint(topSpace - (pad.top||0), //top
18462 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18467 * Returns a reference to the linked element
18469 * @return {HTMLElement} the html element
18471 getEl: function() {
18472 if (!this._domRef) {
18473 this._domRef = Roo.getDom(this.id);
18476 return this._domRef;
18480 * Returns a reference to the actual element to drag. By default this is
18481 * the same as the html element, but it can be assigned to another
18482 * element. An example of this can be found in Roo.dd.DDProxy
18483 * @method getDragEl
18484 * @return {HTMLElement} the html element
18486 getDragEl: function() {
18487 return Roo.getDom(this.dragElId);
18491 * Sets up the DragDrop object. Must be called in the constructor of any
18492 * Roo.dd.DragDrop subclass
18494 * @param id the id of the linked element
18495 * @param {String} sGroup the group of related items
18496 * @param {object} config configuration attributes
18498 init: function(id, sGroup, config) {
18499 this.initTarget(id, sGroup, config);
18500 if (!Roo.isTouch) {
18501 Event.on(this.id, "mousedown", this.handleMouseDown, this);
18503 Event.on(this.id, "touchstart", this.handleMouseDown, this);
18504 // Event.on(this.id, "selectstart", Event.preventDefault);
18508 * Initializes Targeting functionality only... the object does not
18509 * get a mousedown handler.
18510 * @method initTarget
18511 * @param id the id of the linked element
18512 * @param {String} sGroup the group of related items
18513 * @param {object} config configuration attributes
18515 initTarget: function(id, sGroup, config) {
18517 // configuration attributes
18518 this.config = config || {};
18520 // create a local reference to the drag and drop manager
18521 this.DDM = Roo.dd.DDM;
18522 // initialize the groups array
18525 // assume that we have an element reference instead of an id if the
18526 // parameter is not a string
18527 if (typeof id !== "string") {
18534 // add to an interaction group
18535 this.addToGroup((sGroup) ? sGroup : "default");
18537 // We don't want to register this as the handle with the manager
18538 // so we just set the id rather than calling the setter.
18539 this.handleElId = id;
18541 // the linked element is the element that gets dragged by default
18542 this.setDragElId(id);
18544 // by default, clicked anchors will not start drag operations.
18545 this.invalidHandleTypes = { A: "A" };
18546 this.invalidHandleIds = {};
18547 this.invalidHandleClasses = [];
18549 this.applyConfig();
18551 this.handleOnAvailable();
18555 * Applies the configuration parameters that were passed into the constructor.
18556 * This is supposed to happen at each level through the inheritance chain. So
18557 * a DDProxy implentation will execute apply config on DDProxy, DD, and
18558 * DragDrop in order to get all of the parameters that are available in
18560 * @method applyConfig
18562 applyConfig: function() {
18564 // configurable properties:
18565 // padding, isTarget, maintainOffset, primaryButtonOnly
18566 this.padding = this.config.padding || [0, 0, 0, 0];
18567 this.isTarget = (this.config.isTarget !== false);
18568 this.maintainOffset = (this.config.maintainOffset);
18569 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18574 * Executed when the linked element is available
18575 * @method handleOnAvailable
18578 handleOnAvailable: function() {
18579 this.available = true;
18580 this.resetConstraints();
18581 this.onAvailable();
18585 * Configures the padding for the target zone in px. Effectively expands
18586 * (or reduces) the virtual object size for targeting calculations.
18587 * Supports css-style shorthand; if only one parameter is passed, all sides
18588 * will have that padding, and if only two are passed, the top and bottom
18589 * will have the first param, the left and right the second.
18590 * @method setPadding
18591 * @param {int} iTop Top pad
18592 * @param {int} iRight Right pad
18593 * @param {int} iBot Bot pad
18594 * @param {int} iLeft Left pad
18596 setPadding: function(iTop, iRight, iBot, iLeft) {
18597 // this.padding = [iLeft, iRight, iTop, iBot];
18598 if (!iRight && 0 !== iRight) {
18599 this.padding = [iTop, iTop, iTop, iTop];
18600 } else if (!iBot && 0 !== iBot) {
18601 this.padding = [iTop, iRight, iTop, iRight];
18603 this.padding = [iTop, iRight, iBot, iLeft];
18608 * Stores the initial placement of the linked element.
18609 * @method setInitialPosition
18610 * @param {int} diffX the X offset, default 0
18611 * @param {int} diffY the Y offset, default 0
18613 setInitPosition: function(diffX, diffY) {
18614 var el = this.getEl();
18616 if (!this.DDM.verifyEl(el)) {
18620 var dx = diffX || 0;
18621 var dy = diffY || 0;
18623 var p = Dom.getXY( el );
18625 this.initPageX = p[0] - dx;
18626 this.initPageY = p[1] - dy;
18628 this.lastPageX = p[0];
18629 this.lastPageY = p[1];
18632 this.setStartPosition(p);
18636 * Sets the start position of the element. This is set when the obj
18637 * is initialized, the reset when a drag is started.
18638 * @method setStartPosition
18639 * @param pos current position (from previous lookup)
18642 setStartPosition: function(pos) {
18643 var p = pos || Dom.getXY( this.getEl() );
18644 this.deltaSetXY = null;
18646 this.startPageX = p[0];
18647 this.startPageY = p[1];
18651 * Add this instance to a group of related drag/drop objects. All
18652 * instances belong to at least one group, and can belong to as many
18653 * groups as needed.
18654 * @method addToGroup
18655 * @param sGroup {string} the name of the group
18657 addToGroup: function(sGroup) {
18658 this.groups[sGroup] = true;
18659 this.DDM.regDragDrop(this, sGroup);
18663 * Remove's this instance from the supplied interaction group
18664 * @method removeFromGroup
18665 * @param {string} sGroup The group to drop
18667 removeFromGroup: function(sGroup) {
18668 if (this.groups[sGroup]) {
18669 delete this.groups[sGroup];
18672 this.DDM.removeDDFromGroup(this, sGroup);
18676 * Allows you to specify that an element other than the linked element
18677 * will be moved with the cursor during a drag
18678 * @method setDragElId
18679 * @param id {string} the id of the element that will be used to initiate the drag
18681 setDragElId: function(id) {
18682 this.dragElId = id;
18686 * Allows you to specify a child of the linked element that should be
18687 * used to initiate the drag operation. An example of this would be if
18688 * you have a content div with text and links. Clicking anywhere in the
18689 * content area would normally start the drag operation. Use this method
18690 * to specify that an element inside of the content div is the element
18691 * that starts the drag operation.
18692 * @method setHandleElId
18693 * @param id {string} the id of the element that will be used to
18694 * initiate the drag.
18696 setHandleElId: function(id) {
18697 if (typeof id !== "string") {
18700 this.handleElId = id;
18701 this.DDM.regHandle(this.id, id);
18705 * Allows you to set an element outside of the linked element as a drag
18707 * @method setOuterHandleElId
18708 * @param id the id of the element that will be used to initiate the drag
18710 setOuterHandleElId: function(id) {
18711 if (typeof id !== "string") {
18714 Event.on(id, "mousedown",
18715 this.handleMouseDown, this);
18716 this.setHandleElId(id);
18718 this.hasOuterHandles = true;
18722 * Remove all drag and drop hooks for this element
18725 unreg: function() {
18726 Event.un(this.id, "mousedown",
18727 this.handleMouseDown);
18728 Event.un(this.id, "touchstart",
18729 this.handleMouseDown);
18730 this._domRef = null;
18731 this.DDM._remove(this);
18734 destroy : function(){
18739 * Returns true if this instance is locked, or the drag drop mgr is locked
18740 * (meaning that all drag/drop is disabled on the page.)
18742 * @return {boolean} true if this obj or all drag/drop is locked, else
18745 isLocked: function() {
18746 return (this.DDM.isLocked() || this.locked);
18750 * Fired when this object is clicked
18751 * @method handleMouseDown
18753 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18756 handleMouseDown: function(e, oDD){
18758 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18759 //Roo.log('not touch/ button !=0');
18762 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18763 return; // double touch..
18767 if (this.isLocked()) {
18768 //Roo.log('locked');
18772 this.DDM.refreshCache(this.groups);
18773 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18774 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18775 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
18776 //Roo.log('no outer handes or not over target');
18779 // Roo.log('check validator');
18780 if (this.clickValidator(e)) {
18781 // Roo.log('validate success');
18782 // set the initial element position
18783 this.setStartPosition();
18786 this.b4MouseDown(e);
18787 this.onMouseDown(e);
18789 this.DDM.handleMouseDown(e, this);
18791 this.DDM.stopEvent(e);
18799 clickValidator: function(e) {
18800 var target = e.getTarget();
18801 return ( this.isValidHandleChild(target) &&
18802 (this.id == this.handleElId ||
18803 this.DDM.handleWasClicked(target, this.id)) );
18807 * Allows you to specify a tag name that should not start a drag operation
18808 * when clicked. This is designed to facilitate embedding links within a
18809 * drag handle that do something other than start the drag.
18810 * @method addInvalidHandleType
18811 * @param {string} tagName the type of element to exclude
18813 addInvalidHandleType: function(tagName) {
18814 var type = tagName.toUpperCase();
18815 this.invalidHandleTypes[type] = type;
18819 * Lets you to specify an element id for a child of a drag handle
18820 * that should not initiate a drag
18821 * @method addInvalidHandleId
18822 * @param {string} id the element id of the element you wish to ignore
18824 addInvalidHandleId: function(id) {
18825 if (typeof id !== "string") {
18828 this.invalidHandleIds[id] = id;
18832 * Lets you specify a css class of elements that will not initiate a drag
18833 * @method addInvalidHandleClass
18834 * @param {string} cssClass the class of the elements you wish to ignore
18836 addInvalidHandleClass: function(cssClass) {
18837 this.invalidHandleClasses.push(cssClass);
18841 * Unsets an excluded tag name set by addInvalidHandleType
18842 * @method removeInvalidHandleType
18843 * @param {string} tagName the type of element to unexclude
18845 removeInvalidHandleType: function(tagName) {
18846 var type = tagName.toUpperCase();
18847 // this.invalidHandleTypes[type] = null;
18848 delete this.invalidHandleTypes[type];
18852 * Unsets an invalid handle id
18853 * @method removeInvalidHandleId
18854 * @param {string} id the id of the element to re-enable
18856 removeInvalidHandleId: function(id) {
18857 if (typeof id !== "string") {
18860 delete this.invalidHandleIds[id];
18864 * Unsets an invalid css class
18865 * @method removeInvalidHandleClass
18866 * @param {string} cssClass the class of the element(s) you wish to
18869 removeInvalidHandleClass: function(cssClass) {
18870 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18871 if (this.invalidHandleClasses[i] == cssClass) {
18872 delete this.invalidHandleClasses[i];
18878 * Checks the tag exclusion list to see if this click should be ignored
18879 * @method isValidHandleChild
18880 * @param {HTMLElement} node the HTMLElement to evaluate
18881 * @return {boolean} true if this is a valid tag type, false if not
18883 isValidHandleChild: function(node) {
18886 // var n = (node.nodeName == "#text") ? node.parentNode : node;
18889 nodeName = node.nodeName.toUpperCase();
18891 nodeName = node.nodeName;
18893 valid = valid && !this.invalidHandleTypes[nodeName];
18894 valid = valid && !this.invalidHandleIds[node.id];
18896 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18897 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18906 * Create the array of horizontal tick marks if an interval was specified
18907 * in setXConstraint().
18908 * @method setXTicks
18911 setXTicks: function(iStartX, iTickSize) {
18913 this.xTickSize = iTickSize;
18917 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18919 this.xTicks[this.xTicks.length] = i;
18924 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18926 this.xTicks[this.xTicks.length] = i;
18931 this.xTicks.sort(this.DDM.numericSort) ;
18935 * Create the array of vertical tick marks if an interval was specified in
18936 * setYConstraint().
18937 * @method setYTicks
18940 setYTicks: function(iStartY, iTickSize) {
18942 this.yTickSize = iTickSize;
18946 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18948 this.yTicks[this.yTicks.length] = i;
18953 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18955 this.yTicks[this.yTicks.length] = i;
18960 this.yTicks.sort(this.DDM.numericSort) ;
18964 * By default, the element can be dragged any place on the screen. Use
18965 * this method to limit the horizontal travel of the element. Pass in
18966 * 0,0 for the parameters if you want to lock the drag to the y axis.
18967 * @method setXConstraint
18968 * @param {int} iLeft the number of pixels the element can move to the left
18969 * @param {int} iRight the number of pixels the element can move to the
18971 * @param {int} iTickSize optional parameter for specifying that the
18973 * should move iTickSize pixels at a time.
18975 setXConstraint: function(iLeft, iRight, iTickSize) {
18976 this.leftConstraint = iLeft;
18977 this.rightConstraint = iRight;
18979 this.minX = this.initPageX - iLeft;
18980 this.maxX = this.initPageX + iRight;
18981 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
18983 this.constrainX = true;
18987 * Clears any constraints applied to this instance. Also clears ticks
18988 * since they can't exist independent of a constraint at this time.
18989 * @method clearConstraints
18991 clearConstraints: function() {
18992 this.constrainX = false;
18993 this.constrainY = false;
18998 * Clears any tick interval defined for this instance
18999 * @method clearTicks
19001 clearTicks: function() {
19002 this.xTicks = null;
19003 this.yTicks = null;
19004 this.xTickSize = 0;
19005 this.yTickSize = 0;
19009 * By default, the element can be dragged any place on the screen. Set
19010 * this to limit the vertical travel of the element. Pass in 0,0 for the
19011 * parameters if you want to lock the drag to the x axis.
19012 * @method setYConstraint
19013 * @param {int} iUp the number of pixels the element can move up
19014 * @param {int} iDown the number of pixels the element can move down
19015 * @param {int} iTickSize optional parameter for specifying that the
19016 * element should move iTickSize pixels at a time.
19018 setYConstraint: function(iUp, iDown, iTickSize) {
19019 this.topConstraint = iUp;
19020 this.bottomConstraint = iDown;
19022 this.minY = this.initPageY - iUp;
19023 this.maxY = this.initPageY + iDown;
19024 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19026 this.constrainY = true;
19031 * resetConstraints must be called if you manually reposition a dd element.
19032 * @method resetConstraints
19033 * @param {boolean} maintainOffset
19035 resetConstraints: function() {
19038 // Maintain offsets if necessary
19039 if (this.initPageX || this.initPageX === 0) {
19040 // figure out how much this thing has moved
19041 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19042 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19044 this.setInitPosition(dx, dy);
19046 // This is the first time we have detected the element's position
19048 this.setInitPosition();
19051 if (this.constrainX) {
19052 this.setXConstraint( this.leftConstraint,
19053 this.rightConstraint,
19057 if (this.constrainY) {
19058 this.setYConstraint( this.topConstraint,
19059 this.bottomConstraint,
19065 * Normally the drag element is moved pixel by pixel, but we can specify
19066 * that it move a number of pixels at a time. This method resolves the
19067 * location when we have it set up like this.
19069 * @param {int} val where we want to place the object
19070 * @param {int[]} tickArray sorted array of valid points
19071 * @return {int} the closest tick
19074 getTick: function(val, tickArray) {
19077 // If tick interval is not defined, it is effectively 1 pixel,
19078 // so we return the value passed to us.
19080 } else if (tickArray[0] >= val) {
19081 // The value is lower than the first tick, so we return the first
19083 return tickArray[0];
19085 for (var i=0, len=tickArray.length; i<len; ++i) {
19087 if (tickArray[next] && tickArray[next] >= val) {
19088 var diff1 = val - tickArray[i];
19089 var diff2 = tickArray[next] - val;
19090 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19094 // The value is larger than the last tick, so we return the last
19096 return tickArray[tickArray.length - 1];
19103 * @return {string} string representation of the dd obj
19105 toString: function() {
19106 return ("DragDrop " + this.id);
19114 * Ext JS Library 1.1.1
19115 * Copyright(c) 2006-2007, Ext JS, LLC.
19117 * Originally Released Under LGPL - original licence link has changed is not relivant.
19120 * <script type="text/javascript">
19125 * The drag and drop utility provides a framework for building drag and drop
19126 * applications. In addition to enabling drag and drop for specific elements,
19127 * the drag and drop elements are tracked by the manager class, and the
19128 * interactions between the various elements are tracked during the drag and
19129 * the implementing code is notified about these important moments.
19132 // Only load the library once. Rewriting the manager class would orphan
19133 // existing drag and drop instances.
19134 if (!Roo.dd.DragDropMgr) {
19137 * @class Roo.dd.DragDropMgr
19138 * DragDropMgr is a singleton that tracks the element interaction for
19139 * all DragDrop items in the window. Generally, you will not call
19140 * this class directly, but it does have helper methods that could
19141 * be useful in your DragDrop implementations.
19144 Roo.dd.DragDropMgr = function() {
19146 var Event = Roo.EventManager;
19151 * Two dimensional Array of registered DragDrop objects. The first
19152 * dimension is the DragDrop item group, the second the DragDrop
19155 * @type {string: string}
19162 * Array of element ids defined as drag handles. Used to determine
19163 * if the element that generated the mousedown event is actually the
19164 * handle and not the html element itself.
19165 * @property handleIds
19166 * @type {string: string}
19173 * the DragDrop object that is currently being dragged
19174 * @property dragCurrent
19182 * the DragDrop object(s) that are being hovered over
19183 * @property dragOvers
19191 * the X distance between the cursor and the object being dragged
19200 * the Y distance between the cursor and the object being dragged
19209 * Flag to determine if we should prevent the default behavior of the
19210 * events we define. By default this is true, but this can be set to
19211 * false if you need the default behavior (not recommended)
19212 * @property preventDefault
19216 preventDefault: true,
19219 * Flag to determine if we should stop the propagation of the events
19220 * we generate. This is true by default but you may want to set it to
19221 * false if the html element contains other features that require the
19223 * @property stopPropagation
19227 stopPropagation: true,
19230 * Internal flag that is set to true when drag and drop has been
19232 * @property initialized
19239 * All drag and drop can be disabled.
19247 * Called the first time an element is registered.
19253 this.initialized = true;
19257 * In point mode, drag and drop interaction is defined by the
19258 * location of the cursor during the drag/drop
19266 * In intersect mode, drag and drop interactio nis defined by the
19267 * overlap of two or more drag and drop objects.
19268 * @property INTERSECT
19275 * The current drag and drop mode. Default: POINT
19283 * Runs method on all drag and drop objects
19284 * @method _execOnAll
19288 _execOnAll: function(sMethod, args) {
19289 for (var i in this.ids) {
19290 for (var j in this.ids[i]) {
19291 var oDD = this.ids[i][j];
19292 if (! this.isTypeOfDD(oDD)) {
19295 oDD[sMethod].apply(oDD, args);
19301 * Drag and drop initialization. Sets up the global event handlers
19306 _onLoad: function() {
19310 if (!Roo.isTouch) {
19311 Event.on(document, "mouseup", this.handleMouseUp, this, true);
19312 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19314 Event.on(document, "touchend", this.handleMouseUp, this, true);
19315 Event.on(document, "touchmove", this.handleMouseMove, this, true);
19317 Event.on(window, "unload", this._onUnload, this, true);
19318 Event.on(window, "resize", this._onResize, this, true);
19319 // Event.on(window, "mouseout", this._test);
19324 * Reset constraints on all drag and drop objs
19325 * @method _onResize
19329 _onResize: function(e) {
19330 this._execOnAll("resetConstraints", []);
19334 * Lock all drag and drop functionality
19338 lock: function() { this.locked = true; },
19341 * Unlock all drag and drop functionality
19345 unlock: function() { this.locked = false; },
19348 * Is drag and drop locked?
19350 * @return {boolean} True if drag and drop is locked, false otherwise.
19353 isLocked: function() { return this.locked; },
19356 * Location cache that is set for all drag drop objects when a drag is
19357 * initiated, cleared when the drag is finished.
19358 * @property locationCache
19365 * Set useCache to false if you want to force object the lookup of each
19366 * drag and drop linked element constantly during a drag.
19367 * @property useCache
19374 * The number of pixels that the mouse needs to move after the
19375 * mousedown before the drag is initiated. Default=3;
19376 * @property clickPixelThresh
19380 clickPixelThresh: 3,
19383 * The number of milliseconds after the mousedown event to initiate the
19384 * drag if we don't get a mouseup event. Default=1000
19385 * @property clickTimeThresh
19389 clickTimeThresh: 350,
19392 * Flag that indicates that either the drag pixel threshold or the
19393 * mousdown time threshold has been met
19394 * @property dragThreshMet
19399 dragThreshMet: false,
19402 * Timeout used for the click time threshold
19403 * @property clickTimeout
19408 clickTimeout: null,
19411 * The X position of the mousedown event stored for later use when a
19412 * drag threshold is met.
19421 * The Y position of the mousedown event stored for later use when a
19422 * drag threshold is met.
19431 * Each DragDrop instance must be registered with the DragDropMgr.
19432 * This is executed in DragDrop.init()
19433 * @method regDragDrop
19434 * @param {DragDrop} oDD the DragDrop object to register
19435 * @param {String} sGroup the name of the group this element belongs to
19438 regDragDrop: function(oDD, sGroup) {
19439 if (!this.initialized) { this.init(); }
19441 if (!this.ids[sGroup]) {
19442 this.ids[sGroup] = {};
19444 this.ids[sGroup][oDD.id] = oDD;
19448 * Removes the supplied dd instance from the supplied group. Executed
19449 * by DragDrop.removeFromGroup, so don't call this function directly.
19450 * @method removeDDFromGroup
19454 removeDDFromGroup: function(oDD, sGroup) {
19455 if (!this.ids[sGroup]) {
19456 this.ids[sGroup] = {};
19459 var obj = this.ids[sGroup];
19460 if (obj && obj[oDD.id]) {
19461 delete obj[oDD.id];
19466 * Unregisters a drag and drop item. This is executed in
19467 * DragDrop.unreg, use that method instead of calling this directly.
19472 _remove: function(oDD) {
19473 for (var g in oDD.groups) {
19474 if (g && this.ids[g][oDD.id]) {
19475 delete this.ids[g][oDD.id];
19478 delete this.handleIds[oDD.id];
19482 * Each DragDrop handle element must be registered. This is done
19483 * automatically when executing DragDrop.setHandleElId()
19484 * @method regHandle
19485 * @param {String} sDDId the DragDrop id this element is a handle for
19486 * @param {String} sHandleId the id of the element that is the drag
19490 regHandle: function(sDDId, sHandleId) {
19491 if (!this.handleIds[sDDId]) {
19492 this.handleIds[sDDId] = {};
19494 this.handleIds[sDDId][sHandleId] = sHandleId;
19498 * Utility function to determine if a given element has been
19499 * registered as a drag drop item.
19500 * @method isDragDrop
19501 * @param {String} id the element id to check
19502 * @return {boolean} true if this element is a DragDrop item,
19506 isDragDrop: function(id) {
19507 return ( this.getDDById(id) ) ? true : false;
19511 * Returns the drag and drop instances that are in all groups the
19512 * passed in instance belongs to.
19513 * @method getRelated
19514 * @param {DragDrop} p_oDD the obj to get related data for
19515 * @param {boolean} bTargetsOnly if true, only return targetable objs
19516 * @return {DragDrop[]} the related instances
19519 getRelated: function(p_oDD, bTargetsOnly) {
19521 for (var i in p_oDD.groups) {
19522 for (j in this.ids[i]) {
19523 var dd = this.ids[i][j];
19524 if (! this.isTypeOfDD(dd)) {
19527 if (!bTargetsOnly || dd.isTarget) {
19528 oDDs[oDDs.length] = dd;
19537 * Returns true if the specified dd target is a legal target for
19538 * the specifice drag obj
19539 * @method isLegalTarget
19540 * @param {DragDrop} the drag obj
19541 * @param {DragDrop} the target
19542 * @return {boolean} true if the target is a legal target for the
19546 isLegalTarget: function (oDD, oTargetDD) {
19547 var targets = this.getRelated(oDD, true);
19548 for (var i=0, len=targets.length;i<len;++i) {
19549 if (targets[i].id == oTargetDD.id) {
19558 * My goal is to be able to transparently determine if an object is
19559 * typeof DragDrop, and the exact subclass of DragDrop. typeof
19560 * returns "object", oDD.constructor.toString() always returns
19561 * "DragDrop" and not the name of the subclass. So for now it just
19562 * evaluates a well-known variable in DragDrop.
19563 * @method isTypeOfDD
19564 * @param {Object} the object to evaluate
19565 * @return {boolean} true if typeof oDD = DragDrop
19568 isTypeOfDD: function (oDD) {
19569 return (oDD && oDD.__ygDragDrop);
19573 * Utility function to determine if a given element has been
19574 * registered as a drag drop handle for the given Drag Drop object.
19576 * @param {String} id the element id to check
19577 * @return {boolean} true if this element is a DragDrop handle, false
19581 isHandle: function(sDDId, sHandleId) {
19582 return ( this.handleIds[sDDId] &&
19583 this.handleIds[sDDId][sHandleId] );
19587 * Returns the DragDrop instance for a given id
19588 * @method getDDById
19589 * @param {String} id the id of the DragDrop object
19590 * @return {DragDrop} the drag drop object, null if it is not found
19593 getDDById: function(id) {
19594 for (var i in this.ids) {
19595 if (this.ids[i][id]) {
19596 return this.ids[i][id];
19603 * Fired after a registered DragDrop object gets the mousedown event.
19604 * Sets up the events required to track the object being dragged
19605 * @method handleMouseDown
19606 * @param {Event} e the event
19607 * @param oDD the DragDrop object being dragged
19611 handleMouseDown: function(e, oDD) {
19613 Roo.QuickTips.disable();
19615 this.currentTarget = e.getTarget();
19617 this.dragCurrent = oDD;
19619 var el = oDD.getEl();
19621 // track start position
19622 this.startX = e.getPageX();
19623 this.startY = e.getPageY();
19625 this.deltaX = this.startX - el.offsetLeft;
19626 this.deltaY = this.startY - el.offsetTop;
19628 this.dragThreshMet = false;
19630 this.clickTimeout = setTimeout(
19632 var DDM = Roo.dd.DDM;
19633 DDM.startDrag(DDM.startX, DDM.startY);
19635 this.clickTimeThresh );
19639 * Fired when either the drag pixel threshol or the mousedown hold
19640 * time threshold has been met.
19641 * @method startDrag
19642 * @param x {int} the X position of the original mousedown
19643 * @param y {int} the Y position of the original mousedown
19646 startDrag: function(x, y) {
19647 clearTimeout(this.clickTimeout);
19648 if (this.dragCurrent) {
19649 this.dragCurrent.b4StartDrag(x, y);
19650 this.dragCurrent.startDrag(x, y);
19652 this.dragThreshMet = true;
19656 * Internal function to handle the mouseup event. Will be invoked
19657 * from the context of the document.
19658 * @method handleMouseUp
19659 * @param {Event} e the event
19663 handleMouseUp: function(e) {
19666 Roo.QuickTips.enable();
19668 if (! this.dragCurrent) {
19672 clearTimeout(this.clickTimeout);
19674 if (this.dragThreshMet) {
19675 this.fireEvents(e, true);
19685 * Utility to stop event propagation and event default, if these
19686 * features are turned on.
19687 * @method stopEvent
19688 * @param {Event} e the event as returned by this.getEvent()
19691 stopEvent: function(e){
19692 if(this.stopPropagation) {
19693 e.stopPropagation();
19696 if (this.preventDefault) {
19697 e.preventDefault();
19702 * Internal function to clean up event handlers after the drag
19703 * operation is complete
19705 * @param {Event} e the event
19709 stopDrag: function(e) {
19710 // Fire the drag end event for the item that was dragged
19711 if (this.dragCurrent) {
19712 if (this.dragThreshMet) {
19713 this.dragCurrent.b4EndDrag(e);
19714 this.dragCurrent.endDrag(e);
19717 this.dragCurrent.onMouseUp(e);
19720 this.dragCurrent = null;
19721 this.dragOvers = {};
19725 * Internal function to handle the mousemove event. Will be invoked
19726 * from the context of the html element.
19728 * @TODO figure out what we can do about mouse events lost when the
19729 * user drags objects beyond the window boundary. Currently we can
19730 * detect this in internet explorer by verifying that the mouse is
19731 * down during the mousemove event. Firefox doesn't give us the
19732 * button state on the mousemove event.
19733 * @method handleMouseMove
19734 * @param {Event} e the event
19738 handleMouseMove: function(e) {
19739 if (! this.dragCurrent) {
19743 // var button = e.which || e.button;
19745 // check for IE mouseup outside of page boundary
19746 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19748 return this.handleMouseUp(e);
19751 if (!this.dragThreshMet) {
19752 var diffX = Math.abs(this.startX - e.getPageX());
19753 var diffY = Math.abs(this.startY - e.getPageY());
19754 if (diffX > this.clickPixelThresh ||
19755 diffY > this.clickPixelThresh) {
19756 this.startDrag(this.startX, this.startY);
19760 if (this.dragThreshMet) {
19761 this.dragCurrent.b4Drag(e);
19762 this.dragCurrent.onDrag(e);
19763 if(!this.dragCurrent.moveOnly){
19764 this.fireEvents(e, false);
19774 * Iterates over all of the DragDrop elements to find ones we are
19775 * hovering over or dropping on
19776 * @method fireEvents
19777 * @param {Event} e the event
19778 * @param {boolean} isDrop is this a drop op or a mouseover op?
19782 fireEvents: function(e, isDrop) {
19783 var dc = this.dragCurrent;
19785 // If the user did the mouse up outside of the window, we could
19786 // get here even though we have ended the drag.
19787 if (!dc || dc.isLocked()) {
19791 var pt = e.getPoint();
19793 // cache the previous dragOver array
19799 var enterEvts = [];
19801 // Check to see if the object(s) we were hovering over is no longer
19802 // being hovered over so we can fire the onDragOut event
19803 for (var i in this.dragOvers) {
19805 var ddo = this.dragOvers[i];
19807 if (! this.isTypeOfDD(ddo)) {
19811 if (! this.isOverTarget(pt, ddo, this.mode)) {
19812 outEvts.push( ddo );
19815 oldOvers[i] = true;
19816 delete this.dragOvers[i];
19819 for (var sGroup in dc.groups) {
19821 if ("string" != typeof sGroup) {
19825 for (i in this.ids[sGroup]) {
19826 var oDD = this.ids[sGroup][i];
19827 if (! this.isTypeOfDD(oDD)) {
19831 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19832 if (this.isOverTarget(pt, oDD, this.mode)) {
19833 // look for drop interactions
19835 dropEvts.push( oDD );
19836 // look for drag enter and drag over interactions
19839 // initial drag over: dragEnter fires
19840 if (!oldOvers[oDD.id]) {
19841 enterEvts.push( oDD );
19842 // subsequent drag overs: dragOver fires
19844 overEvts.push( oDD );
19847 this.dragOvers[oDD.id] = oDD;
19855 if (outEvts.length) {
19856 dc.b4DragOut(e, outEvts);
19857 dc.onDragOut(e, outEvts);
19860 if (enterEvts.length) {
19861 dc.onDragEnter(e, enterEvts);
19864 if (overEvts.length) {
19865 dc.b4DragOver(e, overEvts);
19866 dc.onDragOver(e, overEvts);
19869 if (dropEvts.length) {
19870 dc.b4DragDrop(e, dropEvts);
19871 dc.onDragDrop(e, dropEvts);
19875 // fire dragout events
19877 for (i=0, len=outEvts.length; i<len; ++i) {
19878 dc.b4DragOut(e, outEvts[i].id);
19879 dc.onDragOut(e, outEvts[i].id);
19882 // fire enter events
19883 for (i=0,len=enterEvts.length; i<len; ++i) {
19884 // dc.b4DragEnter(e, oDD.id);
19885 dc.onDragEnter(e, enterEvts[i].id);
19888 // fire over events
19889 for (i=0,len=overEvts.length; i<len; ++i) {
19890 dc.b4DragOver(e, overEvts[i].id);
19891 dc.onDragOver(e, overEvts[i].id);
19894 // fire drop events
19895 for (i=0, len=dropEvts.length; i<len; ++i) {
19896 dc.b4DragDrop(e, dropEvts[i].id);
19897 dc.onDragDrop(e, dropEvts[i].id);
19902 // notify about a drop that did not find a target
19903 if (isDrop && !dropEvts.length) {
19904 dc.onInvalidDrop(e);
19910 * Helper function for getting the best match from the list of drag
19911 * and drop objects returned by the drag and drop events when we are
19912 * in INTERSECT mode. It returns either the first object that the
19913 * cursor is over, or the object that has the greatest overlap with
19914 * the dragged element.
19915 * @method getBestMatch
19916 * @param {DragDrop[]} dds The array of drag and drop objects
19918 * @return {DragDrop} The best single match
19921 getBestMatch: function(dds) {
19923 // Return null if the input is not what we expect
19924 //if (!dds || !dds.length || dds.length == 0) {
19926 // If there is only one item, it wins
19927 //} else if (dds.length == 1) {
19929 var len = dds.length;
19934 // Loop through the targeted items
19935 for (var i=0; i<len; ++i) {
19937 // If the cursor is over the object, it wins. If the
19938 // cursor is over multiple matches, the first one we come
19940 if (dd.cursorIsOver) {
19943 // Otherwise the object with the most overlap wins
19946 winner.overlap.getArea() < dd.overlap.getArea()) {
19957 * Refreshes the cache of the top-left and bottom-right points of the
19958 * drag and drop objects in the specified group(s). This is in the
19959 * format that is stored in the drag and drop instance, so typical
19962 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19966 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19968 * @TODO this really should be an indexed array. Alternatively this
19969 * method could accept both.
19970 * @method refreshCache
19971 * @param {Object} groups an associative array of groups to refresh
19974 refreshCache: function(groups) {
19975 for (var sGroup in groups) {
19976 if ("string" != typeof sGroup) {
19979 for (var i in this.ids[sGroup]) {
19980 var oDD = this.ids[sGroup][i];
19982 if (this.isTypeOfDD(oDD)) {
19983 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
19984 var loc = this.getLocation(oDD);
19986 this.locationCache[oDD.id] = loc;
19988 delete this.locationCache[oDD.id];
19989 // this will unregister the drag and drop object if
19990 // the element is not in a usable state
19999 * This checks to make sure an element exists and is in the DOM. The
20000 * main purpose is to handle cases where innerHTML is used to remove
20001 * drag and drop objects from the DOM. IE provides an 'unspecified
20002 * error' when trying to access the offsetParent of such an element
20004 * @param {HTMLElement} el the element to check
20005 * @return {boolean} true if the element looks usable
20008 verifyEl: function(el) {
20013 parent = el.offsetParent;
20016 parent = el.offsetParent;
20027 * Returns a Region object containing the drag and drop element's position
20028 * and size, including the padding configured for it
20029 * @method getLocation
20030 * @param {DragDrop} oDD the drag and drop object to get the
20032 * @return {Roo.lib.Region} a Region object representing the total area
20033 * the element occupies, including any padding
20034 * the instance is configured for.
20037 getLocation: function(oDD) {
20038 if (! this.isTypeOfDD(oDD)) {
20042 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20045 pos= Roo.lib.Dom.getXY(el);
20053 x2 = x1 + el.offsetWidth;
20055 y2 = y1 + el.offsetHeight;
20057 t = y1 - oDD.padding[0];
20058 r = x2 + oDD.padding[1];
20059 b = y2 + oDD.padding[2];
20060 l = x1 - oDD.padding[3];
20062 return new Roo.lib.Region( t, r, b, l );
20066 * Checks the cursor location to see if it over the target
20067 * @method isOverTarget
20068 * @param {Roo.lib.Point} pt The point to evaluate
20069 * @param {DragDrop} oTarget the DragDrop object we are inspecting
20070 * @return {boolean} true if the mouse is over the target
20074 isOverTarget: function(pt, oTarget, intersect) {
20075 // use cache if available
20076 var loc = this.locationCache[oTarget.id];
20077 if (!loc || !this.useCache) {
20078 loc = this.getLocation(oTarget);
20079 this.locationCache[oTarget.id] = loc;
20087 oTarget.cursorIsOver = loc.contains( pt );
20089 // DragDrop is using this as a sanity check for the initial mousedown
20090 // in this case we are done. In POINT mode, if the drag obj has no
20091 // contraints, we are also done. Otherwise we need to evaluate the
20092 // location of the target as related to the actual location of the
20093 // dragged element.
20094 var dc = this.dragCurrent;
20095 if (!dc || !dc.getTargetCoord ||
20096 (!intersect && !dc.constrainX && !dc.constrainY)) {
20097 return oTarget.cursorIsOver;
20100 oTarget.overlap = null;
20102 // Get the current location of the drag element, this is the
20103 // location of the mouse event less the delta that represents
20104 // where the original mousedown happened on the element. We
20105 // need to consider constraints and ticks as well.
20106 var pos = dc.getTargetCoord(pt.x, pt.y);
20108 var el = dc.getDragEl();
20109 var curRegion = new Roo.lib.Region( pos.y,
20110 pos.x + el.offsetWidth,
20111 pos.y + el.offsetHeight,
20114 var overlap = curRegion.intersect(loc);
20117 oTarget.overlap = overlap;
20118 return (intersect) ? true : oTarget.cursorIsOver;
20125 * unload event handler
20126 * @method _onUnload
20130 _onUnload: function(e, me) {
20131 Roo.dd.DragDropMgr.unregAll();
20135 * Cleans up the drag and drop events and objects.
20140 unregAll: function() {
20142 if (this.dragCurrent) {
20144 this.dragCurrent = null;
20147 this._execOnAll("unreg", []);
20149 for (i in this.elementCache) {
20150 delete this.elementCache[i];
20153 this.elementCache = {};
20158 * A cache of DOM elements
20159 * @property elementCache
20166 * Get the wrapper for the DOM element specified
20167 * @method getElWrapper
20168 * @param {String} id the id of the element to get
20169 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20171 * @deprecated This wrapper isn't that useful
20174 getElWrapper: function(id) {
20175 var oWrapper = this.elementCache[id];
20176 if (!oWrapper || !oWrapper.el) {
20177 oWrapper = this.elementCache[id] =
20178 new this.ElementWrapper(Roo.getDom(id));
20184 * Returns the actual DOM element
20185 * @method getElement
20186 * @param {String} id the id of the elment to get
20187 * @return {Object} The element
20188 * @deprecated use Roo.getDom instead
20191 getElement: function(id) {
20192 return Roo.getDom(id);
20196 * Returns the style property for the DOM element (i.e.,
20197 * document.getElById(id).style)
20199 * @param {String} id the id of the elment to get
20200 * @return {Object} The style property of the element
20201 * @deprecated use Roo.getDom instead
20204 getCss: function(id) {
20205 var el = Roo.getDom(id);
20206 return (el) ? el.style : null;
20210 * Inner class for cached elements
20211 * @class DragDropMgr.ElementWrapper
20216 ElementWrapper: function(el) {
20221 this.el = el || null;
20226 this.id = this.el && el.id;
20228 * A reference to the style property
20231 this.css = this.el && el.style;
20235 * Returns the X position of an html element
20237 * @param el the element for which to get the position
20238 * @return {int} the X coordinate
20240 * @deprecated use Roo.lib.Dom.getX instead
20243 getPosX: function(el) {
20244 return Roo.lib.Dom.getX(el);
20248 * Returns the Y position of an html element
20250 * @param el the element for which to get the position
20251 * @return {int} the Y coordinate
20252 * @deprecated use Roo.lib.Dom.getY instead
20255 getPosY: function(el) {
20256 return Roo.lib.Dom.getY(el);
20260 * Swap two nodes. In IE, we use the native method, for others we
20261 * emulate the IE behavior
20263 * @param n1 the first node to swap
20264 * @param n2 the other node to swap
20267 swapNode: function(n1, n2) {
20271 var p = n2.parentNode;
20272 var s = n2.nextSibling;
20275 p.insertBefore(n1, n2);
20276 } else if (n2 == n1.nextSibling) {
20277 p.insertBefore(n2, n1);
20279 n1.parentNode.replaceChild(n2, n1);
20280 p.insertBefore(n1, s);
20286 * Returns the current scroll position
20287 * @method getScroll
20291 getScroll: function () {
20292 var t, l, dde=document.documentElement, db=document.body;
20293 if (dde && (dde.scrollTop || dde.scrollLeft)) {
20295 l = dde.scrollLeft;
20302 return { top: t, left: l };
20306 * Returns the specified element style property
20308 * @param {HTMLElement} el the element
20309 * @param {string} styleProp the style property
20310 * @return {string} The value of the style property
20311 * @deprecated use Roo.lib.Dom.getStyle
20314 getStyle: function(el, styleProp) {
20315 return Roo.fly(el).getStyle(styleProp);
20319 * Gets the scrollTop
20320 * @method getScrollTop
20321 * @return {int} the document's scrollTop
20324 getScrollTop: function () { return this.getScroll().top; },
20327 * Gets the scrollLeft
20328 * @method getScrollLeft
20329 * @return {int} the document's scrollTop
20332 getScrollLeft: function () { return this.getScroll().left; },
20335 * Sets the x/y position of an element to the location of the
20338 * @param {HTMLElement} moveEl The element to move
20339 * @param {HTMLElement} targetEl The position reference element
20342 moveToEl: function (moveEl, targetEl) {
20343 var aCoord = Roo.lib.Dom.getXY(targetEl);
20344 Roo.lib.Dom.setXY(moveEl, aCoord);
20348 * Numeric array sort function
20349 * @method numericSort
20352 numericSort: function(a, b) { return (a - b); },
20356 * @property _timeoutCount
20363 * Trying to make the load order less important. Without this we get
20364 * an error if this file is loaded before the Event Utility.
20365 * @method _addListeners
20369 _addListeners: function() {
20370 var DDM = Roo.dd.DDM;
20371 if ( Roo.lib.Event && document ) {
20374 if (DDM._timeoutCount > 2000) {
20376 setTimeout(DDM._addListeners, 10);
20377 if (document && document.body) {
20378 DDM._timeoutCount += 1;
20385 * Recursively searches the immediate parent and all child nodes for
20386 * the handle element in order to determine wheter or not it was
20388 * @method handleWasClicked
20389 * @param node the html element to inspect
20392 handleWasClicked: function(node, id) {
20393 if (this.isHandle(id, node.id)) {
20396 // check to see if this is a text node child of the one we want
20397 var p = node.parentNode;
20400 if (this.isHandle(id, p.id)) {
20415 // shorter alias, save a few bytes
20416 Roo.dd.DDM = Roo.dd.DragDropMgr;
20417 Roo.dd.DDM._addListeners();
20421 * Ext JS Library 1.1.1
20422 * Copyright(c) 2006-2007, Ext JS, LLC.
20424 * Originally Released Under LGPL - original licence link has changed is not relivant.
20427 * <script type="text/javascript">
20432 * A DragDrop implementation where the linked element follows the
20433 * mouse cursor during a drag.
20434 * @extends Roo.dd.DragDrop
20436 * @param {String} id the id of the linked element
20437 * @param {String} sGroup the group of related DragDrop items
20438 * @param {object} config an object containing configurable attributes
20439 * Valid properties for DD:
20442 Roo.dd.DD = function(id, sGroup, config) {
20444 this.init(id, sGroup, config);
20448 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20451 * When set to true, the utility automatically tries to scroll the browser
20452 * window wehn a drag and drop element is dragged near the viewport boundary.
20453 * Defaults to true.
20460 * Sets the pointer offset to the distance between the linked element's top
20461 * left corner and the location the element was clicked
20462 * @method autoOffset
20463 * @param {int} iPageX the X coordinate of the click
20464 * @param {int} iPageY the Y coordinate of the click
20466 autoOffset: function(iPageX, iPageY) {
20467 var x = iPageX - this.startPageX;
20468 var y = iPageY - this.startPageY;
20469 this.setDelta(x, y);
20473 * Sets the pointer offset. You can call this directly to force the
20474 * offset to be in a particular location (e.g., pass in 0,0 to set it
20475 * to the center of the object)
20477 * @param {int} iDeltaX the distance from the left
20478 * @param {int} iDeltaY the distance from the top
20480 setDelta: function(iDeltaX, iDeltaY) {
20481 this.deltaX = iDeltaX;
20482 this.deltaY = iDeltaY;
20486 * Sets the drag element to the location of the mousedown or click event,
20487 * maintaining the cursor location relative to the location on the element
20488 * that was clicked. Override this if you want to place the element in a
20489 * location other than where the cursor is.
20490 * @method setDragElPos
20491 * @param {int} iPageX the X coordinate of the mousedown or drag event
20492 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20494 setDragElPos: function(iPageX, iPageY) {
20495 // the first time we do this, we are going to check to make sure
20496 // the element has css positioning
20498 var el = this.getDragEl();
20499 this.alignElWithMouse(el, iPageX, iPageY);
20503 * Sets the element to the location of the mousedown or click event,
20504 * maintaining the cursor location relative to the location on the element
20505 * that was clicked. Override this if you want to place the element in a
20506 * location other than where the cursor is.
20507 * @method alignElWithMouse
20508 * @param {HTMLElement} el the element to move
20509 * @param {int} iPageX the X coordinate of the mousedown or drag event
20510 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20512 alignElWithMouse: function(el, iPageX, iPageY) {
20513 var oCoord = this.getTargetCoord(iPageX, iPageY);
20514 var fly = el.dom ? el : Roo.fly(el);
20515 if (!this.deltaSetXY) {
20516 var aCoord = [oCoord.x, oCoord.y];
20518 var newLeft = fly.getLeft(true);
20519 var newTop = fly.getTop(true);
20520 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20522 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20525 this.cachePosition(oCoord.x, oCoord.y);
20526 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20531 * Saves the most recent position so that we can reset the constraints and
20532 * tick marks on-demand. We need to know this so that we can calculate the
20533 * number of pixels the element is offset from its original position.
20534 * @method cachePosition
20535 * @param iPageX the current x position (optional, this just makes it so we
20536 * don't have to look it up again)
20537 * @param iPageY the current y position (optional, this just makes it so we
20538 * don't have to look it up again)
20540 cachePosition: function(iPageX, iPageY) {
20542 this.lastPageX = iPageX;
20543 this.lastPageY = iPageY;
20545 var aCoord = Roo.lib.Dom.getXY(this.getEl());
20546 this.lastPageX = aCoord[0];
20547 this.lastPageY = aCoord[1];
20552 * Auto-scroll the window if the dragged object has been moved beyond the
20553 * visible window boundary.
20554 * @method autoScroll
20555 * @param {int} x the drag element's x position
20556 * @param {int} y the drag element's y position
20557 * @param {int} h the height of the drag element
20558 * @param {int} w the width of the drag element
20561 autoScroll: function(x, y, h, w) {
20564 // The client height
20565 var clientH = Roo.lib.Dom.getViewWidth();
20567 // The client width
20568 var clientW = Roo.lib.Dom.getViewHeight();
20570 // The amt scrolled down
20571 var st = this.DDM.getScrollTop();
20573 // The amt scrolled right
20574 var sl = this.DDM.getScrollLeft();
20576 // Location of the bottom of the element
20579 // Location of the right of the element
20582 // The distance from the cursor to the bottom of the visible area,
20583 // adjusted so that we don't scroll if the cursor is beyond the
20584 // element drag constraints
20585 var toBot = (clientH + st - y - this.deltaY);
20587 // The distance from the cursor to the right of the visible area
20588 var toRight = (clientW + sl - x - this.deltaX);
20591 // How close to the edge the cursor must be before we scroll
20592 // var thresh = (document.all) ? 100 : 40;
20595 // How many pixels to scroll per autoscroll op. This helps to reduce
20596 // clunky scrolling. IE is more sensitive about this ... it needs this
20597 // value to be higher.
20598 var scrAmt = (document.all) ? 80 : 30;
20600 // Scroll down if we are near the bottom of the visible page and the
20601 // obj extends below the crease
20602 if ( bot > clientH && toBot < thresh ) {
20603 window.scrollTo(sl, st + scrAmt);
20606 // Scroll up if the window is scrolled down and the top of the object
20607 // goes above the top border
20608 if ( y < st && st > 0 && y - st < thresh ) {
20609 window.scrollTo(sl, st - scrAmt);
20612 // Scroll right if the obj is beyond the right border and the cursor is
20613 // near the border.
20614 if ( right > clientW && toRight < thresh ) {
20615 window.scrollTo(sl + scrAmt, st);
20618 // Scroll left if the window has been scrolled to the right and the obj
20619 // extends past the left border
20620 if ( x < sl && sl > 0 && x - sl < thresh ) {
20621 window.scrollTo(sl - scrAmt, st);
20627 * Finds the location the element should be placed if we want to move
20628 * it to where the mouse location less the click offset would place us.
20629 * @method getTargetCoord
20630 * @param {int} iPageX the X coordinate of the click
20631 * @param {int} iPageY the Y coordinate of the click
20632 * @return an object that contains the coordinates (Object.x and Object.y)
20635 getTargetCoord: function(iPageX, iPageY) {
20638 var x = iPageX - this.deltaX;
20639 var y = iPageY - this.deltaY;
20641 if (this.constrainX) {
20642 if (x < this.minX) { x = this.minX; }
20643 if (x > this.maxX) { x = this.maxX; }
20646 if (this.constrainY) {
20647 if (y < this.minY) { y = this.minY; }
20648 if (y > this.maxY) { y = this.maxY; }
20651 x = this.getTick(x, this.xTicks);
20652 y = this.getTick(y, this.yTicks);
20659 * Sets up config options specific to this class. Overrides
20660 * Roo.dd.DragDrop, but all versions of this method through the
20661 * inheritance chain are called
20663 applyConfig: function() {
20664 Roo.dd.DD.superclass.applyConfig.call(this);
20665 this.scroll = (this.config.scroll !== false);
20669 * Event that fires prior to the onMouseDown event. Overrides
20672 b4MouseDown: function(e) {
20673 // this.resetConstraints();
20674 this.autoOffset(e.getPageX(),
20679 * Event that fires prior to the onDrag event. Overrides
20682 b4Drag: function(e) {
20683 this.setDragElPos(e.getPageX(),
20687 toString: function() {
20688 return ("DD " + this.id);
20691 //////////////////////////////////////////////////////////////////////////
20692 // Debugging ygDragDrop events that can be overridden
20693 //////////////////////////////////////////////////////////////////////////
20695 startDrag: function(x, y) {
20698 onDrag: function(e) {
20701 onDragEnter: function(e, id) {
20704 onDragOver: function(e, id) {
20707 onDragOut: function(e, id) {
20710 onDragDrop: function(e, id) {
20713 endDrag: function(e) {
20720 * Ext JS Library 1.1.1
20721 * Copyright(c) 2006-2007, Ext JS, LLC.
20723 * Originally Released Under LGPL - original licence link has changed is not relivant.
20726 * <script type="text/javascript">
20730 * @class Roo.dd.DDProxy
20731 * A DragDrop implementation that inserts an empty, bordered div into
20732 * the document that follows the cursor during drag operations. At the time of
20733 * the click, the frame div is resized to the dimensions of the linked html
20734 * element, and moved to the exact location of the linked element.
20736 * References to the "frame" element refer to the single proxy element that
20737 * was created to be dragged in place of all DDProxy elements on the
20740 * @extends Roo.dd.DD
20742 * @param {String} id the id of the linked html element
20743 * @param {String} sGroup the group of related DragDrop objects
20744 * @param {object} config an object containing configurable attributes
20745 * Valid properties for DDProxy in addition to those in DragDrop:
20746 * resizeFrame, centerFrame, dragElId
20748 Roo.dd.DDProxy = function(id, sGroup, config) {
20750 this.init(id, sGroup, config);
20756 * The default drag frame div id
20757 * @property Roo.dd.DDProxy.dragElId
20761 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20763 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20766 * By default we resize the drag frame to be the same size as the element
20767 * we want to drag (this is to get the frame effect). We can turn it off
20768 * if we want a different behavior.
20769 * @property resizeFrame
20775 * By default the frame is positioned exactly where the drag element is, so
20776 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
20777 * you do not have constraints on the obj is to have the drag frame centered
20778 * around the cursor. Set centerFrame to true for this effect.
20779 * @property centerFrame
20782 centerFrame: false,
20785 * Creates the proxy element if it does not yet exist
20786 * @method createFrame
20788 createFrame: function() {
20790 var body = document.body;
20792 if (!body || !body.firstChild) {
20793 setTimeout( function() { self.createFrame(); }, 50 );
20797 var div = this.getDragEl();
20800 div = document.createElement("div");
20801 div.id = this.dragElId;
20804 s.position = "absolute";
20805 s.visibility = "hidden";
20807 s.border = "2px solid #aaa";
20810 // appendChild can blow up IE if invoked prior to the window load event
20811 // while rendering a table. It is possible there are other scenarios
20812 // that would cause this to happen as well.
20813 body.insertBefore(div, body.firstChild);
20818 * Initialization for the drag frame element. Must be called in the
20819 * constructor of all subclasses
20820 * @method initFrame
20822 initFrame: function() {
20823 this.createFrame();
20826 applyConfig: function() {
20827 Roo.dd.DDProxy.superclass.applyConfig.call(this);
20829 this.resizeFrame = (this.config.resizeFrame !== false);
20830 this.centerFrame = (this.config.centerFrame);
20831 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20835 * Resizes the drag frame to the dimensions of the clicked object, positions
20836 * it over the object, and finally displays it
20837 * @method showFrame
20838 * @param {int} iPageX X click position
20839 * @param {int} iPageY Y click position
20842 showFrame: function(iPageX, iPageY) {
20843 var el = this.getEl();
20844 var dragEl = this.getDragEl();
20845 var s = dragEl.style;
20847 this._resizeProxy();
20849 if (this.centerFrame) {
20850 this.setDelta( Math.round(parseInt(s.width, 10)/2),
20851 Math.round(parseInt(s.height, 10)/2) );
20854 this.setDragElPos(iPageX, iPageY);
20856 Roo.fly(dragEl).show();
20860 * The proxy is automatically resized to the dimensions of the linked
20861 * element when a drag is initiated, unless resizeFrame is set to false
20862 * @method _resizeProxy
20865 _resizeProxy: function() {
20866 if (this.resizeFrame) {
20867 var el = this.getEl();
20868 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20872 // overrides Roo.dd.DragDrop
20873 b4MouseDown: function(e) {
20874 var x = e.getPageX();
20875 var y = e.getPageY();
20876 this.autoOffset(x, y);
20877 this.setDragElPos(x, y);
20880 // overrides Roo.dd.DragDrop
20881 b4StartDrag: function(x, y) {
20882 // show the drag frame
20883 this.showFrame(x, y);
20886 // overrides Roo.dd.DragDrop
20887 b4EndDrag: function(e) {
20888 Roo.fly(this.getDragEl()).hide();
20891 // overrides Roo.dd.DragDrop
20892 // By default we try to move the element to the last location of the frame.
20893 // This is so that the default behavior mirrors that of Roo.dd.DD.
20894 endDrag: function(e) {
20896 var lel = this.getEl();
20897 var del = this.getDragEl();
20899 // Show the drag frame briefly so we can get its position
20900 del.style.visibility = "";
20903 // Hide the linked element before the move to get around a Safari
20905 lel.style.visibility = "hidden";
20906 Roo.dd.DDM.moveToEl(lel, del);
20907 del.style.visibility = "hidden";
20908 lel.style.visibility = "";
20913 beforeMove : function(){
20917 afterDrag : function(){
20921 toString: function() {
20922 return ("DDProxy " + this.id);
20928 * Ext JS Library 1.1.1
20929 * Copyright(c) 2006-2007, Ext JS, LLC.
20931 * Originally Released Under LGPL - original licence link has changed is not relivant.
20934 * <script type="text/javascript">
20938 * @class Roo.dd.DDTarget
20939 * A DragDrop implementation that does not move, but can be a drop
20940 * target. You would get the same result by simply omitting implementation
20941 * for the event callbacks, but this way we reduce the processing cost of the
20942 * event listener and the callbacks.
20943 * @extends Roo.dd.DragDrop
20945 * @param {String} id the id of the element that is a drop target
20946 * @param {String} sGroup the group of related DragDrop objects
20947 * @param {object} config an object containing configurable attributes
20948 * Valid properties for DDTarget in addition to those in
20952 Roo.dd.DDTarget = function(id, sGroup, config) {
20954 this.initTarget(id, sGroup, config);
20956 if (config.listeners || config.events) {
20957 Roo.dd.DragDrop.superclass.constructor.call(this, {
20958 listeners : config.listeners || {},
20959 events : config.events || {}
20964 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20965 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20966 toString: function() {
20967 return ("DDTarget " + this.id);
20972 * Ext JS Library 1.1.1
20973 * Copyright(c) 2006-2007, Ext JS, LLC.
20975 * Originally Released Under LGPL - original licence link has changed is not relivant.
20978 * <script type="text/javascript">
20983 * @class Roo.dd.ScrollManager
20984 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
20985 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
20988 Roo.dd.ScrollManager = function(){
20989 var ddm = Roo.dd.DragDropMgr;
20996 var onStop = function(e){
21001 var triggerRefresh = function(){
21002 if(ddm.dragCurrent){
21003 ddm.refreshCache(ddm.dragCurrent.groups);
21007 var doScroll = function(){
21008 if(ddm.dragCurrent){
21009 var dds = Roo.dd.ScrollManager;
21011 if(proc.el.scroll(proc.dir, dds.increment)){
21015 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21020 var clearProc = function(){
21022 clearInterval(proc.id);
21029 var startProc = function(el, dir){
21030 Roo.log('scroll startproc');
21034 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21037 var onFire = function(e, isDrop){
21039 if(isDrop || !ddm.dragCurrent){ return; }
21040 var dds = Roo.dd.ScrollManager;
21041 if(!dragEl || dragEl != ddm.dragCurrent){
21042 dragEl = ddm.dragCurrent;
21043 // refresh regions on drag start
21044 dds.refreshCache();
21047 var xy = Roo.lib.Event.getXY(e);
21048 var pt = new Roo.lib.Point(xy[0], xy[1]);
21049 for(var id in els){
21050 var el = els[id], r = el._region;
21051 if(r && r.contains(pt) && el.isScrollable()){
21052 if(r.bottom - pt.y <= dds.thresh){
21054 startProc(el, "down");
21057 }else if(r.right - pt.x <= dds.thresh){
21059 startProc(el, "left");
21062 }else if(pt.y - r.top <= dds.thresh){
21064 startProc(el, "up");
21067 }else if(pt.x - r.left <= dds.thresh){
21069 startProc(el, "right");
21078 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21079 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21083 * Registers new overflow element(s) to auto scroll
21084 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21086 register : function(el){
21087 if(el instanceof Array){
21088 for(var i = 0, len = el.length; i < len; i++) {
21089 this.register(el[i]);
21095 Roo.dd.ScrollManager.els = els;
21099 * Unregisters overflow element(s) so they are no longer scrolled
21100 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21102 unregister : function(el){
21103 if(el instanceof Array){
21104 for(var i = 0, len = el.length; i < len; i++) {
21105 this.unregister(el[i]);
21114 * The number of pixels from the edge of a container the pointer needs to be to
21115 * trigger scrolling (defaults to 25)
21121 * The number of pixels to scroll in each scroll increment (defaults to 50)
21127 * The frequency of scrolls in milliseconds (defaults to 500)
21133 * True to animate the scroll (defaults to true)
21139 * The animation duration in seconds -
21140 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21146 * Manually trigger a cache refresh.
21148 refreshCache : function(){
21149 for(var id in els){
21150 if(typeof els[id] == 'object'){ // for people extending the object prototype
21151 els[id]._region = els[id].getRegion();
21158 * Ext JS Library 1.1.1
21159 * Copyright(c) 2006-2007, Ext JS, LLC.
21161 * Originally Released Under LGPL - original licence link has changed is not relivant.
21164 * <script type="text/javascript">
21169 * @class Roo.dd.Registry
21170 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
21171 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21174 Roo.dd.Registry = function(){
21177 var autoIdSeed = 0;
21179 var getId = function(el, autogen){
21180 if(typeof el == "string"){
21184 if(!id && autogen !== false){
21185 id = "roodd-" + (++autoIdSeed);
21193 * Register a drag drop element
21194 * @param {String|HTMLElement} element The id or DOM node to register
21195 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21196 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
21197 * knows how to interpret, plus there are some specific properties known to the Registry that should be
21198 * populated in the data object (if applicable):
21200 Value Description<br />
21201 --------- ------------------------------------------<br />
21202 handles Array of DOM nodes that trigger dragging<br />
21203 for the element being registered<br />
21204 isHandle True if the element passed in triggers<br />
21205 dragging itself, else false
21208 register : function(el, data){
21210 if(typeof el == "string"){
21211 el = document.getElementById(el);
21214 elements[getId(el)] = data;
21215 if(data.isHandle !== false){
21216 handles[data.ddel.id] = data;
21219 var hs = data.handles;
21220 for(var i = 0, len = hs.length; i < len; i++){
21221 handles[getId(hs[i])] = data;
21227 * Unregister a drag drop element
21228 * @param {String|HTMLElement} element The id or DOM node to unregister
21230 unregister : function(el){
21231 var id = getId(el, false);
21232 var data = elements[id];
21234 delete elements[id];
21236 var hs = data.handles;
21237 for(var i = 0, len = hs.length; i < len; i++){
21238 delete handles[getId(hs[i], false)];
21245 * Returns the handle registered for a DOM Node by id
21246 * @param {String|HTMLElement} id The DOM node or id to look up
21247 * @return {Object} handle The custom handle data
21249 getHandle : function(id){
21250 if(typeof id != "string"){ // must be element?
21253 return handles[id];
21257 * Returns the handle that is registered for the DOM node that is the target of the event
21258 * @param {Event} e The event
21259 * @return {Object} handle The custom handle data
21261 getHandleFromEvent : function(e){
21262 var t = Roo.lib.Event.getTarget(e);
21263 return t ? handles[t.id] : null;
21267 * Returns a custom data object that is registered for a DOM node by id
21268 * @param {String|HTMLElement} id The DOM node or id to look up
21269 * @return {Object} data The custom data
21271 getTarget : function(id){
21272 if(typeof id != "string"){ // must be element?
21275 return elements[id];
21279 * Returns a custom data object that is registered for the DOM node that is the target of the event
21280 * @param {Event} e The event
21281 * @return {Object} data The custom data
21283 getTargetFromEvent : function(e){
21284 var t = Roo.lib.Event.getTarget(e);
21285 return t ? elements[t.id] || handles[t.id] : null;
21290 * Ext JS Library 1.1.1
21291 * Copyright(c) 2006-2007, Ext JS, LLC.
21293 * Originally Released Under LGPL - original licence link has changed is not relivant.
21296 * <script type="text/javascript">
21301 * @class Roo.dd.StatusProxy
21302 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
21303 * default drag proxy used by all Roo.dd components.
21305 * @param {Object} config
21307 Roo.dd.StatusProxy = function(config){
21308 Roo.apply(this, config);
21309 this.id = this.id || Roo.id();
21310 this.el = new Roo.Layer({
21312 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21313 {tag: "div", cls: "x-dd-drop-icon"},
21314 {tag: "div", cls: "x-dd-drag-ghost"}
21317 shadow: !config || config.shadow !== false
21319 this.ghost = Roo.get(this.el.dom.childNodes[1]);
21320 this.dropStatus = this.dropNotAllowed;
21323 Roo.dd.StatusProxy.prototype = {
21325 * @cfg {String} dropAllowed
21326 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21328 dropAllowed : "x-dd-drop-ok",
21330 * @cfg {String} dropNotAllowed
21331 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21333 dropNotAllowed : "x-dd-drop-nodrop",
21336 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21337 * over the current target element.
21338 * @param {String} cssClass The css class for the new drop status indicator image
21340 setStatus : function(cssClass){
21341 cssClass = cssClass || this.dropNotAllowed;
21342 if(this.dropStatus != cssClass){
21343 this.el.replaceClass(this.dropStatus, cssClass);
21344 this.dropStatus = cssClass;
21349 * Resets the status indicator to the default dropNotAllowed value
21350 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21352 reset : function(clearGhost){
21353 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21354 this.dropStatus = this.dropNotAllowed;
21356 this.ghost.update("");
21361 * Updates the contents of the ghost element
21362 * @param {String} html The html that will replace the current innerHTML of the ghost element
21364 update : function(html){
21365 if(typeof html == "string"){
21366 this.ghost.update(html);
21368 this.ghost.update("");
21369 html.style.margin = "0";
21370 this.ghost.dom.appendChild(html);
21372 // ensure float = none set?? cant remember why though.
21373 var el = this.ghost.dom.firstChild;
21375 Roo.fly(el).setStyle('float', 'none');
21380 * Returns the underlying proxy {@link Roo.Layer}
21381 * @return {Roo.Layer} el
21383 getEl : function(){
21388 * Returns the ghost element
21389 * @return {Roo.Element} el
21391 getGhost : function(){
21397 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21399 hide : function(clear){
21407 * Stops the repair animation if it's currently running
21410 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21416 * Displays this proxy
21423 * Force the Layer to sync its shadow and shim positions to the element
21430 * Causes the proxy to return to its position of origin via an animation. Should be called after an
21431 * invalid drop operation by the item being dragged.
21432 * @param {Array} xy The XY position of the element ([x, y])
21433 * @param {Function} callback The function to call after the repair is complete
21434 * @param {Object} scope The scope in which to execute the callback
21436 repair : function(xy, callback, scope){
21437 this.callback = callback;
21438 this.scope = scope;
21439 if(xy && this.animRepair !== false){
21440 this.el.addClass("x-dd-drag-repair");
21441 this.el.hideUnders(true);
21442 this.anim = this.el.shift({
21443 duration: this.repairDuration || .5,
21447 callback: this.afterRepair,
21451 this.afterRepair();
21456 afterRepair : function(){
21458 if(typeof this.callback == "function"){
21459 this.callback.call(this.scope || this);
21461 this.callback = null;
21466 * Ext JS Library 1.1.1
21467 * Copyright(c) 2006-2007, Ext JS, LLC.
21469 * Originally Released Under LGPL - original licence link has changed is not relivant.
21472 * <script type="text/javascript">
21476 * @class Roo.dd.DragSource
21477 * @extends Roo.dd.DDProxy
21478 * A simple class that provides the basic implementation needed to make any element draggable.
21480 * @param {String/HTMLElement/Element} el The container element
21481 * @param {Object} config
21483 Roo.dd.DragSource = function(el, config){
21484 this.el = Roo.get(el);
21485 this.dragData = {};
21487 Roo.apply(this, config);
21490 this.proxy = new Roo.dd.StatusProxy();
21493 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21494 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21496 this.dragging = false;
21499 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21501 * @cfg {String} dropAllowed
21502 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21504 dropAllowed : "x-dd-drop-ok",
21506 * @cfg {String} dropNotAllowed
21507 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21509 dropNotAllowed : "x-dd-drop-nodrop",
21512 * Returns the data object associated with this drag source
21513 * @return {Object} data An object containing arbitrary data
21515 getDragData : function(e){
21516 return this.dragData;
21520 onDragEnter : function(e, id){
21521 var target = Roo.dd.DragDropMgr.getDDById(id);
21522 this.cachedTarget = target;
21523 if(this.beforeDragEnter(target, e, id) !== false){
21524 if(target.isNotifyTarget){
21525 var status = target.notifyEnter(this, e, this.dragData);
21526 this.proxy.setStatus(status);
21528 this.proxy.setStatus(this.dropAllowed);
21531 if(this.afterDragEnter){
21533 * An empty function by default, but provided so that you can perform a custom action
21534 * when the dragged item enters the drop target by providing an implementation.
21535 * @param {Roo.dd.DragDrop} target The drop target
21536 * @param {Event} e The event object
21537 * @param {String} id The id of the dragged element
21538 * @method afterDragEnter
21540 this.afterDragEnter(target, e, id);
21546 * An empty function by default, but provided so that you can perform a custom action
21547 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21548 * @param {Roo.dd.DragDrop} target The drop target
21549 * @param {Event} e The event object
21550 * @param {String} id The id of the dragged element
21551 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21553 beforeDragEnter : function(target, e, id){
21558 alignElWithMouse: function() {
21559 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21564 onDragOver : function(e, id){
21565 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21566 if(this.beforeDragOver(target, e, id) !== false){
21567 if(target.isNotifyTarget){
21568 var status = target.notifyOver(this, e, this.dragData);
21569 this.proxy.setStatus(status);
21572 if(this.afterDragOver){
21574 * An empty function by default, but provided so that you can perform a custom action
21575 * while the dragged item is over the drop target by providing an implementation.
21576 * @param {Roo.dd.DragDrop} target The drop target
21577 * @param {Event} e The event object
21578 * @param {String} id The id of the dragged element
21579 * @method afterDragOver
21581 this.afterDragOver(target, e, id);
21587 * An empty function by default, but provided so that you can perform a custom action
21588 * while the dragged item is over the drop target and optionally cancel the onDragOver.
21589 * @param {Roo.dd.DragDrop} target The drop target
21590 * @param {Event} e The event object
21591 * @param {String} id The id of the dragged element
21592 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21594 beforeDragOver : function(target, e, id){
21599 onDragOut : function(e, id){
21600 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21601 if(this.beforeDragOut(target, e, id) !== false){
21602 if(target.isNotifyTarget){
21603 target.notifyOut(this, e, this.dragData);
21605 this.proxy.reset();
21606 if(this.afterDragOut){
21608 * An empty function by default, but provided so that you can perform a custom action
21609 * after the dragged item is dragged out of the target without dropping.
21610 * @param {Roo.dd.DragDrop} target The drop target
21611 * @param {Event} e The event object
21612 * @param {String} id The id of the dragged element
21613 * @method afterDragOut
21615 this.afterDragOut(target, e, id);
21618 this.cachedTarget = null;
21622 * An empty function by default, but provided so that you can perform a custom action before the dragged
21623 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21624 * @param {Roo.dd.DragDrop} target The drop target
21625 * @param {Event} e The event object
21626 * @param {String} id The id of the dragged element
21627 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21629 beforeDragOut : function(target, e, id){
21634 onDragDrop : function(e, id){
21635 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21636 if(this.beforeDragDrop(target, e, id) !== false){
21637 if(target.isNotifyTarget){
21638 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21639 this.onValidDrop(target, e, id);
21641 this.onInvalidDrop(target, e, id);
21644 this.onValidDrop(target, e, id);
21647 if(this.afterDragDrop){
21649 * An empty function by default, but provided so that you can perform a custom action
21650 * after a valid drag drop has occurred by providing an implementation.
21651 * @param {Roo.dd.DragDrop} target The drop target
21652 * @param {Event} e The event object
21653 * @param {String} id The id of the dropped element
21654 * @method afterDragDrop
21656 this.afterDragDrop(target, e, id);
21659 delete this.cachedTarget;
21663 * An empty function by default, but provided so that you can perform a custom action before the dragged
21664 * item is dropped onto the target and optionally cancel the onDragDrop.
21665 * @param {Roo.dd.DragDrop} target The drop target
21666 * @param {Event} e The event object
21667 * @param {String} id The id of the dragged element
21668 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21670 beforeDragDrop : function(target, e, id){
21675 onValidDrop : function(target, e, id){
21677 if(this.afterValidDrop){
21679 * An empty function by default, but provided so that you can perform a custom action
21680 * after a valid drop has occurred by providing an implementation.
21681 * @param {Object} target The target DD
21682 * @param {Event} e The event object
21683 * @param {String} id The id of the dropped element
21684 * @method afterInvalidDrop
21686 this.afterValidDrop(target, e, id);
21691 getRepairXY : function(e, data){
21692 return this.el.getXY();
21696 onInvalidDrop : function(target, e, id){
21697 this.beforeInvalidDrop(target, e, id);
21698 if(this.cachedTarget){
21699 if(this.cachedTarget.isNotifyTarget){
21700 this.cachedTarget.notifyOut(this, e, this.dragData);
21702 this.cacheTarget = null;
21704 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21706 if(this.afterInvalidDrop){
21708 * An empty function by default, but provided so that you can perform a custom action
21709 * after an invalid drop has occurred by providing an implementation.
21710 * @param {Event} e The event object
21711 * @param {String} id The id of the dropped element
21712 * @method afterInvalidDrop
21714 this.afterInvalidDrop(e, id);
21719 afterRepair : function(){
21721 this.el.highlight(this.hlColor || "c3daf9");
21723 this.dragging = false;
21727 * An empty function by default, but provided so that you can perform a custom action after an invalid
21728 * drop has occurred.
21729 * @param {Roo.dd.DragDrop} target The drop target
21730 * @param {Event} e The event object
21731 * @param {String} id The id of the dragged element
21732 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21734 beforeInvalidDrop : function(target, e, id){
21739 handleMouseDown : function(e){
21740 if(this.dragging) {
21743 var data = this.getDragData(e);
21744 if(data && this.onBeforeDrag(data, e) !== false){
21745 this.dragData = data;
21747 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21752 * An empty function by default, but provided so that you can perform a custom action before the initial
21753 * drag event begins and optionally cancel it.
21754 * @param {Object} data An object containing arbitrary data to be shared with drop targets
21755 * @param {Event} e The event object
21756 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21758 onBeforeDrag : function(data, e){
21763 * An empty function by default, but provided so that you can perform a custom action once the initial
21764 * drag event has begun. The drag cannot be canceled from this function.
21765 * @param {Number} x The x position of the click on the dragged object
21766 * @param {Number} y The y position of the click on the dragged object
21768 onStartDrag : Roo.emptyFn,
21770 // private - YUI override
21771 startDrag : function(x, y){
21772 this.proxy.reset();
21773 this.dragging = true;
21774 this.proxy.update("");
21775 this.onInitDrag(x, y);
21780 onInitDrag : function(x, y){
21781 var clone = this.el.dom.cloneNode(true);
21782 clone.id = Roo.id(); // prevent duplicate ids
21783 this.proxy.update(clone);
21784 this.onStartDrag(x, y);
21789 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21790 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21792 getProxy : function(){
21797 * Hides the drag source's {@link Roo.dd.StatusProxy}
21799 hideProxy : function(){
21801 this.proxy.reset(true);
21802 this.dragging = false;
21806 triggerCacheRefresh : function(){
21807 Roo.dd.DDM.refreshCache(this.groups);
21810 // private - override to prevent hiding
21811 b4EndDrag: function(e) {
21814 // private - override to prevent moving
21815 endDrag : function(e){
21816 this.onEndDrag(this.dragData, e);
21820 onEndDrag : function(data, e){
21823 // private - pin to cursor
21824 autoOffset : function(x, y) {
21825 this.setDelta(-12, -20);
21829 * Ext JS Library 1.1.1
21830 * Copyright(c) 2006-2007, Ext JS, LLC.
21832 * Originally Released Under LGPL - original licence link has changed is not relivant.
21835 * <script type="text/javascript">
21840 * @class Roo.dd.DropTarget
21841 * @extends Roo.dd.DDTarget
21842 * A simple class that provides the basic implementation needed to make any element a drop target that can have
21843 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
21845 * @param {String/HTMLElement/Element} el The container element
21846 * @param {Object} config
21848 Roo.dd.DropTarget = function(el, config){
21849 this.el = Roo.get(el);
21851 var listeners = false; ;
21852 if (config && config.listeners) {
21853 listeners= config.listeners;
21854 delete config.listeners;
21856 Roo.apply(this, config);
21858 if(this.containerScroll){
21859 Roo.dd.ScrollManager.register(this.el);
21863 * @scope Roo.dd.DropTarget
21868 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21869 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
21870 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
21872 * IMPORTANT : it should set this.overClass and this.dropAllowed
21874 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21875 * @param {Event} e The event
21876 * @param {Object} data An object containing arbitrary data supplied by the drag source
21882 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21883 * This method will be called on every mouse movement while the drag source is over the drop target.
21884 * This default implementation simply returns the dropAllowed config value.
21886 * IMPORTANT : it should set this.dropAllowed
21888 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21889 * @param {Event} e The event
21890 * @param {Object} data An object containing arbitrary data supplied by the drag source
21896 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21897 * out of the target without dropping. This default implementation simply removes the CSS class specified by
21898 * overClass (if any) from the drop element.
21900 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21901 * @param {Event} e The event
21902 * @param {Object} data An object containing arbitrary data supplied by the drag source
21908 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21909 * been dropped on it. This method has no default implementation and returns false, so you must provide an
21910 * implementation that does something to process the drop event and returns true so that the drag source's
21911 * repair action does not run.
21913 * IMPORTANT : it should set this.success
21915 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21916 * @param {Event} e The event
21917 * @param {Object} data An object containing arbitrary data supplied by the drag source
21923 Roo.dd.DropTarget.superclass.constructor.call( this,
21925 this.ddGroup || this.group,
21928 listeners : listeners || {}
21936 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21938 * @cfg {String} overClass
21939 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21942 * @cfg {String} ddGroup
21943 * The drag drop group to handle drop events for
21947 * @cfg {String} dropAllowed
21948 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21950 dropAllowed : "x-dd-drop-ok",
21952 * @cfg {String} dropNotAllowed
21953 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21955 dropNotAllowed : "x-dd-drop-nodrop",
21957 * @cfg {boolean} success
21958 * set this after drop listener..
21962 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21963 * if the drop point is valid for over/enter..
21970 isNotifyTarget : true,
21975 notifyEnter : function(dd, e, data)
21978 this.fireEvent('enter', dd, e, data);
21979 if(this.overClass){
21980 this.el.addClass(this.overClass);
21982 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
21983 this.valid ? this.dropAllowed : this.dropNotAllowed
21990 notifyOver : function(dd, e, data)
21993 this.fireEvent('over', dd, e, data);
21994 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
21995 this.valid ? this.dropAllowed : this.dropNotAllowed
22002 notifyOut : function(dd, e, data)
22004 this.fireEvent('out', dd, e, data);
22005 if(this.overClass){
22006 this.el.removeClass(this.overClass);
22013 notifyDrop : function(dd, e, data)
22015 this.success = false;
22016 this.fireEvent('drop', dd, e, data);
22017 return this.success;
22021 * Ext JS Library 1.1.1
22022 * Copyright(c) 2006-2007, Ext JS, LLC.
22024 * Originally Released Under LGPL - original licence link has changed is not relivant.
22027 * <script type="text/javascript">
22032 * @class Roo.dd.DragZone
22033 * @extends Roo.dd.DragSource
22034 * This class provides a container DD instance that proxies for multiple child node sources.<br />
22035 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22037 * @param {String/HTMLElement/Element} el The container element
22038 * @param {Object} config
22040 Roo.dd.DragZone = function(el, config){
22041 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22042 if(this.containerScroll){
22043 Roo.dd.ScrollManager.register(this.el);
22047 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22049 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22050 * for auto scrolling during drag operations.
22053 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22054 * method after a failed drop (defaults to "c3daf9" - light blue)
22058 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22059 * for a valid target to drag based on the mouse down. Override this method
22060 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22061 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22062 * @param {EventObject} e The mouse down event
22063 * @return {Object} The dragData
22065 getDragData : function(e){
22066 return Roo.dd.Registry.getHandleFromEvent(e);
22070 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22071 * this.dragData.ddel
22072 * @param {Number} x The x position of the click on the dragged object
22073 * @param {Number} y The y position of the click on the dragged object
22074 * @return {Boolean} true to continue the drag, false to cancel
22076 onInitDrag : function(x, y){
22077 this.proxy.update(this.dragData.ddel.cloneNode(true));
22078 this.onStartDrag(x, y);
22083 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
22085 afterRepair : function(){
22087 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22089 this.dragging = false;
22093 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22094 * the XY of this.dragData.ddel
22095 * @param {EventObject} e The mouse up event
22096 * @return {Array} The xy location (e.g. [100, 200])
22098 getRepairXY : function(e){
22099 return Roo.Element.fly(this.dragData.ddel).getXY();
22103 * Ext JS Library 1.1.1
22104 * Copyright(c) 2006-2007, Ext JS, LLC.
22106 * Originally Released Under LGPL - original licence link has changed is not relivant.
22109 * <script type="text/javascript">
22112 * @class Roo.dd.DropZone
22113 * @extends Roo.dd.DropTarget
22114 * This class provides a container DD instance that proxies for multiple child node targets.<br />
22115 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22117 * @param {String/HTMLElement/Element} el The container element
22118 * @param {Object} config
22120 Roo.dd.DropZone = function(el, config){
22121 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22124 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22126 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22127 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22128 * provide your own custom lookup.
22129 * @param {Event} e The event
22130 * @return {Object} data The custom data
22132 getTargetFromEvent : function(e){
22133 return Roo.dd.Registry.getTargetFromEvent(e);
22137 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22138 * that it has registered. This method has no default implementation and should be overridden to provide
22139 * node-specific processing if necessary.
22140 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22141 * {@link #getTargetFromEvent} for this node)
22142 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22143 * @param {Event} e The event
22144 * @param {Object} data An object containing arbitrary data supplied by the drag source
22146 onNodeEnter : function(n, dd, e, data){
22151 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22152 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
22153 * overridden to provide the proper feedback.
22154 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22155 * {@link #getTargetFromEvent} for this node)
22156 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22157 * @param {Event} e The event
22158 * @param {Object} data An object containing arbitrary data supplied by the drag source
22159 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22160 * underlying {@link Roo.dd.StatusProxy} can be updated
22162 onNodeOver : function(n, dd, e, data){
22163 return this.dropAllowed;
22167 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22168 * the drop node without dropping. This method has no default implementation and should be overridden to provide
22169 * node-specific processing if necessary.
22170 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22171 * {@link #getTargetFromEvent} for this node)
22172 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22173 * @param {Event} e The event
22174 * @param {Object} data An object containing arbitrary data supplied by the drag source
22176 onNodeOut : function(n, dd, e, data){
22181 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22182 * the drop node. The default implementation returns false, so it should be overridden to provide the
22183 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22184 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22185 * {@link #getTargetFromEvent} for this node)
22186 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22187 * @param {Event} e The event
22188 * @param {Object} data An object containing arbitrary data supplied by the drag source
22189 * @return {Boolean} True if the drop was valid, else false
22191 onNodeDrop : function(n, dd, e, data){
22196 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22197 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
22198 * it should be overridden to provide the proper feedback if necessary.
22199 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22200 * @param {Event} e The event
22201 * @param {Object} data An object containing arbitrary data supplied by the drag source
22202 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22203 * underlying {@link Roo.dd.StatusProxy} can be updated
22205 onContainerOver : function(dd, e, data){
22206 return this.dropNotAllowed;
22210 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22211 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
22212 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22213 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
22214 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22215 * @param {Event} e The event
22216 * @param {Object} data An object containing arbitrary data supplied by the drag source
22217 * @return {Boolean} True if the drop was valid, else false
22219 onContainerDrop : function(dd, e, data){
22224 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22225 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
22226 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22227 * you should override this method and provide a custom implementation.
22228 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22229 * @param {Event} e The event
22230 * @param {Object} data An object containing arbitrary data supplied by the drag source
22231 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22232 * underlying {@link Roo.dd.StatusProxy} can be updated
22234 notifyEnter : function(dd, e, data){
22235 return this.dropNotAllowed;
22239 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22240 * This method will be called on every mouse movement while the drag source is over the drop zone.
22241 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22242 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22243 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22244 * registered node, it will call {@link #onContainerOver}.
22245 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22246 * @param {Event} e The event
22247 * @param {Object} data An object containing arbitrary data supplied by the drag source
22248 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22249 * underlying {@link Roo.dd.StatusProxy} can be updated
22251 notifyOver : function(dd, e, data){
22252 var n = this.getTargetFromEvent(e);
22253 if(!n){ // not over valid drop target
22254 if(this.lastOverNode){
22255 this.onNodeOut(this.lastOverNode, dd, e, data);
22256 this.lastOverNode = null;
22258 return this.onContainerOver(dd, e, data);
22260 if(this.lastOverNode != n){
22261 if(this.lastOverNode){
22262 this.onNodeOut(this.lastOverNode, dd, e, data);
22264 this.onNodeEnter(n, dd, e, data);
22265 this.lastOverNode = n;
22267 return this.onNodeOver(n, dd, e, data);
22271 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22272 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
22273 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22274 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22275 * @param {Event} e The event
22276 * @param {Object} data An object containing arbitrary data supplied by the drag zone
22278 notifyOut : function(dd, e, data){
22279 if(this.lastOverNode){
22280 this.onNodeOut(this.lastOverNode, dd, e, data);
22281 this.lastOverNode = null;
22286 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22287 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
22288 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22289 * otherwise it will call {@link #onContainerDrop}.
22290 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22291 * @param {Event} e The event
22292 * @param {Object} data An object containing arbitrary data supplied by the drag source
22293 * @return {Boolean} True if the drop was valid, else false
22295 notifyDrop : function(dd, e, data){
22296 if(this.lastOverNode){
22297 this.onNodeOut(this.lastOverNode, dd, e, data);
22298 this.lastOverNode = null;
22300 var n = this.getTargetFromEvent(e);
22302 this.onNodeDrop(n, dd, e, data) :
22303 this.onContainerDrop(dd, e, data);
22307 triggerCacheRefresh : function(){
22308 Roo.dd.DDM.refreshCache(this.groups);