4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isFirefox = ua.indexOf("firefox") > -1,
57 isIE = ua.indexOf("msie") > -1,
58 isIE7 = ua.indexOf("msie 7") > -1,
59 isIE11 = /trident.*rv\:11\./.test(ua),
60 isEdge = ua.indexOf("edge") > -1,
61 isGecko = !isSafari && ua.indexOf("gecko") > -1,
62 isBorderBox = isIE && !isStrict,
63 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
64 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
65 isLinux = (ua.indexOf("linux") != -1),
66 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
67 isIOS = /iphone|ipad/.test(ua),
68 isAndroid = /android/.test(ua),
69 isTouch = (function() {
71 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
72 window.addEventListener('touchstart', function __set_has_touch__ () {
74 window.removeEventListener('touchstart', __set_has_touch__);
76 return false; // no touch on chrome!?
78 document.createEvent("TouchEvent");
85 // remove css image flicker
88 document.execCommand("BackgroundImageCache", false, true);
94 * True if the browser is in strict mode
99 * True if the page is running over SSL
104 * True when the document is fully initialized and ready for action
109 * Turn on debugging output (currently only the factory uses this)
116 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
119 enableGarbageCollector : true,
122 * True to automatically purge event listeners after uncaching an element (defaults to false).
123 * Note: this only happens if enableGarbageCollector is true.
126 enableListenerCollection:false,
129 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
130 * the IE insecure content warning (defaults to javascript:false).
133 SSL_SECURE_URL : "javascript:false",
136 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
137 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
140 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
142 emptyFn : function(){},
145 * Copies all the properties of config to obj if they don't already exist.
146 * @param {Object} obj The receiver of the properties
147 * @param {Object} config The source of the properties
148 * @return {Object} returns obj
150 applyIf : function(o, c){
153 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
160 * Applies event listeners to elements by selectors when the document is ready.
161 * The event name is specified with an @ suffix.
164 // add a listener for click on all anchors in element with id foo
165 '#foo a@click' : function(e, t){
169 // add the same listener to multiple selectors (separated by comma BEFORE the @)
170 '#foo a, #bar span.some-class@mouseover' : function(){
175 * @param {Object} obj The list of behaviors to apply
177 addBehaviors : function(o){
179 Roo.onReady(function(){
184 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
186 var parts = b.split('@');
187 if(parts[1]){ // for Object prototype breakers
190 cache[s] = Roo.select(s);
192 cache[s].on(parts[1], o[b]);
199 * Generates unique ids. If the element already has an id, it is unchanged
200 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
201 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
202 * @return {String} The generated Id.
204 id : function(el, prefix){
205 prefix = prefix || "roo-gen";
207 var id = prefix + (++idSeed);
208 return el ? (el.id ? el.id : (el.id = id)) : id;
213 * Extends one class with another class and optionally overrides members with the passed literal. This class
214 * also adds the function "override()" to the class that can be used to override
215 * members on an instance.
216 * @param {Object} subclass The class inheriting the functionality
217 * @param {Object} superclass The class being extended
218 * @param {Object} overrides (optional) A literal with members
223 var io = function(o){
228 return function(sb, sp, overrides){
229 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
232 sb = function(){sp.apply(this, arguments);};
234 var F = function(){}, sbp, spp = sp.prototype;
236 sbp = sb.prototype = new F();
240 if(spp.constructor == Object.prototype.constructor){
245 sb.override = function(o){
249 Roo.override(sb, overrides);
255 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
257 Roo.override(MyClass, {
258 newMethod1: function(){
261 newMethod2: function(foo){
266 * @param {Object} origclass The class to override
267 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
268 * containing one or more methods.
271 override : function(origclass, overrides){
273 var p = origclass.prototype;
274 for(var method in overrides){
275 p[method] = overrides[method];
280 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
282 Roo.namespace('Company', 'Company.data');
283 Company.Widget = function() { ... }
284 Company.data.CustomStore = function(config) { ... }
286 * @param {String} namespace1
287 * @param {String} namespace2
288 * @param {String} etc
291 namespace : function(){
292 var a=arguments, o=null, i, j, d, rt;
293 for (i=0; i<a.length; ++i) {
297 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
298 for (j=1; j<d.length; ++j) {
299 o[d[j]]=o[d[j]] || {};
305 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
307 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
308 Roo.factory(conf, Roo.data);
310 * @param {String} classname
311 * @param {String} namespace (optional)
315 factory : function(c, ns)
317 // no xtype, no ns or c.xns - or forced off by c.xns
318 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
321 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
322 if (c.constructor == ns[c.xtype]) {// already created...
326 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
327 var ret = new ns[c.xtype](c);
331 c.xns = false; // prevent recursion..
335 * Logs to console if it can.
337 * @param {String|Object} string
342 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
349 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
353 urlEncode : function(o){
359 var ov = o[key], k = Roo.encodeURIComponent(key);
360 var type = typeof ov;
361 if(type == 'undefined'){
363 }else if(type != "function" && type != "object"){
364 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
365 }else if(ov instanceof Array){
367 for(var i = 0, len = ov.length; i < len; i++) {
368 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
379 * Safe version of encodeURIComponent
380 * @param {String} data
384 encodeURIComponent : function (data)
387 return encodeURIComponent(data);
388 } catch(e) {} // should be an uri encode error.
390 if (data == '' || data == null){
393 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
394 function nibble_to_hex(nibble){
395 var chars = '0123456789ABCDEF';
396 return chars.charAt(nibble);
398 data = data.toString();
400 for(var i=0; i<data.length; i++){
401 var c = data.charCodeAt(i);
402 var bs = new Array();
405 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
406 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
407 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
408 bs[3] = 0x80 | (c & 0x3F);
409 }else if (c > 0x800){
411 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
412 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
413 bs[2] = 0x80 | (c & 0x3F);
416 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
417 bs[1] = 0x80 | (c & 0x3F);
422 for(var j=0; j<bs.length; j++){
424 var hex = nibble_to_hex((b & 0xF0) >>> 4)
425 + nibble_to_hex(b &0x0F);
434 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
435 * @param {String} string
436 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
437 * @return {Object} A literal with members
439 urlDecode : function(string, overwrite){
440 if(!string || !string.length){
444 var pairs = string.split('&');
445 var pair, name, value;
446 for(var i = 0, len = pairs.length; i < len; i++){
447 pair = pairs[i].split('=');
448 name = decodeURIComponent(pair[0]);
449 value = decodeURIComponent(pair[1]);
450 if(overwrite !== true){
451 if(typeof obj[name] == "undefined"){
453 }else if(typeof obj[name] == "string"){
454 obj[name] = [obj[name]];
455 obj[name].push(value);
457 obj[name].push(value);
467 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
468 * passed array is not really an array, your function is called once with it.
469 * The supplied function is called with (Object item, Number index, Array allItems).
470 * @param {Array/NodeList/Mixed} array
471 * @param {Function} fn
472 * @param {Object} scope
474 each : function(array, fn, scope){
475 if(typeof array.length == "undefined" || typeof array == "string"){
478 for(var i = 0, len = array.length; i < len; i++){
479 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
484 combine : function(){
485 var as = arguments, l = as.length, r = [];
486 for(var i = 0; i < l; i++){
488 if(a instanceof Array){
490 }else if(a.length !== undefined && !a.substr){
491 r = r.concat(Array.prototype.slice.call(a, 0));
500 * Escapes the passed string for use in a regular expression
501 * @param {String} str
504 escapeRe : function(s) {
505 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
509 callback : function(cb, scope, args, delay){
510 if(typeof cb == "function"){
512 cb.defer(delay, scope, args || []);
514 cb.apply(scope, args || []);
520 * Return the dom node for the passed string (id), dom node, or Roo.Element
521 * @param {String/HTMLElement/Roo.Element} el
522 * @return HTMLElement
524 getDom : function(el){
528 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
532 * Shorthand for {@link Roo.ComponentMgr#get}
534 * @return Roo.Component
536 getCmp : function(id){
537 return Roo.ComponentMgr.get(id);
540 num : function(v, defaultValue){
541 if(typeof v != 'number'){
547 destroy : function(){
548 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
552 as.removeAllListeners();
556 if(typeof as.purgeListeners == 'function'){
559 if(typeof as.destroy == 'function'){
566 // inpired by a similar function in mootools library
568 * Returns the type of object that is passed in. If the object passed in is null or undefined it
569 * return false otherwise it returns one of the following values:<ul>
570 * <li><b>string</b>: If the object passed is a string</li>
571 * <li><b>number</b>: If the object passed is a number</li>
572 * <li><b>boolean</b>: If the object passed is a boolean value</li>
573 * <li><b>function</b>: If the object passed is a function reference</li>
574 * <li><b>object</b>: If the object passed is an object</li>
575 * <li><b>array</b>: If the object passed is an array</li>
576 * <li><b>regexp</b>: If the object passed is a regular expression</li>
577 * <li><b>element</b>: If the object passed is a DOM Element</li>
578 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
579 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
580 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
581 * @param {Mixed} object
585 if(o === undefined || o === null){
592 if(t == 'object' && o.nodeName) {
594 case 1: return 'element';
595 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
598 if(t == 'object' || t == 'function') {
599 switch(o.constructor) {
600 case Array: return 'array';
601 case RegExp: return 'regexp';
603 if(typeof o.length == 'number' && typeof o.item == 'function') {
611 * Returns true if the passed value is null, undefined or an empty string (optional).
612 * @param {Mixed} value The value to test
613 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
616 isEmpty : function(v, allowBlank){
617 return v === null || v === undefined || (!allowBlank ? v === '' : false);
625 isFirefox : isFirefox,
637 isBorderBox : isBorderBox,
639 isWindows : isWindows,
647 isAndroid : isAndroid,
652 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
653 * you may want to set this to true.
656 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
661 * Selects a single element as a Roo Element
662 * This is about as close as you can get to jQuery's $('do crazy stuff')
663 * @param {String} selector The selector/xpath query
664 * @param {Node} root (optional) The start of the query (defaults to document).
665 * @return {Roo.Element}
667 selectNode : function(selector, root)
669 var node = Roo.DomQuery.selectNode(selector,root);
670 return node ? Roo.get(node) : new Roo.Element(false);
673 * Find the current bootstrap width Grid size
674 * Note xs is the default for smaller.. - this is currently used by grids to render correct columns
675 * @returns {String} (xs|sm|md|lg|xl)
678 getGridSize : function()
680 var w = Roo.lib.Dom.getViewWidth();
701 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
702 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
705 "Roo.bootstrap.dash");
708 * Ext JS Library 1.1.1
709 * Copyright(c) 2006-2007, Ext JS, LLC.
711 * Originally Released Under LGPL - original licence link has changed is not relivant.
714 * <script type="text/javascript">
718 // wrappedn so fnCleanup is not in global scope...
720 function fnCleanUp() {
721 var p = Function.prototype;
722 delete p.createSequence;
724 delete p.createDelegate;
725 delete p.createCallback;
726 delete p.createInterceptor;
728 window.detachEvent("onunload", fnCleanUp);
730 window.attachEvent("onunload", fnCleanUp);
737 * These functions are available on every Function object (any JavaScript function).
739 Roo.apply(Function.prototype, {
741 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
742 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
743 * Will create a function that is bound to those 2 args.
744 * @return {Function} The new function
746 createCallback : function(/*args...*/){
747 // make args available, in function below
748 var args = arguments;
751 return method.apply(window, args);
756 * Creates a delegate (callback) that sets the scope to obj.
757 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
758 * Will create a function that is automatically scoped to this.
759 * @param {Object} obj (optional) The object for which the scope is set
760 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
761 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
762 * if a number the args are inserted at the specified position
763 * @return {Function} The new function
765 createDelegate : function(obj, args, appendArgs){
768 var callArgs = args || arguments;
769 if(appendArgs === true){
770 callArgs = Array.prototype.slice.call(arguments, 0);
771 callArgs = callArgs.concat(args);
772 }else if(typeof appendArgs == "number"){
773 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
774 var applyArgs = [appendArgs, 0].concat(args); // create method call params
775 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
777 return method.apply(obj || window, callArgs);
782 * Calls this function after the number of millseconds specified.
783 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
784 * @param {Object} obj (optional) The object for which the scope is set
785 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
786 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
787 * if a number the args are inserted at the specified position
788 * @return {Number} The timeout id that can be used with clearTimeout
790 defer : function(millis, obj, args, appendArgs){
791 var fn = this.createDelegate(obj, args, appendArgs);
793 return setTimeout(fn, millis);
799 * Create a combined function call sequence of the original function + the passed function.
800 * The resulting function returns the results of the original function.
801 * The passed fcn is called with the parameters of the original function
802 * @param {Function} fcn The function to sequence
803 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
804 * @return {Function} The new function
806 createSequence : function(fcn, scope){
807 if(typeof fcn != "function"){
812 var retval = method.apply(this || window, arguments);
813 fcn.apply(scope || this || window, arguments);
819 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
820 * The resulting function returns the results of the original function.
821 * The passed fcn is called with the parameters of the original function.
823 * @param {Function} fcn The function to call before the original
824 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
825 * @return {Function} The new function
827 createInterceptor : function(fcn, scope){
828 if(typeof fcn != "function"){
835 if(fcn.apply(scope || this || window, arguments) === false){
838 return method.apply(this || window, arguments);
844 * Ext JS Library 1.1.1
845 * Copyright(c) 2006-2007, Ext JS, LLC.
847 * Originally Released Under LGPL - original licence link has changed is not relivant.
850 * <script type="text/javascript">
853 Roo.applyIf(String, {
858 * Escapes the passed string for ' and \
859 * @param {String} string The string to escape
860 * @return {String} The escaped string
863 escape : function(string) {
864 return string.replace(/('|\\)/g, "\\$1");
868 * Pads the left side of a string with a specified character. This is especially useful
869 * for normalizing number and date strings. Example usage:
871 var s = String.leftPad('123', 5, '0');
872 // s now contains the string: '00123'
874 * @param {String} string The original string
875 * @param {Number} size The total length of the output string
876 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
877 * @return {String} The padded string
880 leftPad : function (val, size, ch) {
881 var result = new String(val);
882 if(ch === null || ch === undefined || ch === '') {
885 while (result.length < size) {
886 result = ch + result;
892 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
893 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
895 var cls = 'my-class', text = 'Some text';
896 var s = String.format('<div class="{0}">{1}</div>', cls, text);
897 // s now contains the string: '<div class="my-class">Some text</div>'
899 * @param {String} string The tokenized string to be formatted
900 * @param {String} value1 The value to replace token {0}
901 * @param {String} value2 Etc...
902 * @return {String} The formatted string
905 format : function(format){
906 var args = Array.prototype.slice.call(arguments, 1);
907 return format.replace(/\{(\d+)\}/g, function(m, i){
908 return Roo.util.Format.htmlEncode(args[i]);
916 * Utility function that allows you to easily switch a string between two alternating values. The passed value
917 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
918 * they are already different, the first value passed in is returned. Note that this method returns the new value
919 * but does not change the current string.
921 // alternate sort directions
922 sort = sort.toggle('ASC', 'DESC');
924 // instead of conditional logic:
925 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
927 * @param {String} value The value to compare to the current string
928 * @param {String} other The new value to use if the string already equals the first value passed in
929 * @return {String} The new value
932 String.prototype.toggle = function(value, other){
933 return this == value ? other : value;
938 * Remove invalid unicode characters from a string
940 * @return {String} The clean string
942 String.prototype.unicodeClean = function () {
943 return this.replace(/[\s\S]/g,
944 function(character) {
945 if (character.charCodeAt()< 256) {
949 encodeURIComponent(character);
960 * Ext JS Library 1.1.1
961 * Copyright(c) 2006-2007, Ext JS, LLC.
963 * Originally Released Under LGPL - original licence link has changed is not relivant.
966 * <script type="text/javascript">
972 Roo.applyIf(Number.prototype, {
974 * Checks whether or not the current number is within a desired range. If the number is already within the
975 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
976 * exceeded. Note that this method returns the constrained value but does not change the current number.
977 * @param {Number} min The minimum number in the range
978 * @param {Number} max The maximum number in the range
979 * @return {Number} The constrained value if outside the range, otherwise the current value
981 constrain : function(min, max){
982 return Math.min(Math.max(this, min), max);
986 * Ext JS Library 1.1.1
987 * Copyright(c) 2006-2007, Ext JS, LLC.
989 * Originally Released Under LGPL - original licence link has changed is not relivant.
992 * <script type="text/javascript">
997 Roo.applyIf(Array.prototype, {
1000 * Checks whether or not the specified object exists in the array.
1001 * @param {Object} o The object to check for
1002 * @return {Number} The index of o in the array (or -1 if it is not found)
1004 indexOf : function(o){
1005 for (var i = 0, len = this.length; i < len; i++){
1006 if(this[i] == o) { return i; }
1012 * Removes the specified object from the array. If the object is not found nothing happens.
1013 * @param {Object} o The object to remove
1015 remove : function(o){
1016 var index = this.indexOf(o);
1018 this.splice(index, 1);
1022 * Map (JS 1.6 compatibility)
1023 * @param {Function} function to call
1025 map : function(fun )
1027 var len = this.length >>> 0;
1028 if (typeof fun != "function") {
1029 throw new TypeError();
1031 var res = new Array(len);
1032 var thisp = arguments[1];
1033 for (var i = 0; i < len; i++)
1036 res[i] = fun.call(thisp, this[i], i, this);
1044 * @param {Array} o The array to compare to
1045 * @returns {Boolean} true if the same
1047 equals : function(b)
1049 // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
1056 if (this.length !== b.length) {
1060 // sort?? a.sort().equals(b.sort());
1062 for (var i = 0; i < this.length; ++i) {
1063 if (this[i] !== b[i]) {
1075 Roo.applyIf(Array, {
1079 * @param {Array} o Or Array like object (eg. nodelist)
1086 for (var i =0; i < o.length; i++) {
1095 * Ext JS Library 1.1.1
1096 * Copyright(c) 2006-2007, Ext JS, LLC.
1098 * Originally Released Under LGPL - original licence link has changed is not relivant.
1101 * <script type="text/javascript">
1107 * The date parsing and format syntax is a subset of
1108 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1109 * supported will provide results equivalent to their PHP versions.
1111 * Following is the list of all currently supported formats:
1114 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1116 Format Output Description
1117 ------ ---------- --------------------------------------------------------------
1118 d 10 Day of the month, 2 digits with leading zeros
1119 D Wed A textual representation of a day, three letters
1120 j 10 Day of the month without leading zeros
1121 l Wednesday A full textual representation of the day of the week
1122 S th English ordinal day of month suffix, 2 chars (use with j)
1123 w 3 Numeric representation of the day of the week
1124 z 9 The julian date, or day of the year (0-365)
1125 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1126 F January A full textual representation of the month
1127 m 01 Numeric representation of a month, with leading zeros
1128 M Jan Month name abbreviation, three letters
1129 n 1 Numeric representation of a month, without leading zeros
1130 t 31 Number of days in the given month
1131 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1132 Y 2007 A full numeric representation of a year, 4 digits
1133 y 07 A two digit representation of a year
1134 a pm Lowercase Ante meridiem and Post meridiem
1135 A PM Uppercase Ante meridiem and Post meridiem
1136 g 3 12-hour format of an hour without leading zeros
1137 G 15 24-hour format of an hour without leading zeros
1138 h 03 12-hour format of an hour with leading zeros
1139 H 15 24-hour format of an hour with leading zeros
1140 i 05 Minutes with leading zeros
1141 s 01 Seconds, with leading zeros
1142 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1143 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1144 T CST Timezone setting of the machine running the code
1145 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1148 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1150 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1151 document.write(dt.format('Y-m-d')); //2007-01-10
1152 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1153 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
1156 * Here are some standard date/time patterns that you might find helpful. They
1157 * are not part of the source of Date.js, but to use them you can simply copy this
1158 * block of code into any script that is included after Date.js and they will also become
1159 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1162 ISO8601Long:"Y-m-d H:i:s",
1163 ISO8601Short:"Y-m-d",
1165 LongDate: "l, F d, Y",
1166 FullDateTime: "l, F d, Y g:i:s A",
1169 LongTime: "g:i:s A",
1170 SortableDateTime: "Y-m-d\\TH:i:s",
1171 UniversalSortableDateTime: "Y-m-d H:i:sO",
1178 var dt = new Date();
1179 document.write(dt.format(Date.patterns.ShortDate));
1184 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1185 * They generate precompiled functions from date formats instead of parsing and
1186 * processing the pattern every time you format a date. These functions are available
1187 * on every Date object (any javascript function).
1189 * The original article and download are here:
1190 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1197 Returns the number of milliseconds between this date and date
1198 @param {Date} date (optional) Defaults to now
1199 @return {Number} The diff in milliseconds
1200 @member Date getElapsed
1202 Date.prototype.getElapsed = function(date) {
1203 return Math.abs((date || new Date()).getTime()-this.getTime());
1205 // was in date file..
1209 Date.parseFunctions = {count:0};
1211 Date.parseRegexes = [];
1213 Date.formatFunctions = {count:0};
1216 Date.prototype.dateFormat = function(format) {
1217 if (Date.formatFunctions[format] == null) {
1218 Date.createNewFormat(format);
1220 var func = Date.formatFunctions[format];
1221 return this[func]();
1226 * Formats a date given the supplied format string
1227 * @param {String} format The format string
1228 * @return {String} The formatted date
1231 Date.prototype.format = Date.prototype.dateFormat;
1234 Date.createNewFormat = function(format) {
1235 var funcName = "format" + Date.formatFunctions.count++;
1236 Date.formatFunctions[format] = funcName;
1237 var code = "Date.prototype." + funcName + " = function(){return ";
1238 var special = false;
1240 for (var i = 0; i < format.length; ++i) {
1241 ch = format.charAt(i);
1242 if (!special && ch == "\\") {
1247 code += "'" + String.escape(ch) + "' + ";
1250 code += Date.getFormatCode(ch);
1253 /** eval:var:zzzzzzzzzzzzz */
1254 eval(code.substring(0, code.length - 3) + ";}");
1258 Date.getFormatCode = function(character) {
1259 switch (character) {
1261 return "String.leftPad(this.getDate(), 2, '0') + ";
1263 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1265 return "this.getDate() + ";
1267 return "Date.dayNames[this.getDay()] + ";
1269 return "this.getSuffix() + ";
1271 return "this.getDay() + ";
1273 return "this.getDayOfYear() + ";
1275 return "this.getWeekOfYear() + ";
1277 return "Date.monthNames[this.getMonth()] + ";
1279 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1281 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1283 return "(this.getMonth() + 1) + ";
1285 return "this.getDaysInMonth() + ";
1287 return "(this.isLeapYear() ? 1 : 0) + ";
1289 return "this.getFullYear() + ";
1291 return "('' + this.getFullYear()).substring(2, 4) + ";
1293 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1295 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1297 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1299 return "this.getHours() + ";
1301 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1303 return "String.leftPad(this.getHours(), 2, '0') + ";
1305 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1307 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1309 return "this.getGMTOffset() + ";
1311 return "this.getGMTColonOffset() + ";
1313 return "this.getTimezone() + ";
1315 return "(this.getTimezoneOffset() * -60) + ";
1317 return "'" + String.escape(character) + "' + ";
1322 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1323 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1324 * the date format that is not specified will default to the current date value for that part. Time parts can also
1325 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1326 * string or the parse operation will fail.
1329 //dt = Fri May 25 2007 (current date)
1330 var dt = new Date();
1332 //dt = Thu May 25 2006 (today's month/day in 2006)
1333 dt = Date.parseDate("2006", "Y");
1335 //dt = Sun Jan 15 2006 (all date parts specified)
1336 dt = Date.parseDate("2006-1-15", "Y-m-d");
1338 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1339 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1341 * @param {String} input The unparsed date as a string
1342 * @param {String} format The format the date is in
1343 * @return {Date} The parsed date
1346 Date.parseDate = function(input, format) {
1347 if (Date.parseFunctions[format] == null) {
1348 Date.createParser(format);
1350 var func = Date.parseFunctions[format];
1351 return Date[func](input);
1357 Date.createParser = function(format) {
1358 var funcName = "parse" + Date.parseFunctions.count++;
1359 var regexNum = Date.parseRegexes.length;
1360 var currentGroup = 1;
1361 Date.parseFunctions[format] = funcName;
1363 var code = "Date." + funcName + " = function(input){\n"
1364 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1365 + "var d = new Date();\n"
1366 + "y = d.getFullYear();\n"
1367 + "m = d.getMonth();\n"
1368 + "d = d.getDate();\n"
1369 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1370 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1371 + "if (results && results.length > 0) {";
1374 var special = false;
1376 for (var i = 0; i < format.length; ++i) {
1377 ch = format.charAt(i);
1378 if (!special && ch == "\\") {
1383 regex += String.escape(ch);
1386 var obj = Date.formatCodeToRegex(ch, currentGroup);
1387 currentGroup += obj.g;
1389 if (obj.g && obj.c) {
1395 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1396 + "{v = new Date(y, m, d, h, i, s);}\n"
1397 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1398 + "{v = new Date(y, m, d, h, i);}\n"
1399 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1400 + "{v = new Date(y, m, d, h);}\n"
1401 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1402 + "{v = new Date(y, m, d);}\n"
1403 + "else if (y >= 0 && m >= 0)\n"
1404 + "{v = new Date(y, m);}\n"
1405 + "else if (y >= 0)\n"
1406 + "{v = new Date(y);}\n"
1407 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1408 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1409 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1412 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1413 /** eval:var:zzzzzzzzzzzzz */
1418 Date.formatCodeToRegex = function(character, currentGroup) {
1419 switch (character) {
1423 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1426 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1427 s:"(\\d{1,2})"}; // day of month without leading zeroes
1430 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1431 s:"(\\d{2})"}; // day of month with leading zeroes
1435 s:"(?:" + Date.dayNames.join("|") + ")"};
1439 s:"(?:st|nd|rd|th)"};
1454 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1455 s:"(" + Date.monthNames.join("|") + ")"};
1458 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1459 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1462 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1463 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1466 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1467 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1478 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1482 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1483 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1487 c:"if (results[" + currentGroup + "] == 'am') {\n"
1488 + "if (h == 12) { h = 0; }\n"
1489 + "} else { if (h < 12) { h += 12; }}",
1493 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1494 + "if (h == 12) { h = 0; }\n"
1495 + "} else { if (h < 12) { h += 12; }}",
1500 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1501 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1505 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1506 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1509 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1513 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1518 "o = results[", currentGroup, "];\n",
1519 "var sn = o.substring(0,1);\n", // get + / - sign
1520 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1521 "var mn = o.substring(3,5) % 60;\n", // get minutes
1522 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1523 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1525 s:"([+\-]\\d{2,4})"};
1531 "o = results[", currentGroup, "];\n",
1532 "var sn = o.substring(0,1);\n",
1533 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1534 "var mn = o.substring(4,6) % 60;\n",
1535 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1536 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1542 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1545 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1546 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1547 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1551 s:String.escape(character)};
1556 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1557 * @return {String} The abbreviated timezone name (e.g. 'CST')
1559 Date.prototype.getTimezone = function() {
1560 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1564 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1565 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1567 Date.prototype.getGMTOffset = function() {
1568 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1569 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1570 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1574 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1575 * @return {String} 2-characters representing hours and 2-characters representing minutes
1576 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1578 Date.prototype.getGMTColonOffset = function() {
1579 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1580 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1582 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1586 * Get the numeric day number of the year, adjusted for leap year.
1587 * @return {Number} 0 through 364 (365 in leap years)
1589 Date.prototype.getDayOfYear = function() {
1591 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1592 for (var i = 0; i < this.getMonth(); ++i) {
1593 num += Date.daysInMonth[i];
1595 return num + this.getDate() - 1;
1599 * Get the string representation of the numeric week number of the year
1600 * (equivalent to the format specifier 'W').
1601 * @return {String} '00' through '52'
1603 Date.prototype.getWeekOfYear = function() {
1604 // Skip to Thursday of this week
1605 var now = this.getDayOfYear() + (4 - this.getDay());
1606 // Find the first Thursday of the year
1607 var jan1 = new Date(this.getFullYear(), 0, 1);
1608 var then = (7 - jan1.getDay() + 4);
1609 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1613 * Whether or not the current date is in a leap year.
1614 * @return {Boolean} True if the current date is in a leap year, else false
1616 Date.prototype.isLeapYear = function() {
1617 var year = this.getFullYear();
1618 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1622 * Get the first day of the current month, adjusted for leap year. The returned value
1623 * is the numeric day index within the week (0-6) which can be used in conjunction with
1624 * the {@link #monthNames} array to retrieve the textual day name.
1627 var dt = new Date('1/10/2007');
1628 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1630 * @return {Number} The day number (0-6)
1632 Date.prototype.getFirstDayOfMonth = function() {
1633 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1634 return (day < 0) ? (day + 7) : day;
1638 * Get the last day of the current month, adjusted for leap year. The returned value
1639 * is the numeric day index within the week (0-6) which can be used in conjunction with
1640 * the {@link #monthNames} array to retrieve the textual day name.
1643 var dt = new Date('1/10/2007');
1644 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1646 * @return {Number} The day number (0-6)
1648 Date.prototype.getLastDayOfMonth = function() {
1649 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1650 return (day < 0) ? (day + 7) : day;
1655 * Get the first date of this date's month
1658 Date.prototype.getFirstDateOfMonth = function() {
1659 return new Date(this.getFullYear(), this.getMonth(), 1);
1663 * Get the last date of this date's month
1666 Date.prototype.getLastDateOfMonth = function() {
1667 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1670 * Get the number of days in the current month, adjusted for leap year.
1671 * @return {Number} The number of days in the month
1673 Date.prototype.getDaysInMonth = function() {
1674 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1675 return Date.daysInMonth[this.getMonth()];
1679 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1680 * @return {String} 'st, 'nd', 'rd' or 'th'
1682 Date.prototype.getSuffix = function() {
1683 switch (this.getDate()) {
1700 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1703 * An array of textual month names.
1704 * Override these values for international dates, for example...
1705 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1724 * An array of textual day names.
1725 * Override these values for international dates, for example...
1726 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1742 Date.monthNumbers = {
1757 * Creates and returns a new Date instance with the exact same date value as the called instance.
1758 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1759 * variable will also be changed. When the intention is to create a new variable that will not
1760 * modify the original instance, you should create a clone.
1762 * Example of correctly cloning a date:
1765 var orig = new Date('10/1/2006');
1768 document.write(orig); //returns 'Thu Oct 05 2006'!
1771 var orig = new Date('10/1/2006');
1772 var copy = orig.clone();
1774 document.write(orig); //returns 'Thu Oct 01 2006'
1776 * @return {Date} The new Date instance
1778 Date.prototype.clone = function() {
1779 return new Date(this.getTime());
1783 * Clears any time information from this date
1784 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1785 @return {Date} this or the clone
1787 Date.prototype.clearTime = function(clone){
1789 return this.clone().clearTime();
1794 this.setMilliseconds(0);
1799 // safari setMonth is broken -- check that this is only donw once...
1800 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1801 Date.brokenSetMonth = Date.prototype.setMonth;
1802 Date.prototype.setMonth = function(num){
1804 var n = Math.ceil(-num);
1805 var back_year = Math.ceil(n/12);
1806 var month = (n % 12) ? 12 - n % 12 : 0 ;
1807 this.setFullYear(this.getFullYear() - back_year);
1808 return Date.brokenSetMonth.call(this, month);
1810 return Date.brokenSetMonth.apply(this, arguments);
1815 /** Date interval constant
1819 /** Date interval constant
1823 /** Date interval constant
1827 /** Date interval constant
1831 /** Date interval constant
1835 /** Date interval constant
1839 /** Date interval constant
1845 * Provides a convenient method of performing basic date arithmetic. This method
1846 * does not modify the Date instance being called - it creates and returns
1847 * a new Date instance containing the resulting date value.
1852 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1853 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1855 //Negative values will subtract correctly:
1856 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1857 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1859 //You can even chain several calls together in one line!
1860 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1861 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1864 * @param {String} interval A valid date interval enum value
1865 * @param {Number} value The amount to add to the current date
1866 * @return {Date} The new Date instance
1868 Date.prototype.add = function(interval, value){
1869 var d = this.clone();
1870 if (!interval || value === 0) { return d; }
1871 switch(interval.toLowerCase()){
1873 d.setMilliseconds(this.getMilliseconds() + value);
1876 d.setSeconds(this.getSeconds() + value);
1879 d.setMinutes(this.getMinutes() + value);
1882 d.setHours(this.getHours() + value);
1885 d.setDate(this.getDate() + value);
1888 var day = this.getDate();
1890 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1893 d.setMonth(this.getMonth() + value);
1896 d.setFullYear(this.getFullYear() + value);
1902 * @class Roo.lib.Dom
1906 * Dom utils (from YIU afaik)
1912 * Get the view width
1913 * @param {Boolean} full True will get the full document, otherwise it's the view width
1914 * @return {Number} The width
1917 getViewWidth : function(full) {
1918 return full ? this.getDocumentWidth() : this.getViewportWidth();
1921 * Get the view height
1922 * @param {Boolean} full True will get the full document, otherwise it's the view height
1923 * @return {Number} The height
1925 getViewHeight : function(full) {
1926 return full ? this.getDocumentHeight() : this.getViewportHeight();
1929 * Get the Full Document height
1930 * @return {Number} The height
1932 getDocumentHeight: function() {
1933 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1934 return Math.max(scrollHeight, this.getViewportHeight());
1937 * Get the Full Document width
1938 * @return {Number} The width
1940 getDocumentWidth: function() {
1941 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1942 return Math.max(scrollWidth, this.getViewportWidth());
1945 * Get the Window Viewport height
1946 * @return {Number} The height
1948 getViewportHeight: function() {
1949 var height = self.innerHeight;
1950 var mode = document.compatMode;
1952 if ((mode || Roo.isIE) && !Roo.isOpera) {
1953 height = (mode == "CSS1Compat") ?
1954 document.documentElement.clientHeight :
1955 document.body.clientHeight;
1961 * Get the Window Viewport width
1962 * @return {Number} The width
1964 getViewportWidth: function() {
1965 var width = self.innerWidth;
1966 var mode = document.compatMode;
1968 if (mode || Roo.isIE) {
1969 width = (mode == "CSS1Compat") ?
1970 document.documentElement.clientWidth :
1971 document.body.clientWidth;
1976 isAncestor : function(p, c) {
1983 if (p.contains && !Roo.isSafari) {
1984 return p.contains(c);
1985 } else if (p.compareDocumentPosition) {
1986 return !!(p.compareDocumentPosition(c) & 16);
1988 var parent = c.parentNode;
1993 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1996 parent = parent.parentNode;
2002 getRegion : function(el) {
2003 return Roo.lib.Region.getRegion(el);
2006 getY : function(el) {
2007 return this.getXY(el)[1];
2010 getX : function(el) {
2011 return this.getXY(el)[0];
2014 getXY : function(el) {
2015 var p, pe, b, scroll, bd = document.body;
2016 el = Roo.getDom(el);
2017 var fly = Roo.lib.AnimBase.fly;
2018 if (el.getBoundingClientRect) {
2019 b = el.getBoundingClientRect();
2020 scroll = fly(document).getScroll();
2021 return [b.left + scroll.left, b.top + scroll.top];
2027 var hasAbsolute = fly(el).getStyle("position") == "absolute";
2034 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
2041 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
2042 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2049 if (p != el && pe.getStyle('overflow') != 'visible') {
2057 if (Roo.isSafari && hasAbsolute) {
2062 if (Roo.isGecko && !hasAbsolute) {
2064 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2065 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2069 while (p && p != bd) {
2070 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2082 setXY : function(el, xy) {
2083 el = Roo.fly(el, '_setXY');
2085 var pts = el.translatePoints(xy);
2086 if (xy[0] !== false) {
2087 el.dom.style.left = pts.left + "px";
2089 if (xy[1] !== false) {
2090 el.dom.style.top = pts.top + "px";
2094 setX : function(el, x) {
2095 this.setXY(el, [x, false]);
2098 setY : function(el, y) {
2099 this.setXY(el, [false, y]);
2103 * Portions of this file are based on pieces of Yahoo User Interface Library
2104 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2105 * YUI licensed under the BSD License:
2106 * http://developer.yahoo.net/yui/license.txt
2107 * <script type="text/javascript">
2111 Roo.lib.Event = function() {
2112 var loadComplete = false;
2114 var unloadListeners = [];
2116 var onAvailStack = [];
2118 var lastError = null;
2131 startInterval: function() {
2132 if (!this._interval) {
2134 var callback = function() {
2135 self._tryPreloadAttach();
2137 this._interval = setInterval(callback, this.POLL_INTERVAL);
2142 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2143 onAvailStack.push({ id: p_id,
2146 override: p_override,
2147 checkReady: false });
2149 retryCount = this.POLL_RETRYS;
2150 this.startInterval();
2154 addListener: function(el, eventName, fn) {
2155 el = Roo.getDom(el);
2160 if ("unload" == eventName) {
2161 unloadListeners[unloadListeners.length] =
2162 [el, eventName, fn];
2166 var wrappedFn = function(e) {
2167 return fn(Roo.lib.Event.getEvent(e));
2170 var li = [el, eventName, fn, wrappedFn];
2172 var index = listeners.length;
2173 listeners[index] = li;
2175 this.doAdd(el, eventName, wrappedFn, false);
2181 removeListener: function(el, eventName, fn) {
2184 el = Roo.getDom(el);
2187 return this.purgeElement(el, false, eventName);
2191 if ("unload" == eventName) {
2193 for (i = 0,len = unloadListeners.length; i < len; i++) {
2194 var li = unloadListeners[i];
2197 li[1] == eventName &&
2199 unloadListeners.splice(i, 1);
2207 var cacheItem = null;
2210 var index = arguments[3];
2212 if ("undefined" == typeof index) {
2213 index = this._getCacheIndex(el, eventName, fn);
2217 cacheItem = listeners[index];
2220 if (!el || !cacheItem) {
2224 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2226 delete listeners[index][this.WFN];
2227 delete listeners[index][this.FN];
2228 listeners.splice(index, 1);
2235 getTarget: function(ev, resolveTextNode) {
2236 ev = ev.browserEvent || ev;
2237 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2238 var t = ev.target || ev.srcElement;
2239 return this.resolveTextNode(t);
2243 resolveTextNode: function(node) {
2244 if (Roo.isSafari && node && 3 == node.nodeType) {
2245 return node.parentNode;
2252 getPageX: function(ev) {
2253 ev = ev.browserEvent || ev;
2254 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2256 if (!x && 0 !== x) {
2257 x = ev.clientX || 0;
2260 x += this.getScroll()[1];
2268 getPageY: function(ev) {
2269 ev = ev.browserEvent || ev;
2270 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2272 if (!y && 0 !== y) {
2273 y = ev.clientY || 0;
2276 y += this.getScroll()[0];
2285 getXY: function(ev) {
2286 ev = ev.browserEvent || ev;
2287 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2288 return [this.getPageX(ev), this.getPageY(ev)];
2292 getRelatedTarget: function(ev) {
2293 ev = ev.browserEvent || ev;
2294 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2295 var t = ev.relatedTarget;
2297 if (ev.type == "mouseout") {
2299 } else if (ev.type == "mouseover") {
2304 return this.resolveTextNode(t);
2308 getTime: function(ev) {
2309 ev = ev.browserEvent || ev;
2310 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2312 var t = new Date().getTime();
2316 this.lastError = ex;
2325 stopEvent: function(ev) {
2326 this.stopPropagation(ev);
2327 this.preventDefault(ev);
2331 stopPropagation: function(ev) {
2332 ev = ev.browserEvent || ev;
2333 if (ev.stopPropagation) {
2334 ev.stopPropagation();
2336 ev.cancelBubble = true;
2341 preventDefault: function(ev) {
2342 ev = ev.browserEvent || ev;
2343 if(ev.preventDefault) {
2344 ev.preventDefault();
2346 ev.returnValue = false;
2351 getEvent: function(e) {
2352 var ev = e || window.event;
2354 var c = this.getEvent.caller;
2356 ev = c.arguments[0];
2357 if (ev && Event == ev.constructor) {
2367 getCharCode: function(ev) {
2368 ev = ev.browserEvent || ev;
2369 return ev.charCode || ev.keyCode || 0;
2373 _getCacheIndex: function(el, eventName, fn) {
2374 for (var i = 0,len = listeners.length; i < len; ++i) {
2375 var li = listeners[i];
2377 li[this.FN] == fn &&
2378 li[this.EL] == el &&
2379 li[this.TYPE] == eventName) {
2391 getEl: function(id) {
2392 return document.getElementById(id);
2396 clearCache: function() {
2400 _load: function(e) {
2401 loadComplete = true;
2402 var EU = Roo.lib.Event;
2406 EU.doRemove(window, "load", EU._load);
2411 _tryPreloadAttach: function() {
2420 var tryAgain = !loadComplete;
2422 tryAgain = (retryCount > 0);
2427 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2428 var item = onAvailStack[i];
2430 var el = this.getEl(item.id);
2433 if (!item.checkReady ||
2436 (document && document.body)) {
2439 if (item.override) {
2440 if (item.override === true) {
2443 scope = item.override;
2446 item.fn.call(scope, item.obj);
2447 onAvailStack[i] = null;
2450 notAvail.push(item);
2455 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2459 this.startInterval();
2461 clearInterval(this._interval);
2462 this._interval = null;
2465 this.locked = false;
2472 purgeElement: function(el, recurse, eventName) {
2473 var elListeners = this.getListeners(el, eventName);
2475 for (var i = 0,len = elListeners.length; i < len; ++i) {
2476 var l = elListeners[i];
2477 this.removeListener(el, l.type, l.fn);
2481 if (recurse && el && el.childNodes) {
2482 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2483 this.purgeElement(el.childNodes[i], recurse, eventName);
2489 getListeners: function(el, eventName) {
2490 var results = [], searchLists;
2492 searchLists = [listeners, unloadListeners];
2493 } else if (eventName == "unload") {
2494 searchLists = [unloadListeners];
2496 searchLists = [listeners];
2499 for (var j = 0; j < searchLists.length; ++j) {
2500 var searchList = searchLists[j];
2501 if (searchList && searchList.length > 0) {
2502 for (var i = 0,len = searchList.length; i < len; ++i) {
2503 var l = searchList[i];
2504 if (l && l[this.EL] === el &&
2505 (!eventName || eventName === l[this.TYPE])) {
2510 adjust: l[this.ADJ_SCOPE],
2518 return (results.length) ? results : null;
2522 _unload: function(e) {
2524 var EU = Roo.lib.Event, i, j, l, len, index;
2526 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2527 l = unloadListeners[i];
2530 if (l[EU.ADJ_SCOPE]) {
2531 if (l[EU.ADJ_SCOPE] === true) {
2534 scope = l[EU.ADJ_SCOPE];
2537 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2538 unloadListeners[i] = null;
2544 unloadListeners = null;
2546 if (listeners && listeners.length > 0) {
2547 j = listeners.length;
2550 l = listeners[index];
2552 EU.removeListener(l[EU.EL], l[EU.TYPE],
2562 EU.doRemove(window, "unload", EU._unload);
2567 getScroll: function() {
2568 var dd = document.documentElement, db = document.body;
2569 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2570 return [dd.scrollTop, dd.scrollLeft];
2572 return [db.scrollTop, db.scrollLeft];
2579 doAdd: function () {
2580 if (window.addEventListener) {
2581 return function(el, eventName, fn, capture) {
2582 el.addEventListener(eventName, fn, (capture));
2584 } else if (window.attachEvent) {
2585 return function(el, eventName, fn, capture) {
2586 el.attachEvent("on" + eventName, fn);
2595 doRemove: function() {
2596 if (window.removeEventListener) {
2597 return function (el, eventName, fn, capture) {
2598 el.removeEventListener(eventName, fn, (capture));
2600 } else if (window.detachEvent) {
2601 return function (el, eventName, fn) {
2602 el.detachEvent("on" + eventName, fn);
2614 var E = Roo.lib.Event;
2615 E.on = E.addListener;
2616 E.un = E.removeListener;
2618 if (document && document.body) {
2621 E.doAdd(window, "load", E._load);
2623 E.doAdd(window, "unload", E._unload);
2624 E._tryPreloadAttach();
2631 * @class Roo.lib.Ajax
2633 * provide a simple Ajax request utility functions
2635 * Portions of this file are based on pieces of Yahoo User Interface Library
2636 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2637 * YUI licensed under the BSD License:
2638 * http://developer.yahoo.net/yui/license.txt
2639 * <script type="text/javascript">
2647 request : function(method, uri, cb, data, options) {
2649 var hs = options.headers;
2652 if(hs.hasOwnProperty(h)){
2653 this.initHeader(h, hs[h], false);
2657 if(options.xmlData){
2658 this.initHeader('Content-Type', 'text/xml', false);
2660 data = options.xmlData;
2664 return this.asyncRequest(method, uri, cb, data);
2670 * @param {DomForm} form element
2671 * @return {String} urlencode form output.
2673 serializeForm : function(form) {
2674 if(typeof form == 'string') {
2675 form = (document.getElementById(form) || document.forms[form]);
2678 var el, name, val, disabled, data = '', hasSubmit = false;
2679 for (var i = 0; i < form.elements.length; i++) {
2680 el = form.elements[i];
2681 disabled = form.elements[i].disabled;
2682 name = form.elements[i].name;
2683 val = form.elements[i].value;
2685 if (!disabled && name){
2689 case 'select-multiple':
2690 for (var j = 0; j < el.options.length; j++) {
2691 if (el.options[j].selected) {
2693 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2696 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2704 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2717 if(hasSubmit == false) {
2718 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2723 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2728 data = data.substr(0, data.length - 1);
2736 useDefaultHeader:true,
2738 defaultPostHeader:'application/x-www-form-urlencoded',
2740 useDefaultXhrHeader:true,
2742 defaultXhrHeader:'XMLHttpRequest',
2744 hasDefaultHeaders:true,
2756 setProgId:function(id)
2758 this.activeX.unshift(id);
2761 setDefaultPostHeader:function(b)
2763 this.useDefaultHeader = b;
2766 setDefaultXhrHeader:function(b)
2768 this.useDefaultXhrHeader = b;
2771 setPollingInterval:function(i)
2773 if (typeof i == 'number' && isFinite(i)) {
2774 this.pollInterval = i;
2778 createXhrObject:function(transactionId)
2784 http = new XMLHttpRequest();
2786 obj = { conn:http, tId:transactionId };
2790 for (var i = 0; i < this.activeX.length; ++i) {
2794 http = new ActiveXObject(this.activeX[i]);
2796 obj = { conn:http, tId:transactionId };
2809 getConnectionObject:function()
2812 var tId = this.transactionId;
2816 o = this.createXhrObject(tId);
2818 this.transactionId++;
2829 asyncRequest:function(method, uri, callback, postData)
2831 var o = this.getConnectionObject();
2837 o.conn.open(method, uri, true);
2839 if (this.useDefaultXhrHeader) {
2840 if (!this.defaultHeaders['X-Requested-With']) {
2841 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2845 if(postData && this.useDefaultHeader){
2846 this.initHeader('Content-Type', this.defaultPostHeader);
2849 if (this.hasDefaultHeaders || this.hasHeaders) {
2853 this.handleReadyState(o, callback);
2854 o.conn.send(postData || null);
2860 handleReadyState:function(o, callback)
2864 if (callback && callback.timeout) {
2866 this.timeout[o.tId] = window.setTimeout(function() {
2867 oConn.abort(o, callback, true);
2868 }, callback.timeout);
2871 this.poll[o.tId] = window.setInterval(
2873 if (o.conn && o.conn.readyState == 4) {
2874 window.clearInterval(oConn.poll[o.tId]);
2875 delete oConn.poll[o.tId];
2877 if(callback && callback.timeout) {
2878 window.clearTimeout(oConn.timeout[o.tId]);
2879 delete oConn.timeout[o.tId];
2882 oConn.handleTransactionResponse(o, callback);
2885 , this.pollInterval);
2888 handleTransactionResponse:function(o, callback, isAbort)
2892 this.releaseObject(o);
2896 var httpStatus, responseObject;
2900 if (o.conn.status !== undefined && o.conn.status != 0) {
2901 httpStatus = o.conn.status;
2913 if (httpStatus >= 200 && httpStatus < 300) {
2914 responseObject = this.createResponseObject(o, callback.argument);
2915 if (callback.success) {
2916 if (!callback.scope) {
2917 callback.success(responseObject);
2922 callback.success.apply(callback.scope, [responseObject]);
2927 switch (httpStatus) {
2935 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2936 if (callback.failure) {
2937 if (!callback.scope) {
2938 callback.failure(responseObject);
2941 callback.failure.apply(callback.scope, [responseObject]);
2946 responseObject = this.createResponseObject(o, callback.argument);
2947 if (callback.failure) {
2948 if (!callback.scope) {
2949 callback.failure(responseObject);
2952 callback.failure.apply(callback.scope, [responseObject]);
2958 this.releaseObject(o);
2959 responseObject = null;
2962 createResponseObject:function(o, callbackArg)
2969 var headerStr = o.conn.getAllResponseHeaders();
2970 var header = headerStr.split('\n');
2971 for (var i = 0; i < header.length; i++) {
2972 var delimitPos = header[i].indexOf(':');
2973 if (delimitPos != -1) {
2974 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2982 obj.status = o.conn.status;
2983 obj.statusText = o.conn.statusText;
2984 obj.getResponseHeader = headerObj;
2985 obj.getAllResponseHeaders = headerStr;
2986 obj.responseText = o.conn.responseText;
2987 obj.responseXML = o.conn.responseXML;
2989 if (typeof callbackArg !== undefined) {
2990 obj.argument = callbackArg;
2996 createExceptionObject:function(tId, callbackArg, isAbort)
2999 var COMM_ERROR = 'communication failure';
3000 var ABORT_CODE = -1;
3001 var ABORT_ERROR = 'transaction aborted';
3007 obj.status = ABORT_CODE;
3008 obj.statusText = ABORT_ERROR;
3011 obj.status = COMM_CODE;
3012 obj.statusText = COMM_ERROR;
3016 obj.argument = callbackArg;
3022 initHeader:function(label, value, isDefault)
3024 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
3026 if (headerObj[label] === undefined) {
3027 headerObj[label] = value;
3032 headerObj[label] = value + "," + headerObj[label];
3036 this.hasDefaultHeaders = true;
3039 this.hasHeaders = true;
3044 setHeader:function(o)
3046 if (this.hasDefaultHeaders) {
3047 for (var prop in this.defaultHeaders) {
3048 if (this.defaultHeaders.hasOwnProperty(prop)) {
3049 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3054 if (this.hasHeaders) {
3055 for (var prop in this.headers) {
3056 if (this.headers.hasOwnProperty(prop)) {
3057 o.conn.setRequestHeader(prop, this.headers[prop]);
3061 this.hasHeaders = false;
3065 resetDefaultHeaders:function() {
3066 delete this.defaultHeaders;
3067 this.defaultHeaders = {};
3068 this.hasDefaultHeaders = false;
3071 abort:function(o, callback, isTimeout)
3073 if(this.isCallInProgress(o)) {
3075 window.clearInterval(this.poll[o.tId]);
3076 delete this.poll[o.tId];
3078 delete this.timeout[o.tId];
3081 this.handleTransactionResponse(o, callback, true);
3091 isCallInProgress:function(o)
3094 return o.conn.readyState != 4 && o.conn.readyState != 0;
3103 releaseObject:function(o)
3112 'MSXML2.XMLHTTP.3.0',
3120 * Portions of this file are based on pieces of Yahoo User Interface Library
3121 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3122 * YUI licensed under the BSD License:
3123 * http://developer.yahoo.net/yui/license.txt
3124 * <script type="text/javascript">
3128 Roo.lib.Region = function(t, r, b, l) {
3138 Roo.lib.Region.prototype = {
3139 contains : function(region) {
3140 return ( region.left >= this.left &&
3141 region.right <= this.right &&
3142 region.top >= this.top &&
3143 region.bottom <= this.bottom );
3147 getArea : function() {
3148 return ( (this.bottom - this.top) * (this.right - this.left) );
3151 intersect : function(region) {
3152 var t = Math.max(this.top, region.top);
3153 var r = Math.min(this.right, region.right);
3154 var b = Math.min(this.bottom, region.bottom);
3155 var l = Math.max(this.left, region.left);
3157 if (b >= t && r >= l) {
3158 return new Roo.lib.Region(t, r, b, l);
3163 union : function(region) {
3164 var t = Math.min(this.top, region.top);
3165 var r = Math.max(this.right, region.right);
3166 var b = Math.max(this.bottom, region.bottom);
3167 var l = Math.min(this.left, region.left);
3169 return new Roo.lib.Region(t, r, b, l);
3172 adjust : function(t, l, b, r) {
3181 Roo.lib.Region.getRegion = function(el) {
3182 var p = Roo.lib.Dom.getXY(el);
3185 var r = p[0] + el.offsetWidth;
3186 var b = p[1] + el.offsetHeight;
3189 return new Roo.lib.Region(t, r, b, l);
3192 * Portions of this file are based on pieces of Yahoo User Interface Library
3193 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3194 * YUI licensed under the BSD License:
3195 * http://developer.yahoo.net/yui/license.txt
3196 * <script type="text/javascript">
3199 //@@dep Roo.lib.Region
3202 Roo.lib.Point = function(x, y) {
3203 if (x instanceof Array) {
3207 this.x = this.right = this.left = this[0] = x;
3208 this.y = this.top = this.bottom = this[1] = y;
3211 Roo.lib.Point.prototype = new Roo.lib.Region();
3213 * Portions of this file are based on pieces of Yahoo User Interface Library
3214 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3215 * YUI licensed under the BSD License:
3216 * http://developer.yahoo.net/yui/license.txt
3217 * <script type="text/javascript">
3224 scroll : function(el, args, duration, easing, cb, scope) {
3225 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3228 motion : function(el, args, duration, easing, cb, scope) {
3229 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3232 color : function(el, args, duration, easing, cb, scope) {
3233 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3236 run : function(el, args, duration, easing, cb, scope, type) {
3237 type = type || Roo.lib.AnimBase;
3238 if (typeof easing == "string") {
3239 easing = Roo.lib.Easing[easing];
3241 var anim = new type(el, args, duration, easing);
3242 anim.animateX(function() {
3243 Roo.callback(cb, scope);
3249 * Portions of this file are based on pieces of Yahoo User Interface Library
3250 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3251 * YUI licensed under the BSD License:
3252 * http://developer.yahoo.net/yui/license.txt
3253 * <script type="text/javascript">
3261 if (!libFlyweight) {
3262 libFlyweight = new Roo.Element.Flyweight();
3264 libFlyweight.dom = el;
3265 return libFlyweight;
3268 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3272 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3274 this.init(el, attributes, duration, method);
3278 Roo.lib.AnimBase.fly = fly;
3282 Roo.lib.AnimBase.prototype = {
3284 toString: function() {
3285 var el = this.getEl();
3286 var id = el.id || el.tagName;
3287 return ("Anim " + id);
3291 noNegatives: /width|height|opacity|padding/i,
3292 offsetAttribute: /^((width|height)|(top|left))$/,
3293 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3294 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3298 doMethod: function(attr, start, end) {
3299 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3303 setAttribute: function(attr, val, unit) {
3304 if (this.patterns.noNegatives.test(attr)) {
3305 val = (val > 0) ? val : 0;
3308 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3312 getAttribute: function(attr) {
3313 var el = this.getEl();
3314 var val = fly(el).getStyle(attr);
3316 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3317 return parseFloat(val);
3320 var a = this.patterns.offsetAttribute.exec(attr) || [];
3321 var pos = !!( a[3] );
3322 var box = !!( a[2] );
3325 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3326 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3335 getDefaultUnit: function(attr) {
3336 if (this.patterns.defaultUnit.test(attr)) {
3343 animateX : function(callback, scope) {
3344 var f = function() {
3345 this.onComplete.removeListener(f);
3346 if (typeof callback == "function") {
3347 callback.call(scope || this, this);
3350 this.onComplete.addListener(f, this);
3355 setRuntimeAttribute: function(attr) {
3358 var attributes = this.attributes;
3360 this.runtimeAttributes[attr] = {};
3362 var isset = function(prop) {
3363 return (typeof prop !== 'undefined');
3366 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3370 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3373 if (isset(attributes[attr]['to'])) {
3374 end = attributes[attr]['to'];
3375 } else if (isset(attributes[attr]['by'])) {
3376 if (start.constructor == Array) {
3378 for (var i = 0, len = start.length; i < len; ++i) {
3379 end[i] = start[i] + attributes[attr]['by'][i];
3382 end = start + attributes[attr]['by'];
3386 this.runtimeAttributes[attr].start = start;
3387 this.runtimeAttributes[attr].end = end;
3390 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3394 init: function(el, attributes, duration, method) {
3396 var isAnimated = false;
3399 var startTime = null;
3402 var actualFrames = 0;
3405 el = Roo.getDom(el);
3408 this.attributes = attributes || {};
3411 this.duration = duration || 1;
3414 this.method = method || Roo.lib.Easing.easeNone;
3417 this.useSeconds = true;
3420 this.currentFrame = 0;
3423 this.totalFrames = Roo.lib.AnimMgr.fps;
3426 this.getEl = function() {
3431 this.isAnimated = function() {
3436 this.getStartTime = function() {
3440 this.runtimeAttributes = {};
3443 this.animate = function() {
3444 if (this.isAnimated()) {
3448 this.currentFrame = 0;
3450 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3452 Roo.lib.AnimMgr.registerElement(this);
3456 this.stop = function(finish) {
3458 this.currentFrame = this.totalFrames;
3459 this._onTween.fire();
3461 Roo.lib.AnimMgr.stop(this);
3464 var onStart = function() {
3465 this.onStart.fire();
3467 this.runtimeAttributes = {};
3468 for (var attr in this.attributes) {
3469 this.setRuntimeAttribute(attr);
3474 startTime = new Date();
3478 var onTween = function() {
3480 duration: new Date() - this.getStartTime(),
3481 currentFrame: this.currentFrame
3484 data.toString = function() {
3486 'duration: ' + data.duration +
3487 ', currentFrame: ' + data.currentFrame
3491 this.onTween.fire(data);
3493 var runtimeAttributes = this.runtimeAttributes;
3495 for (var attr in runtimeAttributes) {
3496 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3502 var onComplete = function() {
3503 var actual_duration = (new Date() - startTime) / 1000 ;
3506 duration: actual_duration,
3507 frames: actualFrames,
3508 fps: actualFrames / actual_duration
3511 data.toString = function() {
3513 'duration: ' + data.duration +
3514 ', frames: ' + data.frames +
3515 ', fps: ' + data.fps
3521 this.onComplete.fire(data);
3525 this._onStart = new Roo.util.Event(this);
3526 this.onStart = new Roo.util.Event(this);
3527 this.onTween = new Roo.util.Event(this);
3528 this._onTween = new Roo.util.Event(this);
3529 this.onComplete = new Roo.util.Event(this);
3530 this._onComplete = new Roo.util.Event(this);
3531 this._onStart.addListener(onStart);
3532 this._onTween.addListener(onTween);
3533 this._onComplete.addListener(onComplete);
3538 * Portions of this file are based on pieces of Yahoo User Interface Library
3539 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3540 * YUI licensed under the BSD License:
3541 * http://developer.yahoo.net/yui/license.txt
3542 * <script type="text/javascript">
3546 Roo.lib.AnimMgr = new function() {
3563 this.registerElement = function(tween) {
3564 queue[queue.length] = tween;
3566 tween._onStart.fire();
3571 this.unRegister = function(tween, index) {
3572 tween._onComplete.fire();
3573 index = index || getIndex(tween);
3575 queue.splice(index, 1);
3579 if (tweenCount <= 0) {
3585 this.start = function() {
3586 if (thread === null) {
3587 thread = setInterval(this.run, this.delay);
3592 this.stop = function(tween) {
3594 clearInterval(thread);
3596 for (var i = 0, len = queue.length; i < len; ++i) {
3597 if (queue[0].isAnimated()) {
3598 this.unRegister(queue[0], 0);
3607 this.unRegister(tween);
3612 this.run = function() {
3613 for (var i = 0, len = queue.length; i < len; ++i) {
3614 var tween = queue[i];
3615 if (!tween || !tween.isAnimated()) {
3619 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3621 tween.currentFrame += 1;
3623 if (tween.useSeconds) {
3624 correctFrame(tween);
3626 tween._onTween.fire();
3629 Roo.lib.AnimMgr.stop(tween, i);
3634 var getIndex = function(anim) {
3635 for (var i = 0, len = queue.length; i < len; ++i) {
3636 if (queue[i] == anim) {
3644 var correctFrame = function(tween) {
3645 var frames = tween.totalFrames;
3646 var frame = tween.currentFrame;
3647 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3648 var elapsed = (new Date() - tween.getStartTime());
3651 if (elapsed < tween.duration * 1000) {
3652 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3654 tweak = frames - (frame + 1);
3656 if (tweak > 0 && isFinite(tweak)) {
3657 if (tween.currentFrame + tweak >= frames) {
3658 tweak = frames - (frame + 1);
3661 tween.currentFrame += tweak;
3667 * Portions of this file are based on pieces of Yahoo User Interface Library
3668 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3669 * YUI licensed under the BSD License:
3670 * http://developer.yahoo.net/yui/license.txt
3671 * <script type="text/javascript">
3674 Roo.lib.Bezier = new function() {
3676 this.getPosition = function(points, t) {
3677 var n = points.length;
3680 for (var i = 0; i < n; ++i) {
3681 tmp[i] = [points[i][0], points[i][1]];
3684 for (var j = 1; j < n; ++j) {
3685 for (i = 0; i < n - j; ++i) {
3686 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3687 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3691 return [ tmp[0][0], tmp[0][1] ];
3697 * @class Roo.lib.Color
3699 * An abstract Color implementation. Concrete Color implementations should use
3700 * an instance of this function as their prototype, and implement the getRGB and
3701 * getHSL functions. getRGB should return an object representing the RGB
3702 * components of this Color, with the red, green, and blue components in the
3703 * range [0,255] and the alpha component in the range [0,100]. getHSL should
3704 * return an object representing the HSL components of this Color, with the hue
3705 * component in the range [0,360), the saturation and lightness components in
3706 * the range [0,100], and the alpha component in the range [0,1].
3711 * Functions for Color handling and processing.
3713 * http://www.safalra.com/web-design/javascript/Color-handling-and-processing/
3715 * The author of this program, Safalra (Stephen Morley), irrevocably releases all
3716 * rights to this program, with the intention of it becoming part of the public
3717 * domain. Because this program is released into the public domain, it comes with
3718 * no warranty either expressed or implied, to the extent permitted by law.
3720 * For more free and public domain JavaScript code by the same author, visit:
3721 * http://www.safalra.com/web-design/javascript/
3724 Roo.lib.Color = function() { }
3727 Roo.apply(Roo.lib.Color.prototype, {
3735 * @return {Object} an object representing the RGBA components of this Color. The red,
3736 * green, and blue components are converted to integers in the range [0,255].
3737 * The alpha is a value in the range [0,1].
3739 getIntegerRGB : function(){
3741 // get the RGB components of this Color
3742 var rgb = this.getRGB();
3744 // return the integer components
3746 'r' : Math.round(rgb.r),
3747 'g' : Math.round(rgb.g),
3748 'b' : Math.round(rgb.b),
3756 * @return {Object} an object representing the RGBA components of this Color. The red,
3757 * green, and blue components are converted to numbers in the range [0,100].
3758 * The alpha is a value in the range [0,1].
3760 getPercentageRGB : function(){
3762 // get the RGB components of this Color
3763 var rgb = this.getRGB();
3765 // return the percentage components
3767 'r' : 100 * rgb.r / 255,
3768 'g' : 100 * rgb.g / 255,
3769 'b' : 100 * rgb.b / 255,
3776 * getCSSHexadecimalRGB
3777 * @return {String} a string representing this Color as a CSS hexadecimal RGB Color
3778 * value - that is, a string of the form #RRGGBB where each of RR, GG, and BB
3779 * are two-digit hexadecimal numbers.
3781 getCSSHexadecimalRGB : function()
3784 // get the integer RGB components
3785 var rgb = this.getIntegerRGB();
3787 // determine the hexadecimal equivalents
3788 var r16 = rgb.r.toString(16);
3789 var g16 = rgb.g.toString(16);
3790 var b16 = rgb.b.toString(16);
3792 // return the CSS RGB Color value
3794 + (r16.length == 2 ? r16 : '0' + r16)
3795 + (g16.length == 2 ? g16 : '0' + g16)
3796 + (b16.length == 2 ? b16 : '0' + b16);
3802 * @return {String} a string representing this Color as a CSS integer RGB Color
3803 * value - that is, a string of the form rgb(r,g,b) where each of r, g, and b
3804 * are integers in the range [0,255].
3806 getCSSIntegerRGB : function(){
3808 // get the integer RGB components
3809 var rgb = this.getIntegerRGB();
3811 // return the CSS RGB Color value
3812 return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')';
3818 * @return {String} Returns a string representing this Color as a CSS integer RGBA Color
3819 * value - that is, a string of the form rgba(r,g,b,a) where each of r, g, and
3820 * b are integers in the range [0,255] and a is in the range [0,1].
3822 getCSSIntegerRGBA : function(){
3824 // get the integer RGB components
3825 var rgb = this.getIntegerRGB();
3827 // return the CSS integer RGBA Color value
3828 return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + rgb.a + ')';
3833 * getCSSPercentageRGB
3834 * @return {String} a string representing this Color as a CSS percentage RGB Color
3835 * value - that is, a string of the form rgb(r%,g%,b%) where each of r, g, and
3836 * b are in the range [0,100].
3838 getCSSPercentageRGB : function(){
3840 // get the percentage RGB components
3841 var rgb = this.getPercentageRGB();
3843 // return the CSS RGB Color value
3844 return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%)';
3849 * getCSSPercentageRGBA
3850 * @return {String} a string representing this Color as a CSS percentage RGBA Color
3851 * value - that is, a string of the form rgba(r%,g%,b%,a) where each of r, g,
3852 * and b are in the range [0,100] and a is in the range [0,1].
3854 getCSSPercentageRGBA : function(){
3856 // get the percentage RGB components
3857 var rgb = this.getPercentageRGB();
3859 // return the CSS percentage RGBA Color value
3860 return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%,' + rgb.a + ')';
3866 * @return {String} a string representing this Color as a CSS HSL Color value - that
3867 * is, a string of the form hsl(h,s%,l%) where h is in the range [0,100] and
3868 * s and l are in the range [0,100].
3870 getCSSHSL : function(){
3872 // get the HSL components
3873 var hsl = this.getHSL();
3875 // return the CSS HSL Color value
3876 return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%)';
3882 * @return {String} a string representing this Color as a CSS HSLA Color value - that
3883 * is, a string of the form hsla(h,s%,l%,a) where h is in the range [0,100],
3884 * s and l are in the range [0,100], and a is in the range [0,1].
3886 getCSSHSLA : function(){
3888 // get the HSL components
3889 var hsl = this.getHSL();
3891 // return the CSS HSL Color value
3892 return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%,' + hsl.a + ')';
3897 * Sets the Color of the specified node to this Color. This functions sets
3898 * the CSS 'color' property for the node. The parameter is:
3900 * @param {DomElement} node - the node whose Color should be set
3902 setNodeColor : function(node){
3904 // set the Color of the node
3905 node.style.color = this.getCSSHexadecimalRGB();
3910 * Sets the background Color of the specified node to this Color. This
3911 * functions sets the CSS 'background-color' property for the node. The
3914 * @param {DomElement} node - the node whose background Color should be set
3916 setNodeBackgroundColor : function(node){
3918 // set the background Color of the node
3919 node.style.backgroundColor = this.getCSSHexadecimalRGB();
3922 // convert between formats..
3925 var r = this.getIntegerRGB();
3926 return new Roo.lib.RGBColor(r.r,r.g,r.b,r.a);
3931 var hsl = this.getHSL();
3932 // return the CSS HSL Color value
3933 return new Roo.lib.HSLColor(hsl.h, hsl.s, hsl.l , hsl.a );
3939 var rgb = this.toRGB();
3940 var hsv = rgb.getHSV();
3941 // return the CSS HSL Color value
3942 return new Roo.lib.HSVColor(hsv.h, hsv.s, hsv.v , hsv.a );
3946 // modify v = 0 ... 1 (eg. 0.5)
3947 saturate : function(v)
3949 var rgb = this.toRGB();
3950 var hsv = rgb.getHSV();
3951 return new Roo.lib.HSVColor(hsv.h, hsv.s * v, hsv.v , hsv.a );
3959 * @return {Object} the RGB and alpha components of this Color as an object with r,
3960 * g, b, and a properties. r, g, and b are in the range [0,255] and a is in
3965 // return the RGB components
3977 * @return {Object} the HSV and alpha components of this Color as an object with h,
3978 * s, v, and a properties. h is in the range [0,360), s and v are in the range
3979 * [0,100], and a is in the range [0,1].
3984 // calculate the HSV components if necessary
3985 if (this.hsv == null) {
3986 this.calculateHSV();
3989 // return the HSV components
4001 * @return {Object} the HSL and alpha components of this Color as an object with h,
4002 * s, l, and a properties. h is in the range [0,360), s and l are in the range
4003 * [0,100], and a is in the range [0,1].
4005 getHSL : function(){
4008 // calculate the HSV components if necessary
4009 if (this.hsl == null) { this.calculateHSL(); }
4011 // return the HSL components
4026 * @class Roo.lib.RGBColor
4027 * @extends Roo.lib.Color
4028 * Creates a Color specified in the RGB Color space, with an optional alpha
4029 * component. The parameters are:
4033 * @param {Number} r - the red component, clipped to the range [0,255]
4034 * @param {Number} g - the green component, clipped to the range [0,255]
4035 * @param {Number} b - the blue component, clipped to the range [0,255]
4036 * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4037 * optional and defaults to 1
4039 Roo.lib.RGBColor = function (r, g, b, a){
4041 // store the alpha component after clipping it if necessary
4042 this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4044 // store the RGB components after clipping them if necessary
4047 'r' : Math.max(0, Math.min(255, r)),
4048 'g' : Math.max(0, Math.min(255, g)),
4049 'b' : Math.max(0, Math.min(255, b))
4052 // initialise the HSV and HSL components to null
4056 * //private returns the HSV or HSL hue component of this RGBColor. The hue is in the
4057 * range [0,360). The parameters are:
4059 * maximum - the maximum of the RGB component values
4060 * range - the range of the RGB component values
4065 // this does an 'exteds'
4066 Roo.extend(Roo.lib.RGBColor, Roo.lib.Color, {
4069 getHue : function(maximum, range)
4073 // check whether the range is zero
4076 // set the hue to zero (any hue is acceptable as the Color is grey)
4081 // determine which of the components has the highest value and set the hue
4084 // red has the highest value
4086 var hue = (rgb.g - rgb.b) / range * 60;
4087 if (hue < 0) { hue += 360; }
4090 // green has the highest value
4092 var hue = (rgb.b - rgb.r) / range * 60 + 120;
4095 // blue has the highest value
4097 var hue = (rgb.r - rgb.g) / range * 60 + 240;
4109 /* //private Calculates and stores the HSV components of this RGBColor so that they can
4110 * be returned be the getHSV function.
4112 calculateHSV : function(){
4114 // get the maximum and range of the RGB component values
4115 var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4116 var range = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4118 // store the HSV components
4121 'h' : this.getHue(maximum, range),
4122 's' : (maximum == 0 ? 0 : 100 * range / maximum),
4123 'v' : maximum / 2.55
4128 /* //private Calculates and stores the HSL components of this RGBColor so that they can
4129 * be returned be the getHSL function.
4131 calculateHSL : function(){
4133 // get the maximum and range of the RGB component values
4134 var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4135 var range = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4137 // determine the lightness in the range [0,1]
4138 var l = maximum / 255 - range / 510;
4140 // store the HSL components
4143 'h' : this.getHue(maximum, range),
4144 's' : (range == 0 ? 0 : range / 2.55 / (l < 0.5 ? l * 2 : 2 - l * 2)),
4153 * @class Roo.lib.HSVColor
4154 * @extends Roo.lib.Color
4155 * Creates a Color specified in the HSV Color space, with an optional alpha
4156 * component. The parameters are:
4159 * @param {Number} h - the hue component, wrapped to the range [0,360)
4160 * @param {Number} s - the saturation component, clipped to the range [0,100]
4161 * @param {Number} v - the value component, clipped to the range [0,100]
4162 * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4163 * optional and defaults to 1
4165 Roo.lib.HSVColor = function (h, s, v, a){
4167 // store the alpha component after clipping it if necessary
4168 this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4170 // store the HSV components after clipping or wrapping them if necessary
4173 'h' : (h % 360 + 360) % 360,
4174 's' : Math.max(0, Math.min(100, s)),
4175 'v' : Math.max(0, Math.min(100, v))
4178 // initialise the RGB and HSL components to null
4183 Roo.extend(Roo.lib.HSVColor, Roo.lib.Color, {
4184 /* Calculates and stores the RGB components of this HSVColor so that they can
4185 * be returned be the getRGB function.
4187 calculateRGB: function ()
4190 // check whether the saturation is zero
4193 // set the Color to the appropriate shade of grey
4200 // set some temporary values
4201 var f = hsv.h / 60 - Math.floor(hsv.h / 60);
4202 var p = hsv.v * (1 - hsv.s / 100);
4203 var q = hsv.v * (1 - hsv.s / 100 * f);
4204 var t = hsv.v * (1 - hsv.s / 100 * (1 - f));
4206 // set the RGB Color components to their temporary values
4207 switch (Math.floor(hsv.h / 60)){
4208 case 0: var r = hsv.v; var g = t; var b = p; break;
4209 case 1: var r = q; var g = hsv.v; var b = p; break;
4210 case 2: var r = p; var g = hsv.v; var b = t; break;
4211 case 3: var r = p; var g = q; var b = hsv.v; break;
4212 case 4: var r = t; var g = p; var b = hsv.v; break;
4213 case 5: var r = hsv.v; var g = p; var b = q; break;
4218 // store the RGB components
4228 /* Calculates and stores the HSL components of this HSVColor so that they can
4229 * be returned be the getHSL function.
4231 calculateHSL : function (){
4234 // determine the lightness in the range [0,100]
4235 var l = (2 - hsv.s / 100) * hsv.v / 2;
4237 // store the HSL components
4241 's' : hsv.s * hsv.v / (l < 50 ? l * 2 : 200 - l * 2),
4245 // correct a division-by-zero error
4246 if (isNaN(hsl.s)) { hsl.s = 0; }
4255 * @class Roo.lib.HSLColor
4256 * @extends Roo.lib.Color
4259 * Creates a Color specified in the HSL Color space, with an optional alpha
4260 * component. The parameters are:
4262 * @param {Number} h - the hue component, wrapped to the range [0,360)
4263 * @param {Number} s - the saturation component, clipped to the range [0,100]
4264 * @param {Number} l - the lightness component, clipped to the range [0,100]
4265 * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4266 * optional and defaults to 1
4269 Roo.lib.HSLColor = function(h, s, l, a){
4271 // store the alpha component after clipping it if necessary
4272 this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4274 // store the HSL components after clipping or wrapping them if necessary
4277 'h' : (h % 360 + 360) % 360,
4278 's' : Math.max(0, Math.min(100, s)),
4279 'l' : Math.max(0, Math.min(100, l))
4282 // initialise the RGB and HSV components to null
4285 Roo.extend(Roo.lib.HSLColor, Roo.lib.Color, {
4287 /* Calculates and stores the RGB components of this HSLColor so that they can
4288 * be returned be the getRGB function.
4290 calculateRGB: function (){
4292 // check whether the saturation is zero
4293 if (this.hsl.s == 0){
4295 // store the RGB components representing the appropriate shade of grey
4298 'r' : this.hsl.l * 2.55,
4299 'g' : this.hsl.l * 2.55,
4300 'b' : this.hsl.l * 2.55
4305 // set some temporary values
4306 var p = this.hsl.l < 50
4307 ? this.hsl.l * (1 + hsl.s / 100)
4308 : this.hsl.l + hsl.s - hsl.l * hsl.s / 100;
4309 var q = 2 * hsl.l - p;
4311 // initialise the RGB components
4314 'r' : (h + 120) / 60 % 6,
4316 'b' : (h + 240) / 60 % 6
4319 // loop over the RGB components
4320 for (var key in this.rgb){
4322 // ensure that the property is not inherited from the root object
4323 if (this.rgb.hasOwnProperty(key)){
4325 // set the component to its value in the range [0,100]
4326 if (this.rgb[key] < 1){
4327 this.rgb[key] = q + (p - q) * this.rgb[key];
4328 }else if (this.rgb[key] < 3){
4330 }else if (this.rgb[key] < 4){
4331 this.rgb[key] = q + (p - q) * (4 - this.rgb[key]);
4336 // set the component to its value in the range [0,255]
4337 this.rgb[key] *= 2.55;
4347 /* Calculates and stores the HSV components of this HSLColor so that they can
4348 * be returned be the getHSL function.
4350 calculateHSV : function(){
4352 // set a temporary value
4353 var t = this.hsl.s * (this.hsl.l < 50 ? this.hsl.l : 100 - this.hsl.l) / 100;
4355 // store the HSV components
4359 's' : 200 * t / (this.hsl.l + t),
4360 'v' : t + this.hsl.l
4363 // correct a division-by-zero error
4364 if (isNaN(this.hsv.s)) { this.hsv.s = 0; }
4371 * Portions of this file are based on pieces of Yahoo User Interface Library
4372 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4373 * YUI licensed under the BSD License:
4374 * http://developer.yahoo.net/yui/license.txt
4375 * <script type="text/javascript">
4380 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
4381 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
4384 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
4386 var fly = Roo.lib.AnimBase.fly;
4388 var superclass = Y.ColorAnim.superclass;
4389 var proto = Y.ColorAnim.prototype;
4391 proto.toString = function() {
4392 var el = this.getEl();
4393 var id = el.id || el.tagName;
4394 return ("ColorAnim " + id);
4397 proto.patterns.color = /color$/i;
4398 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
4399 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
4400 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
4401 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
4404 proto.parseColor = function(s) {
4405 if (s.length == 3) {
4409 var c = this.patterns.hex.exec(s);
4410 if (c && c.length == 4) {
4411 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
4414 c = this.patterns.rgb.exec(s);
4415 if (c && c.length == 4) {
4416 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
4419 c = this.patterns.hex3.exec(s);
4420 if (c && c.length == 4) {
4421 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
4426 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
4427 proto.getAttribute = function(attr) {
4428 var el = this.getEl();
4429 if (this.patterns.color.test(attr)) {
4430 var val = fly(el).getStyle(attr);
4432 if (this.patterns.transparent.test(val)) {
4433 var parent = el.parentNode;
4434 val = fly(parent).getStyle(attr);
4436 while (parent && this.patterns.transparent.test(val)) {
4437 parent = parent.parentNode;
4438 val = fly(parent).getStyle(attr);
4439 if (parent.tagName.toUpperCase() == 'HTML') {
4445 val = superclass.getAttribute.call(this, attr);
4450 proto.getAttribute = function(attr) {
4451 var el = this.getEl();
4452 if (this.patterns.color.test(attr)) {
4453 var val = fly(el).getStyle(attr);
4455 if (this.patterns.transparent.test(val)) {
4456 var parent = el.parentNode;
4457 val = fly(parent).getStyle(attr);
4459 while (parent && this.patterns.transparent.test(val)) {
4460 parent = parent.parentNode;
4461 val = fly(parent).getStyle(attr);
4462 if (parent.tagName.toUpperCase() == 'HTML') {
4468 val = superclass.getAttribute.call(this, attr);
4474 proto.doMethod = function(attr, start, end) {
4477 if (this.patterns.color.test(attr)) {
4479 for (var i = 0, len = start.length; i < len; ++i) {
4480 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
4483 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
4486 val = superclass.doMethod.call(this, attr, start, end);
4492 proto.setRuntimeAttribute = function(attr) {
4493 superclass.setRuntimeAttribute.call(this, attr);
4495 if (this.patterns.color.test(attr)) {
4496 var attributes = this.attributes;
4497 var start = this.parseColor(this.runtimeAttributes[attr].start);
4498 var end = this.parseColor(this.runtimeAttributes[attr].end);
4500 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
4501 end = this.parseColor(attributes[attr].by);
4503 for (var i = 0, len = start.length; i < len; ++i) {
4504 end[i] = start[i] + end[i];
4508 this.runtimeAttributes[attr].start = start;
4509 this.runtimeAttributes[attr].end = end;
4515 * Portions of this file are based on pieces of Yahoo User Interface Library
4516 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4517 * YUI licensed under the BSD License:
4518 * http://developer.yahoo.net/yui/license.txt
4519 * <script type="text/javascript">
4525 easeNone: function (t, b, c, d) {
4526 return c * t / d + b;
4530 easeIn: function (t, b, c, d) {
4531 return c * (t /= d) * t + b;
4535 easeOut: function (t, b, c, d) {
4536 return -c * (t /= d) * (t - 2) + b;
4540 easeBoth: function (t, b, c, d) {
4541 if ((t /= d / 2) < 1) {
4542 return c / 2 * t * t + b;
4545 return -c / 2 * ((--t) * (t - 2) - 1) + b;
4549 easeInStrong: function (t, b, c, d) {
4550 return c * (t /= d) * t * t * t + b;
4554 easeOutStrong: function (t, b, c, d) {
4555 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
4559 easeBothStrong: function (t, b, c, d) {
4560 if ((t /= d / 2) < 1) {
4561 return c / 2 * t * t * t * t + b;
4564 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
4569 elasticIn: function (t, b, c, d, a, p) {
4573 if ((t /= d) == 1) {
4580 if (!a || a < Math.abs(c)) {
4585 var s = p / (2 * Math.PI) * Math.asin(c / a);
4588 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4592 elasticOut: function (t, b, c, d, a, p) {
4596 if ((t /= d) == 1) {
4603 if (!a || a < Math.abs(c)) {
4608 var s = p / (2 * Math.PI) * Math.asin(c / a);
4611 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
4615 elasticBoth: function (t, b, c, d, a, p) {
4620 if ((t /= d / 2) == 2) {
4628 if (!a || a < Math.abs(c)) {
4633 var s = p / (2 * Math.PI) * Math.asin(c / a);
4637 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
4638 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4640 return a * Math.pow(2, -10 * (t -= 1)) *
4641 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
4646 backIn: function (t, b, c, d, s) {
4647 if (typeof s == 'undefined') {
4650 return c * (t /= d) * t * ((s + 1) * t - s) + b;
4654 backOut: function (t, b, c, d, s) {
4655 if (typeof s == 'undefined') {
4658 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
4662 backBoth: function (t, b, c, d, s) {
4663 if (typeof s == 'undefined') {
4667 if ((t /= d / 2 ) < 1) {
4668 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
4670 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
4674 bounceIn: function (t, b, c, d) {
4675 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
4679 bounceOut: function (t, b, c, d) {
4680 if ((t /= d) < (1 / 2.75)) {
4681 return c * (7.5625 * t * t) + b;
4682 } else if (t < (2 / 2.75)) {
4683 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
4684 } else if (t < (2.5 / 2.75)) {
4685 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
4687 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
4691 bounceBoth: function (t, b, c, d) {
4693 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
4695 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
4698 * Portions of this file are based on pieces of Yahoo User Interface Library
4699 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4700 * YUI licensed under the BSD License:
4701 * http://developer.yahoo.net/yui/license.txt
4702 * <script type="text/javascript">
4706 Roo.lib.Motion = function(el, attributes, duration, method) {
4708 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
4712 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
4716 var superclass = Y.Motion.superclass;
4717 var proto = Y.Motion.prototype;
4719 proto.toString = function() {
4720 var el = this.getEl();
4721 var id = el.id || el.tagName;
4722 return ("Motion " + id);
4725 proto.patterns.points = /^points$/i;
4727 proto.setAttribute = function(attr, val, unit) {
4728 if (this.patterns.points.test(attr)) {
4729 unit = unit || 'px';
4730 superclass.setAttribute.call(this, 'left', val[0], unit);
4731 superclass.setAttribute.call(this, 'top', val[1], unit);
4733 superclass.setAttribute.call(this, attr, val, unit);
4737 proto.getAttribute = function(attr) {
4738 if (this.patterns.points.test(attr)) {
4740 superclass.getAttribute.call(this, 'left'),
4741 superclass.getAttribute.call(this, 'top')
4744 val = superclass.getAttribute.call(this, attr);
4750 proto.doMethod = function(attr, start, end) {
4753 if (this.patterns.points.test(attr)) {
4754 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4755 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4757 val = superclass.doMethod.call(this, attr, start, end);
4762 proto.setRuntimeAttribute = function(attr) {
4763 if (this.patterns.points.test(attr)) {
4764 var el = this.getEl();
4765 var attributes = this.attributes;
4767 var control = attributes['points']['control'] || [];
4771 if (control.length > 0 && !(control[0] instanceof Array)) {
4772 control = [control];
4775 for (i = 0,len = control.length; i < len; ++i) {
4776 tmp[i] = control[i];
4781 Roo.fly(el).position();
4783 if (isset(attributes['points']['from'])) {
4784 Roo.lib.Dom.setXY(el, attributes['points']['from']);
4787 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4790 start = this.getAttribute('points');
4793 if (isset(attributes['points']['to'])) {
4794 end = translateValues.call(this, attributes['points']['to'], start);
4796 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4797 for (i = 0,len = control.length; i < len; ++i) {
4798 control[i] = translateValues.call(this, control[i], start);
4802 } else if (isset(attributes['points']['by'])) {
4803 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4805 for (i = 0,len = control.length; i < len; ++i) {
4806 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4810 this.runtimeAttributes[attr] = [start];
4812 if (control.length > 0) {
4813 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4816 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4819 superclass.setRuntimeAttribute.call(this, attr);
4823 var translateValues = function(val, start) {
4824 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4825 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4830 var isset = function(prop) {
4831 return (typeof prop !== 'undefined');
4835 * Portions of this file are based on pieces of Yahoo User Interface Library
4836 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4837 * YUI licensed under the BSD License:
4838 * http://developer.yahoo.net/yui/license.txt
4839 * <script type="text/javascript">
4843 Roo.lib.Scroll = function(el, attributes, duration, method) {
4845 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4849 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4853 var superclass = Y.Scroll.superclass;
4854 var proto = Y.Scroll.prototype;
4856 proto.toString = function() {
4857 var el = this.getEl();
4858 var id = el.id || el.tagName;
4859 return ("Scroll " + id);
4862 proto.doMethod = function(attr, start, end) {
4865 if (attr == 'scroll') {
4867 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4868 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4872 val = superclass.doMethod.call(this, attr, start, end);
4877 proto.getAttribute = function(attr) {
4879 var el = this.getEl();
4881 if (attr == 'scroll') {
4882 val = [ el.scrollLeft, el.scrollTop ];
4884 val = superclass.getAttribute.call(this, attr);
4890 proto.setAttribute = function(attr, val, unit) {
4891 var el = this.getEl();
4893 if (attr == 'scroll') {
4894 el.scrollLeft = val[0];
4895 el.scrollTop = val[1];
4897 superclass.setAttribute.call(this, attr, val, unit);
4903 * Ext JS Library 1.1.1
4904 * Copyright(c) 2006-2007, Ext JS, LLC.
4906 * Originally Released Under LGPL - original licence link has changed is not relivant.
4909 * <script type="text/javascript">
4913 // nasty IE9 hack - what a pile of crap that is..
4915 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4916 Range.prototype.createContextualFragment = function (html) {
4917 var doc = window.document;
4918 var container = doc.createElement("div");
4919 container.innerHTML = html;
4920 var frag = doc.createDocumentFragment(), n;
4921 while ((n = container.firstChild)) {
4922 frag.appendChild(n);
4929 * @class Roo.DomHelper
4930 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4931 * 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>.
4934 Roo.DomHelper = function(){
4935 var tempTableEl = null;
4936 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4937 var tableRe = /^table|tbody|tr|td$/i;
4939 // build as innerHTML where available
4941 var createHtml = function(o){
4942 if(typeof o == 'string'){
4951 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4952 if(attr == "style"){
4954 if(typeof s == "function"){
4957 if(typeof s == "string"){
4958 b += ' style="' + s + '"';
4959 }else if(typeof s == "object"){
4962 if(typeof s[key] != "function"){
4963 b += key + ":" + s[key] + ";";
4970 b += ' class="' + o["cls"] + '"';
4971 }else if(attr == "htmlFor"){
4972 b += ' for="' + o["htmlFor"] + '"';
4974 b += " " + attr + '="' + o[attr] + '"';
4978 if(emptyTags.test(o.tag)){
4982 var cn = o.children || o.cn;
4984 //http://bugs.kde.org/show_bug.cgi?id=71506
4985 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4986 for(var i = 0, len = cn.length; i < len; i++) {
4987 b += createHtml(cn[i], b);
4990 b += createHtml(cn, b);
4996 b += "</" + o.tag + ">";
5003 var createDom = function(o, parentNode){
5005 // defininition craeted..
5007 if (o.ns && o.ns != 'html') {
5009 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
5010 xmlns[o.ns] = o.xmlns;
5013 if (typeof(xmlns[o.ns]) == 'undefined') {
5014 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
5020 if (typeof(o) == 'string') {
5021 return parentNode.appendChild(document.createTextNode(o));
5023 o.tag = o.tag || div;
5024 if (o.ns && Roo.isIE) {
5026 o.tag = o.ns + ':' + o.tag;
5029 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
5030 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
5033 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
5034 attr == "style" || typeof o[attr] == "function") { continue; }
5036 if(attr=="cls" && Roo.isIE){
5037 el.className = o["cls"];
5039 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
5045 Roo.DomHelper.applyStyles(el, o.style);
5046 var cn = o.children || o.cn;
5048 //http://bugs.kde.org/show_bug.cgi?id=71506
5049 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5050 for(var i = 0, len = cn.length; i < len; i++) {
5051 createDom(cn[i], el);
5058 el.innerHTML = o.html;
5061 parentNode.appendChild(el);
5066 var ieTable = function(depth, s, h, e){
5067 tempTableEl.innerHTML = [s, h, e].join('');
5068 var i = -1, el = tempTableEl;
5069 while(++i < depth && el.firstChild){
5075 // kill repeat to save bytes
5079 tbe = '</tbody>'+te,
5085 * Nasty code for IE's broken table implementation
5087 var insertIntoTable = function(tag, where, el, html){
5089 tempTableEl = document.createElement('div');
5094 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
5097 if(where == 'beforebegin'){
5101 before = el.nextSibling;
5104 node = ieTable(4, trs, html, tre);
5106 else if(tag == 'tr'){
5107 if(where == 'beforebegin'){
5110 node = ieTable(3, tbs, html, tbe);
5111 } else if(where == 'afterend'){
5112 before = el.nextSibling;
5114 node = ieTable(3, tbs, html, tbe);
5115 } else{ // INTO a TR
5116 if(where == 'afterbegin'){
5117 before = el.firstChild;
5119 node = ieTable(4, trs, html, tre);
5121 } else if(tag == 'tbody'){
5122 if(where == 'beforebegin'){
5125 node = ieTable(2, ts, html, te);
5126 } else if(where == 'afterend'){
5127 before = el.nextSibling;
5129 node = ieTable(2, ts, html, te);
5131 if(where == 'afterbegin'){
5132 before = el.firstChild;
5134 node = ieTable(3, tbs, html, tbe);
5137 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
5140 if(where == 'afterbegin'){
5141 before = el.firstChild;
5143 node = ieTable(2, ts, html, te);
5145 el.insertBefore(node, before);
5149 // this is a bit like the react update code...
5152 var updateNode = function(from, to)
5154 // should we handle non-standard elements?
5156 if (from.nodeType != to.nodeType) {
5157 from.parentNode.replaceChild(to, from);
5160 if (from.nodeType == 3) {
5161 // assume it's text?!
5162 if (from.data == to.data) {
5165 from.data = to.data;
5169 // assume 'to' doesnt have '1/3 nodetypes!
5170 if (from.nodeType !=1 || from.tagName != to.tagName) {
5171 from.parentNode.replaceChild(to, from);
5174 // compare attributes
5175 var ar = Array.from(from.attributes);
5176 for(var i = 0; i< ar.length;i++) {
5177 if (to.hasAttribute(ar[i].name)) {
5180 from.removeAttribute(ar[i].name);
5183 for(var i = 0; i< ar.length;i++) {
5184 if (from.getAttribute(ar[i].name) == to.getAttribute(ar[i].name)) {
5187 from.setAttribute(ar[i].name, to.getAttribute(ar[i].name));
5190 var far = Array.from(from.childNodes);
5191 var tar = Array.from(to.childNodes);
5192 for(var i = 0; i < Math.max(far.length, tar.length); i++) {
5193 if (i < far.length && i < tar.length) {
5194 updateNode(far[i], tar[i]);
5197 if (i < far.length) {
5198 // have from // but no 'to'
5199 from.removeChild(far[i]);
5202 from.appendChild(tar[i]);
5203 // have 'to' but no from
5212 /** True to force the use of DOM instead of html fragments @type Boolean */
5216 * Returns the markup for the passed Element(s) config
5217 * @param {Object} o The Dom object spec (and children)
5220 markup : function(o){
5221 return createHtml(o);
5225 * Applies a style specification to an element
5226 * @param {String/HTMLElement} el The element to apply styles to
5227 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
5228 * a function which returns such a specification.
5230 applyStyles : function(el, styles){
5233 if(typeof styles == "string"){
5234 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
5236 while ((matches = re.exec(styles)) != null){
5237 el.setStyle(matches[1], matches[2]);
5239 }else if (typeof styles == "object"){
5240 for (var style in styles){
5241 el.setStyle(style, styles[style]);
5243 }else if (typeof styles == "function"){
5244 Roo.DomHelper.applyStyles(el, styles.call());
5250 * Inserts an HTML fragment into the Dom
5251 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
5252 * @param {HTMLElement} el The context element
5253 * @param {String} html The HTML fragmenet
5254 * @return {HTMLElement} The new node
5256 insertHtml : function(where, el, html){
5257 where = where.toLowerCase();
5258 if(el.insertAdjacentHTML){
5259 if(tableRe.test(el.tagName)){
5261 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
5267 el.insertAdjacentHTML('BeforeBegin', html);
5268 return el.previousSibling;
5270 el.insertAdjacentHTML('AfterBegin', html);
5271 return el.firstChild;
5273 el.insertAdjacentHTML('BeforeEnd', html);
5274 return el.lastChild;
5276 el.insertAdjacentHTML('AfterEnd', html);
5277 return el.nextSibling;
5279 throw 'Illegal insertion point -> "' + where + '"';
5281 var range = el.ownerDocument.createRange();
5285 range.setStartBefore(el);
5286 frag = range.createContextualFragment(html);
5287 el.parentNode.insertBefore(frag, el);
5288 return el.previousSibling;
5291 range.setStartBefore(el.firstChild);
5292 frag = range.createContextualFragment(html);
5293 el.insertBefore(frag, el.firstChild);
5294 return el.firstChild;
5296 el.innerHTML = html;
5297 return el.firstChild;
5301 range.setStartAfter(el.lastChild);
5302 frag = range.createContextualFragment(html);
5303 el.appendChild(frag);
5304 return el.lastChild;
5306 el.innerHTML = html;
5307 return el.lastChild;
5310 range.setStartAfter(el);
5311 frag = range.createContextualFragment(html);
5312 el.parentNode.insertBefore(frag, el.nextSibling);
5313 return el.nextSibling;
5315 throw 'Illegal insertion point -> "' + where + '"';
5319 * Creates new Dom element(s) and inserts them before el
5320 * @param {String/HTMLElement/Element} el The context element
5321 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5322 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5323 * @return {HTMLElement/Roo.Element} The new node
5325 insertBefore : function(el, o, returnElement){
5326 return this.doInsert(el, o, returnElement, "beforeBegin");
5330 * Creates new Dom element(s) and inserts them after el
5331 * @param {String/HTMLElement/Element} el The context element
5332 * @param {Object} o The Dom object spec (and children)
5333 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5334 * @return {HTMLElement/Roo.Element} The new node
5336 insertAfter : function(el, o, returnElement){
5337 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
5341 * Creates new Dom element(s) and inserts them as the first child of el
5342 * @param {String/HTMLElement/Element} el The context element
5343 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5344 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5345 * @return {HTMLElement/Roo.Element} The new node
5347 insertFirst : function(el, o, returnElement){
5348 return this.doInsert(el, o, returnElement, "afterBegin");
5352 doInsert : function(el, o, returnElement, pos, sibling){
5353 el = Roo.getDom(el);
5355 if(this.useDom || o.ns){
5356 newNode = createDom(o, null);
5357 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
5359 var html = createHtml(o);
5360 newNode = this.insertHtml(pos, el, html);
5362 return returnElement ? Roo.get(newNode, true) : newNode;
5366 * Creates new Dom element(s) and appends them to el
5367 * @param {String/HTMLElement/Element} el The context element
5368 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5369 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5370 * @return {HTMLElement/Roo.Element} The new node
5372 append : function(el, o, returnElement){
5373 el = Roo.getDom(el);
5375 if(this.useDom || o.ns){
5376 newNode = createDom(o, null);
5377 el.appendChild(newNode);
5379 var html = createHtml(o);
5380 newNode = this.insertHtml("beforeEnd", el, html);
5382 return returnElement ? Roo.get(newNode, true) : newNode;
5386 * Creates new Dom element(s) and overwrites the contents of el with them
5387 * @param {String/HTMLElement/Element} el The context element
5388 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5389 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5390 * @return {HTMLElement/Roo.Element} The new node
5392 overwrite : function(el, o, returnElement)
5394 el = Roo.getDom(el);
5397 while (el.childNodes.length) {
5398 el.removeChild(el.firstChild);
5402 el.innerHTML = createHtml(o);
5405 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5409 * Creates a new Roo.DomHelper.Template from the Dom object spec
5410 * @param {Object} o The Dom object spec (and children)
5411 * @return {Roo.DomHelper.Template} The new template
5413 createTemplate : function(o){
5414 var html = createHtml(o);
5415 return new Roo.Template(html);
5418 * Updates the first element with the spec from the o (replacing if necessary)
5419 * This iterates through the children, and updates attributes / children etc..
5420 * @param {String/HTMLElement/Element} el The context element
5421 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5424 update : function(el, o)
5426 updateNode(Roo.getDom(el), createDom(o));
5435 * Ext JS Library 1.1.1
5436 * Copyright(c) 2006-2007, Ext JS, LLC.
5438 * Originally Released Under LGPL - original licence link has changed is not relivant.
5441 * <script type="text/javascript">
5445 * @class Roo.Template
5446 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
5447 * For a list of available format functions, see {@link Roo.util.Format}.<br />
5450 var t = new Roo.Template({
5451 html : '<div name="{id}">' +
5452 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
5454 myformat: function (value, allValues) {
5455 return 'XX' + value;
5458 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
5460 * For more information see this blog post with examples:
5461 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
5462 - Create Elements using DOM, HTML fragments and Templates</a>.
5464 * @param {Object} cfg - Configuration object.
5466 Roo.Template = function(cfg){
5468 if(cfg instanceof Array){
5470 }else if(arguments.length > 1){
5471 cfg = Array.prototype.join.call(arguments, "");
5475 if (typeof(cfg) == 'object') {
5486 Roo.Template.prototype = {
5489 * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
5495 * @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..
5496 * it should be fixed so that template is observable...
5500 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
5508 * Returns an HTML fragment of this template with the specified values applied.
5509 * @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'})
5510 * @return {String} The HTML fragment
5515 applyTemplate : function(values){
5516 //Roo.log(["applyTemplate", values]);
5520 return this.compiled(values);
5522 var useF = this.disableFormats !== true;
5523 var fm = Roo.util.Format, tpl = this;
5524 var fn = function(m, name, format, args){
5526 if(format.substr(0, 5) == "this."){
5527 return tpl.call(format.substr(5), values[name], values);
5530 // quoted values are required for strings in compiled templates,
5531 // but for non compiled we need to strip them
5532 // quoted reversed for jsmin
5533 var re = /^\s*['"](.*)["']\s*$/;
5534 args = args.split(',');
5535 for(var i = 0, len = args.length; i < len; i++){
5536 args[i] = args[i].replace(re, "$1");
5538 args = [values[name]].concat(args);
5540 args = [values[name]];
5542 return fm[format].apply(fm, args);
5545 return values[name] !== undefined ? values[name] : "";
5548 return this.html.replace(this.re, fn);
5566 this.loading = true;
5567 this.compiled = false;
5569 var cx = new Roo.data.Connection();
5573 success : function (response) {
5577 _t.set(response.responseText,true);
5583 failure : function(response) {
5584 Roo.log("Template failed to load from " + _t.url);
5591 * Sets the HTML used as the template and optionally compiles it.
5592 * @param {String} html
5593 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
5594 * @return {Roo.Template} this
5596 set : function(html, compile){
5598 this.compiled = false;
5606 * True to disable format functions (defaults to false)
5609 disableFormats : false,
5612 * The regular expression used to match template variables
5616 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
5619 * Compiles the template into an internal function, eliminating the RegEx overhead.
5620 * @return {Roo.Template} this
5622 compile : function(){
5623 var fm = Roo.util.Format;
5624 var useF = this.disableFormats !== true;
5625 var sep = Roo.isGecko ? "+" : ",";
5626 var fn = function(m, name, format, args){
5628 args = args ? ',' + args : "";
5629 if(format.substr(0, 5) != "this."){
5630 format = "fm." + format + '(';
5632 format = 'this.call("'+ format.substr(5) + '", ';
5636 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
5638 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
5641 // branched to use + in gecko and [].join() in others
5643 body = "this.compiled = function(values){ return '" +
5644 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
5647 body = ["this.compiled = function(values){ return ['"];
5648 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
5649 body.push("'].join('');};");
5650 body = body.join('');
5660 // private function used to call members
5661 call : function(fnName, value, allValues){
5662 return this[fnName](value, allValues);
5666 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
5667 * @param {String/HTMLElement/Roo.Element} el The context element
5668 * @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'})
5669 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5670 * @return {HTMLElement/Roo.Element} The new node or Element
5672 insertFirst: function(el, values, returnElement){
5673 return this.doInsert('afterBegin', el, values, returnElement);
5677 * Applies the supplied values to the template and inserts the new node(s) before el.
5678 * @param {String/HTMLElement/Roo.Element} el The context element
5679 * @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'})
5680 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5681 * @return {HTMLElement/Roo.Element} The new node or Element
5683 insertBefore: function(el, values, returnElement){
5684 return this.doInsert('beforeBegin', el, values, returnElement);
5688 * Applies the supplied values to the template and inserts the new node(s) after el.
5689 * @param {String/HTMLElement/Roo.Element} el The context element
5690 * @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'})
5691 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5692 * @return {HTMLElement/Roo.Element} The new node or Element
5694 insertAfter : function(el, values, returnElement){
5695 return this.doInsert('afterEnd', el, values, returnElement);
5699 * Applies the supplied values to the template and appends the new node(s) to el.
5700 * @param {String/HTMLElement/Roo.Element} el The context element
5701 * @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'})
5702 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5703 * @return {HTMLElement/Roo.Element} The new node or Element
5705 append : function(el, values, returnElement){
5706 return this.doInsert('beforeEnd', el, values, returnElement);
5709 doInsert : function(where, el, values, returnEl){
5710 el = Roo.getDom(el);
5711 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
5712 return returnEl ? Roo.get(newNode, true) : newNode;
5716 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
5717 * @param {String/HTMLElement/Roo.Element} el The context element
5718 * @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'})
5719 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5720 * @return {HTMLElement/Roo.Element} The new node or Element
5722 overwrite : function(el, values, returnElement){
5723 el = Roo.getDom(el);
5724 el.innerHTML = this.applyTemplate(values);
5725 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5729 * Alias for {@link #applyTemplate}
5732 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
5735 Roo.DomHelper.Template = Roo.Template;
5738 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
5739 * @param {String/HTMLElement} el A DOM element or its id
5740 * @returns {Roo.Template} The created template
5743 Roo.Template.from = function(el){
5744 el = Roo.getDom(el);
5745 return new Roo.Template(el.value || el.innerHTML);
5748 * Ext JS Library 1.1.1
5749 * Copyright(c) 2006-2007, Ext JS, LLC.
5751 * Originally Released Under LGPL - original licence link has changed is not relivant.
5754 * <script type="text/javascript">
5759 * This is code is also distributed under MIT license for use
5760 * with jQuery and prototype JavaScript libraries.
5763 * @class Roo.DomQuery
5764 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).
5766 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>
5769 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.
5771 <h4>Element Selectors:</h4>
5773 <li> <b>*</b> any element</li>
5774 <li> <b>E</b> an element with the tag E</li>
5775 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
5776 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
5777 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
5778 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
5780 <h4>Attribute Selectors:</h4>
5781 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
5783 <li> <b>E[foo]</b> has an attribute "foo"</li>
5784 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
5785 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
5786 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
5787 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
5788 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
5789 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
5791 <h4>Pseudo Classes:</h4>
5793 <li> <b>E:first-child</b> E is the first child of its parent</li>
5794 <li> <b>E:last-child</b> E is the last child of its parent</li>
5795 <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>
5796 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
5797 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
5798 <li> <b>E:only-child</b> E is the only child of its parent</li>
5799 <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>
5800 <li> <b>E:first</b> the first E in the resultset</li>
5801 <li> <b>E:last</b> the last E in the resultset</li>
5802 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
5803 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
5804 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
5805 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
5806 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
5807 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
5808 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
5809 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
5810 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
5812 <h4>CSS Value Selectors:</h4>
5814 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
5815 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
5816 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
5817 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
5818 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
5819 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
5823 Roo.DomQuery = function(){
5824 var cache = {}, simpleCache = {}, valueCache = {};
5825 var nonSpace = /\S/;
5826 var trimRe = /^\s+|\s+$/g;
5827 var tplRe = /\{(\d+)\}/g;
5828 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
5829 var tagTokenRe = /^(#)?([\w-\*]+)/;
5830 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
5832 function child(p, index){
5834 var n = p.firstChild;
5836 if(n.nodeType == 1){
5847 while((n = n.nextSibling) && n.nodeType != 1);
5852 while((n = n.previousSibling) && n.nodeType != 1);
5856 function children(d){
5857 var n = d.firstChild, ni = -1;
5859 var nx = n.nextSibling;
5860 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
5870 function byClassName(c, a, v){
5874 var r = [], ri = -1, cn;
5875 for(var i = 0, ci; ci = c[i]; i++){
5879 ( (ci instanceof SVGElement) ? ci.className.baseVal : ci.className)
5880 +' ').indexOf(v) != -1){
5887 function attrValue(n, attr){
5888 if(!n.tagName && typeof n.length != "undefined"){
5897 if(attr == "class" || attr == "className"){
5898 return (n instanceof SVGElement) ? n.className.baseVal : n.className;
5900 return n.getAttribute(attr) || n[attr];
5904 function getNodes(ns, mode, tagName){
5905 var result = [], ri = -1, cs;
5909 tagName = tagName || "*";
5910 if(typeof ns.getElementsByTagName != "undefined"){
5914 for(var i = 0, ni; ni = ns[i]; i++){
5915 cs = ni.getElementsByTagName(tagName);
5916 for(var j = 0, ci; ci = cs[j]; j++){
5920 }else if(mode == "/" || mode == ">"){
5921 var utag = tagName.toUpperCase();
5922 for(var i = 0, ni, cn; ni = ns[i]; i++){
5923 cn = ni.children || ni.childNodes;
5924 for(var j = 0, cj; cj = cn[j]; j++){
5925 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5930 }else if(mode == "+"){
5931 var utag = tagName.toUpperCase();
5932 for(var i = 0, n; n = ns[i]; i++){
5933 while((n = n.nextSibling) && n.nodeType != 1);
5934 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5938 }else if(mode == "~"){
5939 for(var i = 0, n; n = ns[i]; i++){
5940 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5949 function concat(a, b){
5953 for(var i = 0, l = b.length; i < l; i++){
5959 function byTag(cs, tagName){
5960 if(cs.tagName || cs == document){
5966 var r = [], ri = -1;
5967 tagName = tagName.toLowerCase();
5968 for(var i = 0, ci; ci = cs[i]; i++){
5969 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5976 function byId(cs, attr, id){
5977 if(cs.tagName || cs == document){
5983 var r = [], ri = -1;
5984 for(var i = 0,ci; ci = cs[i]; i++){
5985 if(ci && ci.id == id){
5993 function byAttribute(cs, attr, value, op, custom){
5994 var r = [], ri = -1, st = custom=="{";
5995 var f = Roo.DomQuery.operators[op];
5996 for(var i = 0, ci; ci = cs[i]; i++){
5999 a = Roo.DomQuery.getStyle(ci, attr);
6001 else if(attr == "class" || attr == "className"){
6002 a = (ci instanceof SVGElement) ? ci.className.baseVal : ci.className;
6003 }else if(attr == "for"){
6005 }else if(attr == "href"){
6006 a = ci.getAttribute("href", 2);
6008 a = ci.getAttribute(attr);
6010 if((f && f(a, value)) || (!f && a)){
6017 function byPseudo(cs, name, value){
6018 return Roo.DomQuery.pseudos[name](cs, value);
6021 // This is for IE MSXML which does not support expandos.
6022 // IE runs the same speed using setAttribute, however FF slows way down
6023 // and Safari completely fails so they need to continue to use expandos.
6024 var isIE = window.ActiveXObject ? true : false;
6026 // this eval is stop the compressor from
6027 // renaming the variable to something shorter
6029 /** eval:var:batch */
6034 function nodupIEXml(cs){
6036 cs[0].setAttribute("_nodup", d);
6038 for(var i = 1, len = cs.length; i < len; i++){
6040 if(!c.getAttribute("_nodup") != d){
6041 c.setAttribute("_nodup", d);
6045 for(var i = 0, len = cs.length; i < len; i++){
6046 cs[i].removeAttribute("_nodup");
6055 var len = cs.length, c, i, r = cs, cj, ri = -1;
6056 if(!len || typeof cs.nodeType != "undefined" || len == 1){
6059 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
6060 return nodupIEXml(cs);
6064 for(i = 1; c = cs[i]; i++){
6069 for(var j = 0; j < i; j++){
6072 for(j = i+1; cj = cs[j]; j++){
6084 function quickDiffIEXml(c1, c2){
6086 for(var i = 0, len = c1.length; i < len; i++){
6087 c1[i].setAttribute("_qdiff", d);
6090 for(var i = 0, len = c2.length; i < len; i++){
6091 if(c2[i].getAttribute("_qdiff") != d){
6092 r[r.length] = c2[i];
6095 for(var i = 0, len = c1.length; i < len; i++){
6096 c1[i].removeAttribute("_qdiff");
6101 function quickDiff(c1, c2){
6102 var len1 = c1.length;
6106 if(isIE && c1[0].selectSingleNode){
6107 return quickDiffIEXml(c1, c2);
6110 for(var i = 0; i < len1; i++){
6114 for(var i = 0, len = c2.length; i < len; i++){
6115 if(c2[i]._qdiff != d){
6116 r[r.length] = c2[i];
6122 function quickId(ns, mode, root, id){
6124 var d = root.ownerDocument || root;
6125 return d.getElementById(id);
6127 ns = getNodes(ns, mode, "*");
6128 return byId(ns, null, id);
6132 getStyle : function(el, name){
6133 return Roo.fly(el).getStyle(name);
6136 * Compiles a selector/xpath query into a reusable function. The returned function
6137 * takes one parameter "root" (optional), which is the context node from where the query should start.
6138 * @param {String} selector The selector/xpath query
6139 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
6140 * @return {Function}
6142 compile : function(path, type){
6143 type = type || "select";
6145 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
6146 var q = path, mode, lq;
6147 var tk = Roo.DomQuery.matchers;
6148 var tklen = tk.length;
6151 // accept leading mode switch
6152 var lmode = q.match(modeRe);
6153 if(lmode && lmode[1]){
6154 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
6155 q = q.replace(lmode[1], "");
6157 // strip leading slashes
6158 while(path.substr(0, 1)=="/"){
6159 path = path.substr(1);
6162 while(q && lq != q){
6164 var tm = q.match(tagTokenRe);
6165 if(type == "select"){
6168 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
6170 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
6172 q = q.replace(tm[0], "");
6173 }else if(q.substr(0, 1) != '@'){
6174 fn[fn.length] = 'n = getNodes(n, mode, "*");';
6179 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
6181 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
6183 q = q.replace(tm[0], "");
6186 while(!(mm = q.match(modeRe))){
6187 var matched = false;
6188 for(var j = 0; j < tklen; j++){
6190 var m = q.match(t.re);
6192 fn[fn.length] = t.select.replace(tplRe, function(x, i){
6195 q = q.replace(m[0], "");
6200 // prevent infinite loop on bad selector
6202 throw 'Error parsing selector, parsing failed at "' + q + '"';
6206 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
6207 q = q.replace(mm[1], "");
6210 fn[fn.length] = "return nodup(n);\n}";
6213 * list of variables that need from compression as they are used by eval.
6223 * eval:var:byClassName
6225 * eval:var:byAttribute
6226 * eval:var:attrValue
6234 * Selects a group of elements.
6235 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
6236 * @param {Node} root (optional) The start of the query (defaults to document).
6239 select : function(path, root, type){
6240 if(!root || root == document){
6243 if(typeof root == "string"){
6244 root = document.getElementById(root);
6246 var paths = path.split(",");
6248 for(var i = 0, len = paths.length; i < len; i++){
6249 var p = paths[i].replace(trimRe, "");
6251 cache[p] = Roo.DomQuery.compile(p);
6253 throw p + " is not a valid selector";
6256 var result = cache[p](root);
6257 if(result && result != document){
6258 results = results.concat(result);
6261 if(paths.length > 1){
6262 return nodup(results);
6268 * Selects a single element.
6269 * @param {String} selector The selector/xpath query
6270 * @param {Node} root (optional) The start of the query (defaults to document).
6273 selectNode : function(path, root){
6274 return Roo.DomQuery.select(path, root)[0];
6278 * Selects the value of a node, optionally replacing null with the defaultValue.
6279 * @param {String} selector The selector/xpath query
6280 * @param {Node} root (optional) The start of the query (defaults to document).
6281 * @param {String} defaultValue
6283 selectValue : function(path, root, defaultValue){
6284 path = path.replace(trimRe, "");
6285 if(!valueCache[path]){
6286 valueCache[path] = Roo.DomQuery.compile(path, "select");
6288 var n = valueCache[path](root);
6289 n = n[0] ? n[0] : n;
6290 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
6291 return ((v === null||v === undefined||v==='') ? defaultValue : v);
6295 * Selects the value of a node, parsing integers and floats.
6296 * @param {String} selector The selector/xpath query
6297 * @param {Node} root (optional) The start of the query (defaults to document).
6298 * @param {Number} defaultValue
6301 selectNumber : function(path, root, defaultValue){
6302 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
6303 return parseFloat(v);
6307 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
6308 * @param {String/HTMLElement/Array} el An element id, element or array of elements
6309 * @param {String} selector The simple selector to test
6312 is : function(el, ss){
6313 if(typeof el == "string"){
6314 el = document.getElementById(el);
6316 var isArray = (el instanceof Array);
6317 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
6318 return isArray ? (result.length == el.length) : (result.length > 0);
6322 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
6323 * @param {Array} el An array of elements to filter
6324 * @param {String} selector The simple selector to test
6325 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
6326 * the selector instead of the ones that match
6329 filter : function(els, ss, nonMatches){
6330 ss = ss.replace(trimRe, "");
6331 if(!simpleCache[ss]){
6332 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
6334 var result = simpleCache[ss](els);
6335 return nonMatches ? quickDiff(result, els) : result;
6339 * Collection of matching regular expressions and code snippets.
6343 select: 'n = byClassName(n, null, " {1} ");'
6345 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
6346 select: 'n = byPseudo(n, "{1}", "{2}");'
6348 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
6349 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
6352 select: 'n = byId(n, null, "{1}");'
6355 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
6360 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
6361 * 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, > <.
6364 "=" : function(a, v){
6367 "!=" : function(a, v){
6370 "^=" : function(a, v){
6371 return a && a.substr(0, v.length) == v;
6373 "$=" : function(a, v){
6374 return a && a.substr(a.length-v.length) == v;
6376 "*=" : function(a, v){
6377 return a && a.indexOf(v) !== -1;
6379 "%=" : function(a, v){
6380 return (a % v) == 0;
6382 "|=" : function(a, v){
6383 return a && (a == v || a.substr(0, v.length+1) == v+'-');
6385 "~=" : function(a, v){
6386 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
6391 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
6392 * and the argument (if any) supplied in the selector.
6395 "first-child" : function(c){
6396 var r = [], ri = -1, n;
6397 for(var i = 0, ci; ci = n = c[i]; i++){
6398 while((n = n.previousSibling) && n.nodeType != 1);
6406 "last-child" : function(c){
6407 var r = [], ri = -1, n;
6408 for(var i = 0, ci; ci = n = c[i]; i++){
6409 while((n = n.nextSibling) && n.nodeType != 1);
6417 "nth-child" : function(c, a) {
6418 var r = [], ri = -1;
6419 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
6420 var f = (m[1] || 1) - 0, l = m[2] - 0;
6421 for(var i = 0, n; n = c[i]; i++){
6422 var pn = n.parentNode;
6423 if (batch != pn._batch) {
6425 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
6426 if(cn.nodeType == 1){
6433 if (l == 0 || n.nodeIndex == l){
6436 } else if ((n.nodeIndex + l) % f == 0){
6444 "only-child" : function(c){
6445 var r = [], ri = -1;;
6446 for(var i = 0, ci; ci = c[i]; i++){
6447 if(!prev(ci) && !next(ci)){
6454 "empty" : function(c){
6455 var r = [], ri = -1;
6456 for(var i = 0, ci; ci = c[i]; i++){
6457 var cns = ci.childNodes, j = 0, cn, empty = true;
6460 if(cn.nodeType == 1 || cn.nodeType == 3){
6472 "contains" : function(c, v){
6473 var r = [], ri = -1;
6474 for(var i = 0, ci; ci = c[i]; i++){
6475 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
6482 "nodeValue" : function(c, v){
6483 var r = [], ri = -1;
6484 for(var i = 0, ci; ci = c[i]; i++){
6485 if(ci.firstChild && ci.firstChild.nodeValue == v){
6492 "checked" : function(c){
6493 var r = [], ri = -1;
6494 for(var i = 0, ci; ci = c[i]; i++){
6495 if(ci.checked == true){
6502 "not" : function(c, ss){
6503 return Roo.DomQuery.filter(c, ss, true);
6506 "odd" : function(c){
6507 return this["nth-child"](c, "odd");
6510 "even" : function(c){
6511 return this["nth-child"](c, "even");
6514 "nth" : function(c, a){
6515 return c[a-1] || [];
6518 "first" : function(c){
6522 "last" : function(c){
6523 return c[c.length-1] || [];
6526 "has" : function(c, ss){
6527 var s = Roo.DomQuery.select;
6528 var r = [], ri = -1;
6529 for(var i = 0, ci; ci = c[i]; i++){
6530 if(s(ss, ci).length > 0){
6537 "next" : function(c, ss){
6538 var is = Roo.DomQuery.is;
6539 var r = [], ri = -1;
6540 for(var i = 0, ci; ci = c[i]; i++){
6549 "prev" : function(c, ss){
6550 var is = Roo.DomQuery.is;
6551 var r = [], ri = -1;
6552 for(var i = 0, ci; ci = c[i]; i++){
6565 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
6566 * @param {String} path The selector/xpath query
6567 * @param {Node} root (optional) The start of the query (defaults to document).
6572 Roo.query = Roo.DomQuery.select;
6575 * Ext JS Library 1.1.1
6576 * Copyright(c) 2006-2007, Ext JS, LLC.
6578 * Originally Released Under LGPL - original licence link has changed is not relivant.
6581 * <script type="text/javascript">
6585 * @class Roo.util.Observable
6586 * Base class that provides a common interface for publishing events. Subclasses are expected to
6587 * to have a property "events" with all the events defined.<br>
6590 Employee = function(name){
6597 Roo.extend(Employee, Roo.util.Observable);
6599 * @param {Object} config properties to use (incuding events / listeners)
6602 Roo.util.Observable = function(cfg){
6605 this.addEvents(cfg.events || {});
6607 delete cfg.events; // make sure
6610 Roo.apply(this, cfg);
6613 this.on(this.listeners);
6614 delete this.listeners;
6617 Roo.util.Observable.prototype = {
6619 * @cfg {Object} listeners list of events and functions to call for this object,
6623 'click' : function(e) {
6633 * Fires the specified event with the passed parameters (minus the event name).
6634 * @param {String} eventName
6635 * @param {Object...} args Variable number of parameters are passed to handlers
6636 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
6638 fireEvent : function(){
6639 var ce = this.events[arguments[0].toLowerCase()];
6640 if(typeof ce == "object"){
6641 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
6648 filterOptRe : /^(?:scope|delay|buffer|single)$/,
6651 * Appends an event handler to this component
6652 * @param {String} eventName The type of event to listen for
6653 * @param {Function} handler The method the event invokes
6654 * @param {Object} scope (optional) The scope in which to execute the handler
6655 * function. The handler function's "this" context.
6656 * @param {Object} options (optional) An object containing handler configuration
6657 * properties. This may contain any of the following properties:<ul>
6658 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6659 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6660 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6661 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6662 * by the specified number of milliseconds. If the event fires again within that time, the original
6663 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6666 * <b>Combining Options</b><br>
6667 * Using the options argument, it is possible to combine different types of listeners:<br>
6669 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
6671 el.on('click', this.onClick, this, {
6678 * <b>Attaching multiple handlers in 1 call</b><br>
6679 * The method also allows for a single argument to be passed which is a config object containing properties
6680 * which specify multiple handlers.
6689 fn: this.onMouseOver,
6693 fn: this.onMouseOut,
6699 * Or a shorthand syntax which passes the same scope object to all handlers:
6702 'click': this.onClick,
6703 'mouseover': this.onMouseOver,
6704 'mouseout': this.onMouseOut,
6709 addListener : function(eventName, fn, scope, o){
6710 if(typeof eventName == "object"){
6713 if(this.filterOptRe.test(e)){
6716 if(typeof o[e] == "function"){
6718 this.addListener(e, o[e], o.scope, o);
6720 // individual options
6721 this.addListener(e, o[e].fn, o[e].scope, o[e]);
6726 o = (!o || typeof o == "boolean") ? {} : o;
6727 eventName = eventName.toLowerCase();
6728 var ce = this.events[eventName] || true;
6729 if(typeof ce == "boolean"){
6730 ce = new Roo.util.Event(this, eventName);
6731 this.events[eventName] = ce;
6733 ce.addListener(fn, scope, o);
6737 * Removes a listener
6738 * @param {String} eventName The type of event to listen for
6739 * @param {Function} handler The handler to remove
6740 * @param {Object} scope (optional) The scope (this object) for the handler
6742 removeListener : function(eventName, fn, scope){
6743 var ce = this.events[eventName.toLowerCase()];
6744 if(typeof ce == "object"){
6745 ce.removeListener(fn, scope);
6750 * Removes all listeners for this object
6752 purgeListeners : function(){
6753 for(var evt in this.events){
6754 if(typeof this.events[evt] == "object"){
6755 this.events[evt].clearListeners();
6760 relayEvents : function(o, events){
6761 var createHandler = function(ename){
6764 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
6767 for(var i = 0, len = events.length; i < len; i++){
6768 var ename = events[i];
6769 if(!this.events[ename]){
6770 this.events[ename] = true;
6772 o.on(ename, createHandler(ename), this);
6777 * Used to define events on this Observable
6778 * @param {Object} object The object with the events defined
6780 addEvents : function(o){
6784 Roo.applyIf(this.events, o);
6788 * Checks to see if this object has any listeners for a specified event
6789 * @param {String} eventName The name of the event to check for
6790 * @return {Boolean} True if the event is being listened for, else false
6792 hasListener : function(eventName){
6793 var e = this.events[eventName];
6794 return typeof e == "object" && e.listeners.length > 0;
6798 * Appends an event handler to this element (shorthand for addListener)
6799 * @param {String} eventName The type of event to listen for
6800 * @param {Function} handler The method the event invokes
6801 * @param {Object} scope (optional) The scope in which to execute the handler
6802 * function. The handler function's "this" context.
6803 * @param {Object} options (optional)
6806 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
6808 * Removes a listener (shorthand for removeListener)
6809 * @param {String} eventName The type of event to listen for
6810 * @param {Function} handler The handler to remove
6811 * @param {Object} scope (optional) The scope (this object) for the handler
6814 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
6817 * Starts capture on the specified Observable. All events will be passed
6818 * to the supplied function with the event name + standard signature of the event
6819 * <b>before</b> the event is fired. If the supplied function returns false,
6820 * the event will not fire.
6821 * @param {Observable} o The Observable to capture
6822 * @param {Function} fn The function to call
6823 * @param {Object} scope (optional) The scope (this object) for the fn
6826 Roo.util.Observable.capture = function(o, fn, scope){
6827 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
6831 * Removes <b>all</b> added captures from the Observable.
6832 * @param {Observable} o The Observable to release
6835 Roo.util.Observable.releaseCapture = function(o){
6836 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
6841 var createBuffered = function(h, o, scope){
6842 var task = new Roo.util.DelayedTask();
6844 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
6848 var createSingle = function(h, e, fn, scope){
6850 e.removeListener(fn, scope);
6851 return h.apply(scope, arguments);
6855 var createDelayed = function(h, o, scope){
6857 var args = Array.prototype.slice.call(arguments, 0);
6858 setTimeout(function(){
6859 h.apply(scope, args);
6864 Roo.util.Event = function(obj, name){
6867 this.listeners = [];
6870 Roo.util.Event.prototype = {
6871 addListener : function(fn, scope, options){
6872 var o = options || {};
6873 scope = scope || this.obj;
6874 if(!this.isListening(fn, scope)){
6875 var l = {fn: fn, scope: scope, options: o};
6878 h = createDelayed(h, o, scope);
6881 h = createSingle(h, this, fn, scope);
6884 h = createBuffered(h, o, scope);
6887 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6888 this.listeners.push(l);
6890 this.listeners = this.listeners.slice(0);
6891 this.listeners.push(l);
6896 findListener : function(fn, scope){
6897 scope = scope || this.obj;
6898 var ls = this.listeners;
6899 for(var i = 0, len = ls.length; i < len; i++){
6901 if(l.fn == fn && l.scope == scope){
6908 isListening : function(fn, scope){
6909 return this.findListener(fn, scope) != -1;
6912 removeListener : function(fn, scope){
6914 if((index = this.findListener(fn, scope)) != -1){
6916 this.listeners.splice(index, 1);
6918 this.listeners = this.listeners.slice(0);
6919 this.listeners.splice(index, 1);
6926 clearListeners : function(){
6927 this.listeners = [];
6931 var ls = this.listeners, scope, len = ls.length;
6934 var args = Array.prototype.slice.call(arguments, 0);
6935 for(var i = 0; i < len; i++){
6937 if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
6938 this.firing = false;
6942 this.firing = false;
6949 * Copyright(c) 2007-2017, Roo J Solutions Ltd
6956 * @class Roo.Document
6957 * @extends Roo.util.Observable
6958 * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6960 * @param {Object} config the methods and properties of the 'base' class for the application.
6962 * Generic Page handler - implement this to start your app..
6965 * MyProject = new Roo.Document({
6967 'load' : true // your events..
6970 'ready' : function() {
6971 // fired on Roo.onReady()
6976 Roo.Document = function(cfg) {
6981 Roo.util.Observable.call(this,cfg);
6985 Roo.onReady(function() {
6986 _this.fireEvent('ready');
6992 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6994 * Ext JS Library 1.1.1
6995 * Copyright(c) 2006-2007, Ext JS, LLC.
6997 * Originally Released Under LGPL - original licence link has changed is not relivant.
7000 * <script type="text/javascript">
7004 * @class Roo.EventManager
7005 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
7006 * several useful events directly.
7007 * See {@link Roo.EventObject} for more details on normalized event objects.
7010 Roo.EventManager = function(){
7011 var docReadyEvent, docReadyProcId, docReadyState = false;
7012 var resizeEvent, resizeTask, textEvent, textSize;
7013 var E = Roo.lib.Event;
7014 var D = Roo.lib.Dom;
7019 var fireDocReady = function(){
7021 docReadyState = true;
7024 clearInterval(docReadyProcId);
7026 if(Roo.isGecko || Roo.isOpera) {
7027 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
7030 var defer = document.getElementById("ie-deferred-loader");
7032 defer.onreadystatechange = null;
7033 defer.parentNode.removeChild(defer);
7037 docReadyEvent.fire();
7038 docReadyEvent.clearListeners();
7043 var initDocReady = function(){
7044 docReadyEvent = new Roo.util.Event();
7045 if(Roo.isGecko || Roo.isOpera) {
7046 document.addEventListener("DOMContentLoaded", fireDocReady, false);
7048 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
7049 var defer = document.getElementById("ie-deferred-loader");
7050 defer.onreadystatechange = function(){
7051 if(this.readyState == "complete"){
7055 }else if(Roo.isSafari){
7056 docReadyProcId = setInterval(function(){
7057 var rs = document.readyState;
7058 if(rs == "complete") {
7063 // no matter what, make sure it fires on load
7064 E.on(window, "load", fireDocReady);
7067 var createBuffered = function(h, o){
7068 var task = new Roo.util.DelayedTask(h);
7070 // create new event object impl so new events don't wipe out properties
7071 e = new Roo.EventObjectImpl(e);
7072 task.delay(o.buffer, h, null, [e]);
7076 var createSingle = function(h, el, ename, fn){
7078 Roo.EventManager.removeListener(el, ename, fn);
7083 var createDelayed = function(h, o){
7085 // create new event object impl so new events don't wipe out properties
7086 e = new Roo.EventObjectImpl(e);
7087 setTimeout(function(){
7092 var transitionEndVal = false;
7094 var transitionEnd = function()
7096 if (transitionEndVal) {
7097 return transitionEndVal;
7099 var el = document.createElement('div');
7101 var transEndEventNames = {
7102 WebkitTransition : 'webkitTransitionEnd',
7103 MozTransition : 'transitionend',
7104 OTransition : 'oTransitionEnd otransitionend',
7105 transition : 'transitionend'
7108 for (var name in transEndEventNames) {
7109 if (el.style[name] !== undefined) {
7110 transitionEndVal = transEndEventNames[name];
7111 return transitionEndVal ;
7118 var listen = function(element, ename, opt, fn, scope)
7120 var o = (!opt || typeof opt == "boolean") ? {} : opt;
7121 fn = fn || o.fn; scope = scope || o.scope;
7122 var el = Roo.getDom(element);
7126 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
7129 if (ename == 'transitionend') {
7130 ename = transitionEnd();
7132 var h = function(e){
7133 e = Roo.EventObject.setEvent(e);
7136 t = e.getTarget(o.delegate, el);
7143 if(o.stopEvent === true){
7146 if(o.preventDefault === true){
7149 if(o.stopPropagation === true){
7150 e.stopPropagation();
7153 if(o.normalized === false){
7157 fn.call(scope || el, e, t, o);
7160 h = createDelayed(h, o);
7163 h = createSingle(h, el, ename, fn);
7166 h = createBuffered(h, o);
7169 fn._handlers = fn._handlers || [];
7172 fn._handlers.push([Roo.id(el), ename, h]);
7176 E.on(el, ename, h); // this adds the actuall listener to the object..
7179 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
7180 el.addEventListener("DOMMouseScroll", h, false);
7181 E.on(window, 'unload', function(){
7182 el.removeEventListener("DOMMouseScroll", h, false);
7185 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7186 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
7191 var stopListening = function(el, ename, fn){
7192 var id = Roo.id(el), hds = fn._handlers, hd = fn;
7194 for(var i = 0, len = hds.length; i < len; i++){
7196 if(h[0] == id && h[1] == ename){
7203 E.un(el, ename, hd);
7204 el = Roo.getDom(el);
7205 if(ename == "mousewheel" && el.addEventListener){
7206 el.removeEventListener("DOMMouseScroll", hd, false);
7208 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7209 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
7213 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
7220 * @scope Roo.EventManager
7225 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
7226 * object with a Roo.EventObject
7227 * @param {Function} fn The method the event invokes
7228 * @param {Object} scope An object that becomes the scope of the handler
7229 * @param {boolean} override If true, the obj passed in becomes
7230 * the execution scope of the listener
7231 * @return {Function} The wrapped function
7234 wrap : function(fn, scope, override){
7236 Roo.EventObject.setEvent(e);
7237 fn.call(override ? scope || window : window, Roo.EventObject, scope);
7242 * Appends an event handler to an element (shorthand for addListener)
7243 * @param {String/HTMLElement} element The html element or id to assign the
7244 * @param {String} eventName The type of event to listen for
7245 * @param {Function} handler The method the event invokes
7246 * @param {Object} scope (optional) The scope in which to execute the handler
7247 * function. The handler function's "this" context.
7248 * @param {Object} options (optional) An object containing handler configuration
7249 * properties. This may contain any of the following properties:<ul>
7250 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7251 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7252 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7253 * <li>preventDefault {Boolean} True to prevent the default action</li>
7254 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7255 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7256 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7257 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7258 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7259 * by the specified number of milliseconds. If the event fires again within that time, the original
7260 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7263 * <b>Combining Options</b><br>
7264 * Using the options argument, it is possible to combine different types of listeners:<br>
7266 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7268 el.on('click', this.onClick, this, {
7275 * <b>Attaching multiple handlers in 1 call</b><br>
7276 * The method also allows for a single argument to be passed which is a config object containing properties
7277 * which specify multiple handlers.
7287 fn: this.onMouseOver
7296 * Or a shorthand syntax:<br>
7299 'click' : this.onClick,
7300 'mouseover' : this.onMouseOver,
7301 'mouseout' : this.onMouseOut
7305 addListener : function(element, eventName, fn, scope, options){
7306 if(typeof eventName == "object"){
7312 if(typeof o[e] == "function"){
7314 listen(element, e, o, o[e], o.scope);
7316 // individual options
7317 listen(element, e, o[e]);
7322 return listen(element, eventName, options, fn, scope);
7326 * Removes an event handler
7328 * @param {String/HTMLElement} element The id or html element to remove the
7330 * @param {String} eventName The type of event
7331 * @param {Function} fn
7332 * @return {Boolean} True if a listener was actually removed
7334 removeListener : function(element, eventName, fn){
7335 return stopListening(element, eventName, fn);
7339 * Fires when the document is ready (before onload and before images are loaded). Can be
7340 * accessed shorthanded Roo.onReady().
7341 * @param {Function} fn The method the event invokes
7342 * @param {Object} scope An object that becomes the scope of the handler
7343 * @param {boolean} options
7345 onDocumentReady : function(fn, scope, options){
7346 if(docReadyState){ // if it already fired
7347 docReadyEvent.addListener(fn, scope, options);
7348 docReadyEvent.fire();
7349 docReadyEvent.clearListeners();
7355 docReadyEvent.addListener(fn, scope, options);
7359 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
7360 * @param {Function} fn The method the event invokes
7361 * @param {Object} scope An object that becomes the scope of the handler
7362 * @param {boolean} options
7364 onWindowResize : function(fn, scope, options)
7367 resizeEvent = new Roo.util.Event();
7368 resizeTask = new Roo.util.DelayedTask(function(){
7369 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7371 E.on(window, "resize", function()
7374 resizeTask.delay(50);
7376 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7380 resizeEvent.addListener(fn, scope, options);
7384 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
7385 * @param {Function} fn The method the event invokes
7386 * @param {Object} scope An object that becomes the scope of the handler
7387 * @param {boolean} options
7389 onTextResize : function(fn, scope, options){
7391 textEvent = new Roo.util.Event();
7392 var textEl = new Roo.Element(document.createElement('div'));
7393 textEl.dom.className = 'x-text-resize';
7394 textEl.dom.innerHTML = 'X';
7395 textEl.appendTo(document.body);
7396 textSize = textEl.dom.offsetHeight;
7397 setInterval(function(){
7398 if(textEl.dom.offsetHeight != textSize){
7399 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
7401 }, this.textResizeInterval);
7403 textEvent.addListener(fn, scope, options);
7407 * Removes the passed window resize listener.
7408 * @param {Function} fn The method the event invokes
7409 * @param {Object} scope The scope of handler
7411 removeResizeListener : function(fn, scope){
7413 resizeEvent.removeListener(fn, scope);
7418 fireResize : function(){
7420 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7424 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
7428 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
7430 textResizeInterval : 50
7435 * @scopeAlias pub=Roo.EventManager
7439 * Appends an event handler to an element (shorthand for addListener)
7440 * @param {String/HTMLElement} element The html element or id to assign the
7441 * @param {String} eventName The type of event to listen for
7442 * @param {Function} handler The method the event invokes
7443 * @param {Object} scope (optional) The scope in which to execute the handler
7444 * function. The handler function's "this" context.
7445 * @param {Object} options (optional) An object containing handler configuration
7446 * properties. This may contain any of the following properties:<ul>
7447 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7448 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7449 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7450 * <li>preventDefault {Boolean} True to prevent the default action</li>
7451 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7452 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7453 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7454 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7455 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7456 * by the specified number of milliseconds. If the event fires again within that time, the original
7457 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7460 * <b>Combining Options</b><br>
7461 * Using the options argument, it is possible to combine different types of listeners:<br>
7463 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7465 el.on('click', this.onClick, this, {
7472 * <b>Attaching multiple handlers in 1 call</b><br>
7473 * The method also allows for a single argument to be passed which is a config object containing properties
7474 * which specify multiple handlers.
7484 fn: this.onMouseOver
7493 * Or a shorthand syntax:<br>
7496 'click' : this.onClick,
7497 'mouseover' : this.onMouseOver,
7498 'mouseout' : this.onMouseOut
7502 pub.on = pub.addListener;
7503 pub.un = pub.removeListener;
7505 pub.stoppedMouseDownEvent = new Roo.util.Event();
7509 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
7510 * @param {Function} fn The method the event invokes
7511 * @param {Object} scope An object that becomes the scope of the handler
7512 * @param {boolean} override If true, the obj passed in becomes
7513 * the execution scope of the listener
7517 Roo.onReady = Roo.EventManager.onDocumentReady;
7519 Roo.onReady(function(){
7520 var bd = Roo.get(document.body);
7525 : Roo.isIE11 ? "roo-ie11"
7526 : Roo.isEdge ? "roo-edge"
7527 : Roo.isGecko ? "roo-gecko"
7528 : Roo.isOpera ? "roo-opera"
7529 : Roo.isSafari ? "roo-safari" : ""];
7532 cls.push("roo-mac");
7535 cls.push("roo-linux");
7538 cls.push("roo-ios");
7541 cls.push("roo-touch");
7543 if(Roo.isBorderBox){
7544 cls.push('roo-border-box');
7546 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
7547 var p = bd.dom.parentNode;
7549 p.className += ' roo-strict';
7552 bd.addClass(cls.join(' '));
7556 * @class Roo.EventObject
7557 * EventObject exposes the Yahoo! UI Event functionality directly on the object
7558 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
7561 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
7563 var target = e.getTarget();
7566 var myDiv = Roo.get("myDiv");
7567 myDiv.on("click", handleClick);
7569 Roo.EventManager.on("myDiv", 'click', handleClick);
7570 Roo.EventManager.addListener("myDiv", 'click', handleClick);
7574 Roo.EventObject = function(){
7576 var E = Roo.lib.Event;
7578 // safari keypress events for special keys return bad keycodes
7581 63235 : 39, // right
7584 63276 : 33, // page up
7585 63277 : 34, // page down
7586 63272 : 46, // delete
7591 // normalize button clicks
7592 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
7593 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
7595 Roo.EventObjectImpl = function(e){
7597 this.setEvent(e.browserEvent || e);
7600 Roo.EventObjectImpl.prototype = {
7602 * Used to fix doc tools.
7603 * @scope Roo.EventObject.prototype
7609 /** The normal browser event */
7610 browserEvent : null,
7611 /** The button pressed in a mouse event */
7613 /** True if the shift key was down during the event */
7615 /** True if the control key was down during the event */
7617 /** True if the alt key was down during the event */
7676 setEvent : function(e){
7677 if(e == this || (e && e.browserEvent)){ // already wrapped
7680 this.browserEvent = e;
7682 // normalize buttons
7683 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
7684 if(e.type == 'click' && this.button == -1){
7688 this.shiftKey = e.shiftKey;
7689 // mac metaKey behaves like ctrlKey
7690 this.ctrlKey = e.ctrlKey || e.metaKey;
7691 this.altKey = e.altKey;
7692 // in getKey these will be normalized for the mac
7693 this.keyCode = e.keyCode;
7694 // keyup warnings on firefox.
7695 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
7696 // cache the target for the delayed and or buffered events
7697 this.target = E.getTarget(e);
7699 this.xy = E.getXY(e);
7702 this.shiftKey = false;
7703 this.ctrlKey = false;
7704 this.altKey = false;
7714 * Stop the event (preventDefault and stopPropagation)
7716 stopEvent : function(){
7717 if(this.browserEvent){
7718 if(this.browserEvent.type == 'mousedown'){
7719 Roo.EventManager.stoppedMouseDownEvent.fire(this);
7721 E.stopEvent(this.browserEvent);
7726 * Prevents the browsers default handling of the event.
7728 preventDefault : function(){
7729 if(this.browserEvent){
7730 E.preventDefault(this.browserEvent);
7735 isNavKeyPress : function(){
7736 var k = this.keyCode;
7737 k = Roo.isSafari ? (safariKeys[k] || k) : k;
7738 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
7741 isSpecialKey : function(){
7742 var k = this.keyCode;
7743 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
7744 (k == 16) || (k == 17) ||
7745 (k >= 18 && k <= 20) ||
7746 (k >= 33 && k <= 35) ||
7747 (k >= 36 && k <= 39) ||
7748 (k >= 44 && k <= 45);
7751 * Cancels bubbling of the event.
7753 stopPropagation : function(){
7754 if(this.browserEvent){
7755 if(this.type == 'mousedown'){
7756 Roo.EventManager.stoppedMouseDownEvent.fire(this);
7758 E.stopPropagation(this.browserEvent);
7763 * Gets the key code for the event.
7766 getCharCode : function(){
7767 return this.charCode || this.keyCode;
7771 * Returns a normalized keyCode for the event.
7772 * @return {Number} The key code
7774 getKey : function(){
7775 var k = this.keyCode || this.charCode;
7776 return Roo.isSafari ? (safariKeys[k] || k) : k;
7780 * Gets the x coordinate of the event.
7783 getPageX : function(){
7788 * Gets the y coordinate of the event.
7791 getPageY : function(){
7796 * Gets the time of the event.
7799 getTime : function(){
7800 if(this.browserEvent){
7801 return E.getTime(this.browserEvent);
7807 * Gets the page coordinates of the event.
7808 * @return {Array} The xy values like [x, y]
7815 * Gets the target for the event.
7816 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
7817 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7818 search as a number or element (defaults to 10 || document.body)
7819 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7820 * @return {HTMLelement}
7822 getTarget : function(selector, maxDepth, returnEl){
7823 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
7826 * Gets the related target.
7827 * @return {HTMLElement}
7829 getRelatedTarget : function(){
7830 if(this.browserEvent){
7831 return E.getRelatedTarget(this.browserEvent);
7837 * Normalizes mouse wheel delta across browsers
7838 * @return {Number} The delta
7840 getWheelDelta : function(){
7841 var e = this.browserEvent;
7843 if(e.wheelDelta){ /* IE/Opera. */
7844 delta = e.wheelDelta/120;
7845 }else if(e.detail){ /* Mozilla case. */
7846 delta = -e.detail/3;
7852 * Returns true if the control, meta, shift or alt key was pressed during this event.
7855 hasModifier : function(){
7856 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
7860 * Returns true if the target of this event equals el or is a child of el
7861 * @param {String/HTMLElement/Element} el
7862 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
7865 within : function(el, related){
7866 var t = this[related ? "getRelatedTarget" : "getTarget"]();
7867 return t && Roo.fly(el).contains(t);
7870 getPoint : function(){
7871 return new Roo.lib.Point(this.xy[0], this.xy[1]);
7875 return new Roo.EventObjectImpl();
7880 * Ext JS Library 1.1.1
7881 * Copyright(c) 2006-2007, Ext JS, LLC.
7883 * Originally Released Under LGPL - original licence link has changed is not relivant.
7886 * <script type="text/javascript">
7890 // was in Composite Element!??!?!
7893 var D = Roo.lib.Dom;
7894 var E = Roo.lib.Event;
7895 var A = Roo.lib.Anim;
7897 // local style camelizing for speed
7899 var camelRe = /(-[a-z])/gi;
7900 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7901 var view = document.defaultView;
7904 * @class Roo.Element
7905 * Represents an Element in the DOM.<br><br>
7908 var el = Roo.get("my-div");
7911 var el = getEl("my-div");
7913 // or with a DOM element
7914 var el = Roo.get(myDivElement);
7916 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7917 * each call instead of constructing a new one.<br><br>
7918 * <b>Animations</b><br />
7919 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7920 * should either be a boolean (true) or an object literal with animation options. The animation options are:
7922 Option Default Description
7923 --------- -------- ---------------------------------------------
7924 duration .35 The duration of the animation in seconds
7925 easing easeOut The YUI easing method
7926 callback none A function to execute when the anim completes
7927 scope this The scope (this) of the callback function
7929 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7930 * manipulate the animation. Here's an example:
7932 var el = Roo.get("my-div");
7937 // default animation
7938 el.setWidth(100, true);
7940 // animation with some options set
7947 // using the "anim" property to get the Anim object
7953 el.setWidth(100, opt);
7955 if(opt.anim.isAnimated()){
7959 * <b> Composite (Collections of) Elements</b><br />
7960 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7961 * @constructor Create a new Element directly.
7962 * @param {String/HTMLElement} element
7963 * @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).
7965 Roo.Element = function(element, forceNew)
7967 var dom = typeof element == "string" ?
7968 document.getElementById(element) : element;
7970 this.listeners = {};
7972 if(!dom){ // invalid id/element
7976 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7977 return Roo.Element.cache[id];
7987 * The DOM element ID
7990 this.id = id || Roo.id(dom);
7992 return this; // assumed for cctor?
7995 var El = Roo.Element;
7999 * The element's default display mode (defaults to "")
8002 originalDisplay : "",
8005 // note this is overridden in BS version..
8008 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
8014 * Sets the element's visibility mode. When setVisible() is called it
8015 * will use this to determine whether to set the visibility or the display property.
8016 * @param visMode Element.VISIBILITY or Element.DISPLAY
8017 * @return {Roo.Element} this
8019 setVisibilityMode : function(visMode){
8020 this.visibilityMode = visMode;
8024 * Convenience method for setVisibilityMode(Element.DISPLAY)
8025 * @param {String} display (optional) What to set display to when visible
8026 * @return {Roo.Element} this
8028 enableDisplayMode : function(display){
8029 this.setVisibilityMode(El.DISPLAY);
8030 if(typeof display != "undefined") { this.originalDisplay = display; }
8035 * 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)
8036 * @param {String} selector The simple selector to test
8037 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8038 search as a number or element (defaults to 10 || document.body)
8039 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8040 * @return {HTMLElement} The matching DOM node (or null if no match was found)
8042 findParent : function(simpleSelector, maxDepth, returnEl){
8043 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
8044 maxDepth = maxDepth || 50;
8045 if(typeof maxDepth != "number"){
8046 stopEl = Roo.getDom(maxDepth);
8049 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
8050 if(dq.is(p, simpleSelector)){
8051 return returnEl ? Roo.get(p) : p;
8061 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
8062 * @param {String} selector The simple selector to test
8063 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8064 search as a number or element (defaults to 10 || document.body)
8065 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8066 * @return {HTMLElement} The matching DOM node (or null if no match was found)
8068 findParentNode : function(simpleSelector, maxDepth, returnEl){
8069 var p = Roo.fly(this.dom.parentNode, '_internal');
8070 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
8074 * Looks at the scrollable parent element
8076 findScrollableParent : function()
8078 var overflowRegex = /(auto|scroll)/;
8080 if(this.getStyle('position') === 'fixed'){
8081 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8084 var excludeStaticParent = this.getStyle('position') === "absolute";
8086 for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
8088 if (excludeStaticParent && parent.getStyle('position') === "static") {
8092 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
8096 if(parent.dom.nodeName.toLowerCase() == 'body'){
8097 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8101 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8105 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
8106 * This is a shortcut for findParentNode() that always returns an Roo.Element.
8107 * @param {String} selector The simple selector to test
8108 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8109 search as a number or element (defaults to 10 || document.body)
8110 * @return {Roo.Element} The matching DOM node (or null if no match was found)
8112 up : function(simpleSelector, maxDepth){
8113 return this.findParentNode(simpleSelector, maxDepth, true);
8119 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
8120 * @param {String} selector The simple selector to test
8121 * @return {Boolean} True if this element matches the selector, else false
8123 is : function(simpleSelector){
8124 return Roo.DomQuery.is(this.dom, simpleSelector);
8128 * Perform animation on this element.
8129 * @param {Object} args The YUI animation control args
8130 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
8131 * @param {Function} onComplete (optional) Function to call when animation completes
8132 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
8133 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
8134 * @return {Roo.Element} this
8136 animate : function(args, duration, onComplete, easing, animType){
8137 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
8142 * @private Internal animation call
8144 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
8145 animType = animType || 'run';
8147 var anim = Roo.lib.Anim[animType](
8149 (opt.duration || defaultDur) || .35,
8150 (opt.easing || defaultEase) || 'easeOut',
8152 Roo.callback(cb, this);
8153 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
8161 // private legacy anim prep
8162 preanim : function(a, i){
8163 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
8167 * Removes worthless text nodes
8168 * @param {Boolean} forceReclean (optional) By default the element
8169 * keeps track if it has been cleaned already so
8170 * you can call this over and over. However, if you update the element and
8171 * need to force a reclean, you can pass true.
8173 clean : function(forceReclean){
8174 if(this.isCleaned && forceReclean !== true){
8178 var d = this.dom, n = d.firstChild, ni = -1;
8180 var nx = n.nextSibling;
8181 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
8188 this.isCleaned = true;
8193 calcOffsetsTo : function(el){
8196 var restorePos = false;
8197 if(el.getStyle('position') == 'static'){
8198 el.position('relative');
8203 while(op && op != d && op.tagName != 'HTML'){
8206 op = op.offsetParent;
8209 el.position('static');
8215 * Scrolls this element into view within the passed container.
8216 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
8217 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
8218 * @return {Roo.Element} this
8220 scrollIntoView : function(container, hscroll){
8221 var c = Roo.getDom(container) || document.body;
8224 var o = this.calcOffsetsTo(c),
8227 b = t+el.offsetHeight,
8228 r = l+el.offsetWidth;
8230 var ch = c.clientHeight;
8231 var ct = parseInt(c.scrollTop, 10);
8232 var cl = parseInt(c.scrollLeft, 10);
8234 var cr = cl + c.clientWidth;
8242 if(hscroll !== false){
8246 c.scrollLeft = r-c.clientWidth;
8253 scrollChildIntoView : function(child, hscroll){
8254 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
8258 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
8259 * the new height may not be available immediately.
8260 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
8261 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
8262 * @param {Function} onComplete (optional) Function to call when animation completes
8263 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
8264 * @return {Roo.Element} this
8266 autoHeight : function(animate, duration, onComplete, easing){
8267 var oldHeight = this.getHeight();
8269 this.setHeight(1); // force clipping
8270 setTimeout(function(){
8271 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
8273 this.setHeight(height);
8275 if(typeof onComplete == "function"){
8279 this.setHeight(oldHeight); // restore original height
8280 this.setHeight(height, animate, duration, function(){
8282 if(typeof onComplete == "function") { onComplete(); }
8283 }.createDelegate(this), easing);
8285 }.createDelegate(this), 0);
8290 * Returns true if this element is an ancestor of the passed element
8291 * @param {HTMLElement/String} el The element to check
8292 * @return {Boolean} True if this element is an ancestor of el, else false
8294 contains : function(el){
8295 if(!el){return false;}
8296 return D.isAncestor(this.dom, el.dom ? el.dom : el);
8300 * Checks whether the element is currently visible using both visibility and display properties.
8301 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
8302 * @return {Boolean} True if the element is currently visible, else false
8304 isVisible : function(deep) {
8305 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
8306 if(deep !== true || !vis){
8309 var p = this.dom.parentNode;
8310 while(p && p.tagName.toLowerCase() != "body"){
8311 if(!Roo.fly(p, '_isVisible').isVisible()){
8320 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
8321 * @param {String} selector The CSS selector
8322 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
8323 * @return {CompositeElement/CompositeElementLite} The composite element
8325 select : function(selector, unique){
8326 return El.select(selector, unique, this.dom);
8330 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
8331 * @param {String} selector The CSS selector
8332 * @return {Array} An array of the matched nodes
8334 query : function(selector, unique){
8335 return Roo.DomQuery.select(selector, this.dom);
8339 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
8340 * @param {String} selector The CSS selector
8341 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8342 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8344 child : function(selector, returnDom){
8345 var n = Roo.DomQuery.selectNode(selector, this.dom);
8346 return returnDom ? n : Roo.get(n);
8350 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
8351 * @param {String} selector The CSS selector
8352 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8353 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8355 down : function(selector, returnDom){
8356 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
8357 return returnDom ? n : Roo.get(n);
8361 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
8362 * @param {String} group The group the DD object is member of
8363 * @param {Object} config The DD config object
8364 * @param {Object} overrides An object containing methods to override/implement on the DD object
8365 * @return {Roo.dd.DD} The DD object
8367 initDD : function(group, config, overrides){
8368 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
8369 return Roo.apply(dd, overrides);
8373 * Initializes a {@link Roo.dd.DDProxy} object for this element.
8374 * @param {String} group The group the DDProxy object is member of
8375 * @param {Object} config The DDProxy config object
8376 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
8377 * @return {Roo.dd.DDProxy} The DDProxy object
8379 initDDProxy : function(group, config, overrides){
8380 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
8381 return Roo.apply(dd, overrides);
8385 * Initializes a {@link Roo.dd.DDTarget} object for this element.
8386 * @param {String} group The group the DDTarget object is member of
8387 * @param {Object} config The DDTarget config object
8388 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
8389 * @return {Roo.dd.DDTarget} The DDTarget object
8391 initDDTarget : function(group, config, overrides){
8392 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
8393 return Roo.apply(dd, overrides);
8397 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
8398 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
8399 * @param {Boolean} visible Whether the element is visible
8400 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8401 * @return {Roo.Element} this
8403 setVisible : function(visible, animate){
8405 if(this.visibilityMode == El.DISPLAY){
8406 this.setDisplayed(visible);
8409 this.dom.style.visibility = visible ? "visible" : "hidden";
8412 // closure for composites
8414 var visMode = this.visibilityMode;
8416 this.setOpacity(.01);
8417 this.setVisible(true);
8419 this.anim({opacity: { to: (visible?1:0) }},
8420 this.preanim(arguments, 1),
8421 null, .35, 'easeIn', function(){
8423 if(visMode == El.DISPLAY){
8424 dom.style.display = "none";
8426 dom.style.visibility = "hidden";
8428 Roo.get(dom).setOpacity(1);
8436 * Returns true if display is not "none"
8439 isDisplayed : function() {
8440 return this.getStyle("display") != "none";
8444 * Toggles the element's visibility or display, depending on visibility mode.
8445 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8446 * @return {Roo.Element} this
8448 toggle : function(animate){
8449 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
8454 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
8455 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
8456 * @return {Roo.Element} this
8458 setDisplayed : function(value) {
8459 if(typeof value == "boolean"){
8460 value = value ? this.originalDisplay : "none";
8462 this.setStyle("display", value);
8467 * Tries to focus the element. Any exceptions are caught and ignored.
8468 * @return {Roo.Element} this
8470 focus : function() {
8478 * Tries to blur the element. Any exceptions are caught and ignored.
8479 * @return {Roo.Element} this
8489 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
8490 * @param {String/Array} className The CSS class to add, or an array of classes
8491 * @return {Roo.Element} this
8493 addClass : function(className){
8494 if(className instanceof Array){
8495 for(var i = 0, len = className.length; i < len; i++) {
8496 this.addClass(className[i]);
8499 if(className && !this.hasClass(className)){
8500 if (this.dom instanceof SVGElement) {
8501 this.dom.className.baseVal =this.dom.className.baseVal + " " + className;
8503 this.dom.className = this.dom.className + " " + className;
8511 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
8512 * @param {String/Array} className The CSS class to add, or an array of classes
8513 * @return {Roo.Element} this
8515 radioClass : function(className){
8516 var siblings = this.dom.parentNode.childNodes;
8517 for(var i = 0; i < siblings.length; i++) {
8518 var s = siblings[i];
8519 if(s.nodeType == 1){
8520 Roo.get(s).removeClass(className);
8523 this.addClass(className);
8528 * Removes one or more CSS classes from the element.
8529 * @param {String/Array} className The CSS class to remove, or an array of classes
8530 * @return {Roo.Element} this
8532 removeClass : function(className){
8534 var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
8535 if(!className || !cn){
8538 if(className instanceof Array){
8539 for(var i = 0, len = className.length; i < len; i++) {
8540 this.removeClass(className[i]);
8543 if(this.hasClass(className)){
8544 var re = this.classReCache[className];
8546 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
8547 this.classReCache[className] = re;
8549 if (this.dom instanceof SVGElement) {
8550 this.dom.className.baseVal = cn.replace(re, " ");
8552 this.dom.className = cn.replace(re, " ");
8563 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
8564 * @param {String} className The CSS class to toggle
8565 * @return {Roo.Element} this
8567 toggleClass : function(className){
8568 if(this.hasClass(className)){
8569 this.removeClass(className);
8571 this.addClass(className);
8577 * Checks if the specified CSS class exists on this element's DOM node.
8578 * @param {String} className The CSS class to check for
8579 * @return {Boolean} True if the class exists, else false
8581 hasClass : function(className){
8582 if (this.dom instanceof SVGElement) {
8583 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1;
8585 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
8589 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
8590 * @param {String} oldClassName The CSS class to replace
8591 * @param {String} newClassName The replacement CSS class
8592 * @return {Roo.Element} this
8594 replaceClass : function(oldClassName, newClassName){
8595 this.removeClass(oldClassName);
8596 this.addClass(newClassName);
8601 * Returns an object with properties matching the styles requested.
8602 * For example, el.getStyles('color', 'font-size', 'width') might return
8603 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
8604 * @param {String} style1 A style name
8605 * @param {String} style2 A style name
8606 * @param {String} etc.
8607 * @return {Object} The style object
8609 getStyles : function(){
8610 var a = arguments, len = a.length, r = {};
8611 for(var i = 0; i < len; i++){
8612 r[a[i]] = this.getStyle(a[i]);
8618 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
8619 * @param {String} property The style property whose value is returned.
8620 * @return {String} The current value of the style property for this element.
8622 getStyle : function(){
8623 return view && view.getComputedStyle ?
8625 var el = this.dom, v, cs, camel;
8626 if(prop == 'float'){
8629 if(el.style && (v = el.style[prop])){
8632 if(cs = view.getComputedStyle(el, "")){
8633 if(!(camel = propCache[prop])){
8634 camel = propCache[prop] = prop.replace(camelRe, camelFn);
8641 var el = this.dom, v, cs, camel;
8642 if(prop == 'opacity'){
8643 if(typeof el.style.filter == 'string'){
8644 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
8646 var fv = parseFloat(m[1]);
8648 return fv ? fv / 100 : 0;
8653 }else if(prop == 'float'){
8654 prop = "styleFloat";
8656 if(!(camel = propCache[prop])){
8657 camel = propCache[prop] = prop.replace(camelRe, camelFn);
8659 if(v = el.style[camel]){
8662 if(cs = el.currentStyle){
8670 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
8671 * @param {String/Object} property The style property to be set, or an object of multiple styles.
8672 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
8673 * @return {Roo.Element} this
8675 setStyle : function(prop, value){
8676 if(typeof prop == "string"){
8678 if (prop == 'float') {
8679 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
8684 if(!(camel = propCache[prop])){
8685 camel = propCache[prop] = prop.replace(camelRe, camelFn);
8688 if(camel == 'opacity') {
8689 this.setOpacity(value);
8691 this.dom.style[camel] = value;
8694 for(var style in prop){
8695 if(typeof prop[style] != "function"){
8696 this.setStyle(style, prop[style]);
8704 * More flexible version of {@link #setStyle} for setting style properties.
8705 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
8706 * a function which returns such a specification.
8707 * @return {Roo.Element} this
8709 applyStyles : function(style){
8710 Roo.DomHelper.applyStyles(this.dom, style);
8715 * 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).
8716 * @return {Number} The X position of the element
8719 return D.getX(this.dom);
8723 * 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).
8724 * @return {Number} The Y position of the element
8727 return D.getY(this.dom);
8731 * 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).
8732 * @return {Array} The XY position of the element
8735 return D.getXY(this.dom);
8739 * 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).
8740 * @param {Number} The X position of the element
8741 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8742 * @return {Roo.Element} this
8744 setX : function(x, animate){
8746 D.setX(this.dom, x);
8748 this.setXY([x, this.getY()], this.preanim(arguments, 1));
8754 * 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).
8755 * @param {Number} The Y position of the element
8756 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8757 * @return {Roo.Element} this
8759 setY : function(y, animate){
8761 D.setY(this.dom, y);
8763 this.setXY([this.getX(), y], this.preanim(arguments, 1));
8769 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
8770 * @param {String} left The left CSS property value
8771 * @return {Roo.Element} this
8773 setLeft : function(left){
8774 this.setStyle("left", this.addUnits(left));
8779 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
8780 * @param {String} top The top CSS property value
8781 * @return {Roo.Element} this
8783 setTop : function(top){
8784 this.setStyle("top", this.addUnits(top));
8789 * Sets the element's CSS right style.
8790 * @param {String} right The right CSS property value
8791 * @return {Roo.Element} this
8793 setRight : function(right){
8794 this.setStyle("right", this.addUnits(right));
8799 * Sets the element's CSS bottom style.
8800 * @param {String} bottom The bottom CSS property value
8801 * @return {Roo.Element} this
8803 setBottom : function(bottom){
8804 this.setStyle("bottom", this.addUnits(bottom));
8809 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8810 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8811 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
8812 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8813 * @return {Roo.Element} this
8815 setXY : function(pos, animate){
8817 D.setXY(this.dom, pos);
8819 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
8825 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8826 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8827 * @param {Number} x X value for new position (coordinates are page-based)
8828 * @param {Number} y Y value for new position (coordinates are page-based)
8829 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8830 * @return {Roo.Element} this
8832 setLocation : function(x, y, animate){
8833 this.setXY([x, y], this.preanim(arguments, 2));
8838 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8839 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8840 * @param {Number} x X value for new position (coordinates are page-based)
8841 * @param {Number} y Y value for new position (coordinates are page-based)
8842 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8843 * @return {Roo.Element} this
8845 moveTo : function(x, y, animate){
8846 this.setXY([x, y], this.preanim(arguments, 2));
8851 * Returns the region of the given element.
8852 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
8853 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
8855 getRegion : function(){
8856 return D.getRegion(this.dom);
8860 * Returns the offset height of the element
8861 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
8862 * @return {Number} The element's height
8864 getHeight : function(contentHeight){
8865 var h = this.dom.offsetHeight || 0;
8866 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
8870 * Returns the offset width of the element
8871 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
8872 * @return {Number} The element's width
8874 getWidth : function(contentWidth){
8875 var w = this.dom.offsetWidth || 0;
8876 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
8880 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
8881 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
8882 * if a height has not been set using CSS.
8885 getComputedHeight : function(){
8886 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
8888 h = parseInt(this.getStyle('height'), 10) || 0;
8889 if(!this.isBorderBox()){
8890 h += this.getFrameWidth('tb');
8897 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
8898 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
8899 * if a width has not been set using CSS.
8902 getComputedWidth : function(){
8903 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8905 w = parseInt(this.getStyle('width'), 10) || 0;
8906 if(!this.isBorderBox()){
8907 w += this.getFrameWidth('lr');
8914 * Returns the size of the element.
8915 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8916 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8918 getSize : function(contentSize){
8919 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8923 * Returns the width and height of the viewport.
8924 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8926 getViewSize : function(){
8927 var d = this.dom, doc = document, aw = 0, ah = 0;
8928 if(d == doc || d == doc.body){
8929 return {width : D.getViewWidth(), height: D.getViewHeight()};
8932 width : d.clientWidth,
8933 height: d.clientHeight
8939 * Returns the value of the "value" attribute
8940 * @param {Boolean} asNumber true to parse the value as a number
8941 * @return {String/Number}
8943 getValue : function(asNumber){
8944 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8948 adjustWidth : function(width){
8949 if(typeof width == "number"){
8950 if(this.autoBoxAdjust && !this.isBorderBox()){
8951 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8961 adjustHeight : function(height){
8962 if(typeof height == "number"){
8963 if(this.autoBoxAdjust && !this.isBorderBox()){
8964 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8974 * Set the width of the element
8975 * @param {Number} width The new width
8976 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8977 * @return {Roo.Element} this
8979 setWidth : function(width, animate){
8980 width = this.adjustWidth(width);
8982 this.dom.style.width = this.addUnits(width);
8984 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8990 * Set the height of the element
8991 * @param {Number} height The new height
8992 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8993 * @return {Roo.Element} this
8995 setHeight : function(height, animate){
8996 height = this.adjustHeight(height);
8998 this.dom.style.height = this.addUnits(height);
9000 this.anim({height: {to: height}}, this.preanim(arguments, 1));
9006 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
9007 * @param {Number} width The new width
9008 * @param {Number} height The new height
9009 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9010 * @return {Roo.Element} this
9012 setSize : function(width, height, animate){
9013 if(typeof width == "object"){ // in case of object from getSize()
9014 height = width.height; width = width.width;
9016 width = this.adjustWidth(width); height = this.adjustHeight(height);
9018 this.dom.style.width = this.addUnits(width);
9019 this.dom.style.height = this.addUnits(height);
9021 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
9027 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
9028 * @param {Number} x X value for new position (coordinates are page-based)
9029 * @param {Number} y Y value for new position (coordinates are page-based)
9030 * @param {Number} width The new width
9031 * @param {Number} height The new height
9032 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9033 * @return {Roo.Element} this
9035 setBounds : function(x, y, width, height, animate){
9037 this.setSize(width, height);
9038 this.setLocation(x, y);
9040 width = this.adjustWidth(width); height = this.adjustHeight(height);
9041 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
9042 this.preanim(arguments, 4), 'motion');
9048 * 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.
9049 * @param {Roo.lib.Region} region The region to fill
9050 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9051 * @return {Roo.Element} this
9053 setRegion : function(region, animate){
9054 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
9059 * Appends an event handler
9061 * @param {String} eventName The type of event to append
9062 * @param {Function} fn The method the event invokes
9063 * @param {Object} scope (optional) The scope (this object) of the fn
9064 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9066 addListener : function(eventName, fn, scope, options)
9068 if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
9069 this.addListener('touchstart', this.onTapHandler, this);
9072 // we need to handle a special case where dom element is a svg element.
9073 // in this case we do not actua
9078 if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
9079 if (typeof(this.listeners[eventName]) == 'undefined') {
9080 this.listeners[eventName] = new Roo.util.Event(this, eventName);
9082 this.listeners[eventName].addListener(fn, scope, options);
9087 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
9092 onTapHandler : function(event)
9094 if(!this.tapedTwice) {
9095 this.tapedTwice = true;
9097 setTimeout( function() {
9098 s.tapedTwice = false;
9102 event.preventDefault();
9103 var revent = new MouseEvent('dblclick', {
9109 this.dom.dispatchEvent(revent);
9110 //action on double tap goes below
9115 * Removes an event handler from this element
9116 * @param {String} eventName the type of event to remove
9117 * @param {Function} fn the method the event invokes
9118 * @param {Function} scope (needed for svg fake listeners)
9119 * @return {Roo.Element} this
9121 removeListener : function(eventName, fn, scope){
9122 Roo.EventManager.removeListener(this.dom, eventName, fn);
9123 if (typeof(this.listeners) == 'undefined' || typeof(this.listeners[eventName]) == 'undefined') {
9126 this.listeners[eventName].removeListener(fn, scope);
9131 * Removes all previous added listeners from this element
9132 * @return {Roo.Element} this
9134 removeAllListeners : function(){
9135 E.purgeElement(this.dom);
9136 this.listeners = {};
9140 relayEvent : function(eventName, observable){
9141 this.on(eventName, function(e){
9142 observable.fireEvent(eventName, e);
9148 * Set the opacity of the element
9149 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
9150 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9151 * @return {Roo.Element} this
9153 setOpacity : function(opacity, animate){
9155 var s = this.dom.style;
9158 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
9159 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
9161 s.opacity = opacity;
9164 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
9170 * Gets the left X coordinate
9171 * @param {Boolean} local True to get the local css position instead of page coordinate
9174 getLeft : function(local){
9178 return parseInt(this.getStyle("left"), 10) || 0;
9183 * Gets the right X coordinate of the element (element X position + element width)
9184 * @param {Boolean} local True to get the local css position instead of page coordinate
9187 getRight : function(local){
9189 return this.getX() + this.getWidth();
9191 return (this.getLeft(true) + this.getWidth()) || 0;
9196 * Gets the top Y coordinate
9197 * @param {Boolean} local True to get the local css position instead of page coordinate
9200 getTop : function(local) {
9204 return parseInt(this.getStyle("top"), 10) || 0;
9209 * Gets the bottom Y coordinate of the element (element Y position + element height)
9210 * @param {Boolean} local True to get the local css position instead of page coordinate
9213 getBottom : function(local){
9215 return this.getY() + this.getHeight();
9217 return (this.getTop(true) + this.getHeight()) || 0;
9222 * Initializes positioning on this element. If a desired position is not passed, it will make the
9223 * the element positioned relative IF it is not already positioned.
9224 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
9225 * @param {Number} zIndex (optional) The zIndex to apply
9226 * @param {Number} x (optional) Set the page X position
9227 * @param {Number} y (optional) Set the page Y position
9229 position : function(pos, zIndex, x, y){
9231 if(this.getStyle('position') == 'static'){
9232 this.setStyle('position', 'relative');
9235 this.setStyle("position", pos);
9238 this.setStyle("z-index", zIndex);
9240 if(x !== undefined && y !== undefined){
9242 }else if(x !== undefined){
9244 }else if(y !== undefined){
9250 * Clear positioning back to the default when the document was loaded
9251 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
9252 * @return {Roo.Element} this
9254 clearPositioning : function(value){
9262 "position" : "static"
9268 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
9269 * snapshot before performing an update and then restoring the element.
9272 getPositioning : function(){
9273 var l = this.getStyle("left");
9274 var t = this.getStyle("top");
9276 "position" : this.getStyle("position"),
9278 "right" : l ? "" : this.getStyle("right"),
9280 "bottom" : t ? "" : this.getStyle("bottom"),
9281 "z-index" : this.getStyle("z-index")
9286 * Gets the width of the border(s) for the specified side(s)
9287 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9288 * passing lr would get the border (l)eft width + the border (r)ight width.
9289 * @return {Number} The width of the sides passed added together
9291 getBorderWidth : function(side){
9292 return this.addStyles(side, El.borders);
9296 * Gets the width of the padding(s) for the specified side(s)
9297 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9298 * passing lr would get the padding (l)eft + the padding (r)ight.
9299 * @return {Number} The padding of the sides passed added together
9301 getPadding : function(side){
9302 return this.addStyles(side, El.paddings);
9306 * Set positioning with an object returned by getPositioning().
9307 * @param {Object} posCfg
9308 * @return {Roo.Element} this
9310 setPositioning : function(pc){
9311 this.applyStyles(pc);
9312 if(pc.right == "auto"){
9313 this.dom.style.right = "";
9315 if(pc.bottom == "auto"){
9316 this.dom.style.bottom = "";
9322 fixDisplay : function(){
9323 if(this.getStyle("display") == "none"){
9324 this.setStyle("visibility", "hidden");
9325 this.setStyle("display", this.originalDisplay); // first try reverting to default
9326 if(this.getStyle("display") == "none"){ // if that fails, default to block
9327 this.setStyle("display", "block");
9333 * Quick set left and top adding default units
9334 * @param {String} left The left CSS property value
9335 * @param {String} top The top CSS property value
9336 * @return {Roo.Element} this
9338 setLeftTop : function(left, top){
9339 this.dom.style.left = this.addUnits(left);
9340 this.dom.style.top = this.addUnits(top);
9345 * Move this element relative to its current position.
9346 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9347 * @param {Number} distance How far to move the element in pixels
9348 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9349 * @return {Roo.Element} this
9351 move : function(direction, distance, animate){
9352 var xy = this.getXY();
9353 direction = direction.toLowerCase();
9357 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
9361 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
9366 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
9371 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
9378 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
9379 * @return {Roo.Element} this
9382 if(!this.isClipped){
9383 this.isClipped = true;
9384 this.originalClip = {
9385 "o": this.getStyle("overflow"),
9386 "x": this.getStyle("overflow-x"),
9387 "y": this.getStyle("overflow-y")
9389 this.setStyle("overflow", "hidden");
9390 this.setStyle("overflow-x", "hidden");
9391 this.setStyle("overflow-y", "hidden");
9397 * Return clipping (overflow) to original clipping before clip() was called
9398 * @return {Roo.Element} this
9400 unclip : function(){
9402 this.isClipped = false;
9403 var o = this.originalClip;
9404 if(o.o){this.setStyle("overflow", o.o);}
9405 if(o.x){this.setStyle("overflow-x", o.x);}
9406 if(o.y){this.setStyle("overflow-y", o.y);}
9413 * Gets the x,y coordinates specified by the anchor position on the element.
9414 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
9415 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
9416 * {width: (target width), height: (target height)} (defaults to the element's current size)
9417 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
9418 * @return {Array} [x, y] An array containing the element's x and y coordinates
9420 getAnchorXY : function(anchor, local, s){
9421 //Passing a different size is useful for pre-calculating anchors,
9422 //especially for anchored animations that change the el size.
9424 var w, h, vp = false;
9427 if(d == document.body || d == document){
9429 w = D.getViewWidth(); h = D.getViewHeight();
9431 w = this.getWidth(); h = this.getHeight();
9434 w = s.width; h = s.height;
9436 var x = 0, y = 0, r = Math.round;
9437 switch((anchor || "tl").toLowerCase()){
9479 var sc = this.getScroll();
9480 return [x + sc.left, y + sc.top];
9482 //Add the element's offset xy
9483 var o = this.getXY();
9484 return [x+o[0], y+o[1]];
9488 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
9489 * supported position values.
9490 * @param {String/HTMLElement/Roo.Element} element The element to align to.
9491 * @param {String} position The position to align to.
9492 * @param {Array} offsets (optional) Offset the positioning by [x, y]
9493 * @return {Array} [x, y]
9495 getAlignToXY : function(el, p, o)
9500 throw "Element.alignTo with an element that doesn't exist";
9502 var c = false; //constrain to viewport
9503 var p1 = "", p2 = "";
9510 }else if(p.indexOf("-") == -1){
9513 p = p.toLowerCase();
9514 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
9516 throw "Element.alignTo with an invalid alignment " + p;
9518 p1 = m[1]; p2 = m[2]; c = !!m[3];
9520 //Subtract the aligned el's internal xy from the target's offset xy
9521 //plus custom offset to get the aligned el's new offset xy
9522 var a1 = this.getAnchorXY(p1, true);
9523 var a2 = el.getAnchorXY(p2, false);
9524 var x = a2[0] - a1[0] + o[0];
9525 var y = a2[1] - a1[1] + o[1];
9527 //constrain the aligned el to viewport if necessary
9528 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
9529 // 5px of margin for ie
9530 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
9532 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
9533 //perpendicular to the vp border, allow the aligned el to slide on that border,
9534 //otherwise swap the aligned el to the opposite border of the target.
9535 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
9536 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
9537 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t") );
9538 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
9541 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
9542 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
9544 if((x+w) > dw + scrollX){
9545 x = swapX ? r.left-w : dw+scrollX-w;
9548 x = swapX ? r.right : scrollX;
9550 if((y+h) > dh + scrollY){
9551 y = swapY ? r.top-h : dh+scrollY-h;
9554 y = swapY ? r.bottom : scrollY;
9561 getConstrainToXY : function(){
9562 var os = {top:0, left:0, bottom:0, right: 0};
9564 return function(el, local, offsets, proposedXY){
9566 offsets = offsets ? Roo.applyIf(offsets, os) : os;
9568 var vw, vh, vx = 0, vy = 0;
9569 if(el.dom == document.body || el.dom == document){
9570 vw = Roo.lib.Dom.getViewWidth();
9571 vh = Roo.lib.Dom.getViewHeight();
9573 vw = el.dom.clientWidth;
9574 vh = el.dom.clientHeight;
9576 var vxy = el.getXY();
9582 var s = el.getScroll();
9584 vx += offsets.left + s.left;
9585 vy += offsets.top + s.top;
9587 vw -= offsets.right;
9588 vh -= offsets.bottom;
9593 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
9594 var x = xy[0], y = xy[1];
9595 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
9597 // only move it if it needs it
9600 // first validate right/bottom
9609 // then make sure top/left isn't negative
9618 return moved ? [x, y] : false;
9623 adjustForConstraints : function(xy, parent, offsets){
9624 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
9628 * Aligns this element with another element relative to the specified anchor points. If the other element is the
9629 * document it aligns it to the viewport.
9630 * The position parameter is optional, and can be specified in any one of the following formats:
9632 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
9633 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
9634 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
9635 * deprecated in favor of the newer two anchor syntax below</i>.</li>
9636 * <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
9637 * element's anchor point, and the second value is used as the target's anchor point.</li>
9639 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
9640 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
9641 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
9642 * that specified in order to enforce the viewport constraints.
9643 * Following are all of the supported anchor positions:
9646 ----- -----------------------------
9647 tl The top left corner (default)
9648 t The center of the top edge
9649 tr The top right corner
9650 l The center of the left edge
9651 c In the center of the element
9652 r The center of the right edge
9653 bl The bottom left corner
9654 b The center of the bottom edge
9655 br The bottom right corner
9659 // align el to other-el using the default positioning ("tl-bl", non-constrained)
9660 el.alignTo("other-el");
9662 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
9663 el.alignTo("other-el", "tr?");
9665 // align the bottom right corner of el with the center left edge of other-el
9666 el.alignTo("other-el", "br-l?");
9668 // align the center of el with the bottom left corner of other-el and
9669 // adjust the x position by -6 pixels (and the y position by 0)
9670 el.alignTo("other-el", "c-bl", [-6, 0]);
9672 * @param {String/HTMLElement/Roo.Element} element The element to align to.
9673 * @param {String} position The position to align to.
9674 * @param {Array} offsets (optional) Offset the positioning by [x, y]
9675 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9676 * @return {Roo.Element} this
9678 alignTo : function(element, position, offsets, animate){
9679 var xy = this.getAlignToXY(element, position, offsets);
9680 this.setXY(xy, this.preanim(arguments, 3));
9685 * Anchors an element to another element and realigns it when the window is resized.
9686 * @param {String/HTMLElement/Roo.Element} element The element to align to.
9687 * @param {String} position The position to align to.
9688 * @param {Array} offsets (optional) Offset the positioning by [x, y]
9689 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
9690 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
9691 * is a number, it is used as the buffer delay (defaults to 50ms).
9692 * @param {Function} callback The function to call after the animation finishes
9693 * @return {Roo.Element} this
9695 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
9696 var action = function(){
9697 this.alignTo(el, alignment, offsets, animate);
9698 Roo.callback(callback, this);
9700 Roo.EventManager.onWindowResize(action, this);
9701 var tm = typeof monitorScroll;
9702 if(tm != 'undefined'){
9703 Roo.EventManager.on(window, 'scroll', action, this,
9704 {buffer: tm == 'number' ? monitorScroll : 50});
9706 action.call(this); // align immediately
9710 * Clears any opacity settings from this element. Required in some cases for IE.
9711 * @return {Roo.Element} this
9713 clearOpacity : function(){
9714 if (window.ActiveXObject) {
9715 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
9716 this.dom.style.filter = "";
9719 this.dom.style.opacity = "";
9720 this.dom.style["-moz-opacity"] = "";
9721 this.dom.style["-khtml-opacity"] = "";
9727 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
9728 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9729 * @return {Roo.Element} this
9731 hide : function(animate){
9732 this.setVisible(false, this.preanim(arguments, 0));
9737 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
9738 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9739 * @return {Roo.Element} this
9741 show : function(animate){
9742 this.setVisible(true, this.preanim(arguments, 0));
9747 * @private Test if size has a unit, otherwise appends the default
9749 addUnits : function(size){
9750 return Roo.Element.addUnits(size, this.defaultUnit);
9754 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
9755 * @return {Roo.Element} this
9757 beginMeasure : function(){
9759 if(el.offsetWidth || el.offsetHeight){
9760 return this; // offsets work already
9763 var p = this.dom, b = document.body; // start with this element
9764 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
9765 var pe = Roo.get(p);
9766 if(pe.getStyle('display') == 'none'){
9767 changed.push({el: p, visibility: pe.getStyle("visibility")});
9768 p.style.visibility = "hidden";
9769 p.style.display = "block";
9773 this._measureChanged = changed;
9779 * Restores displays to before beginMeasure was called
9780 * @return {Roo.Element} this
9782 endMeasure : function(){
9783 var changed = this._measureChanged;
9785 for(var i = 0, len = changed.length; i < len; i++) {
9787 r.el.style.visibility = r.visibility;
9788 r.el.style.display = "none";
9790 this._measureChanged = null;
9796 * Update the innerHTML of this element, optionally searching for and processing scripts
9797 * @param {String} html The new HTML
9798 * @param {Boolean} loadScripts (optional) true to look for and process scripts
9799 * @param {Function} callback For async script loading you can be noticed when the update completes
9800 * @return {Roo.Element} this
9802 update : function(html, loadScripts, callback){
9803 if(typeof html == "undefined"){
9806 if(loadScripts !== true){
9807 this.dom.innerHTML = html;
9808 if(typeof callback == "function"){
9816 html += '<span id="' + id + '"></span>';
9818 E.onAvailable(id, function(){
9819 var hd = document.getElementsByTagName("head")[0];
9820 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
9821 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
9822 var typeRe = /\stype=([\'\"])(.*?)\1/i;
9825 while(match = re.exec(html)){
9826 var attrs = match[1];
9827 var srcMatch = attrs ? attrs.match(srcRe) : false;
9828 if(srcMatch && srcMatch[2]){
9829 var s = document.createElement("script");
9830 s.src = srcMatch[2];
9831 var typeMatch = attrs.match(typeRe);
9832 if(typeMatch && typeMatch[2]){
9833 s.type = typeMatch[2];
9836 }else if(match[2] && match[2].length > 0){
9837 if(window.execScript) {
9838 window.execScript(match[2]);
9846 window.eval(match[2]);
9850 var el = document.getElementById(id);
9851 if(el){el.parentNode.removeChild(el);}
9852 if(typeof callback == "function"){
9856 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
9861 * Direct access to the UpdateManager update() method (takes the same parameters).
9862 * @param {String/Function} url The url for this request or a function to call to get the url
9863 * @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}
9864 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9865 * @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.
9866 * @return {Roo.Element} this
9869 var um = this.getUpdateManager();
9870 um.update.apply(um, arguments);
9875 * Gets this element's UpdateManager
9876 * @return {Roo.UpdateManager} The UpdateManager
9878 getUpdateManager : function(){
9879 if(!this.updateManager){
9880 this.updateManager = new Roo.UpdateManager(this);
9882 return this.updateManager;
9886 * Disables text selection for this element (normalized across browsers)
9887 * @return {Roo.Element} this
9889 unselectable : function(){
9890 this.dom.unselectable = "on";
9891 this.swallowEvent("selectstart", true);
9892 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
9893 this.addClass("x-unselectable");
9898 * Calculates the x, y to center this element on the screen
9899 * @return {Array} The x, y values [x, y]
9901 getCenterXY : function(){
9902 return this.getAlignToXY(document, 'c-c');
9906 * Centers the Element in either the viewport, or another Element.
9907 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
9909 center : function(centerIn){
9910 this.alignTo(centerIn || document, 'c-c');
9915 * Tests various css rules/browsers to determine if this element uses a border box
9918 isBorderBox : function(){
9919 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
9923 * Return a box {x, y, width, height} that can be used to set another elements
9924 * size/location to match this element.
9925 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
9926 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
9927 * @return {Object} box An object in the format {x, y, width, height}
9929 getBox : function(contentBox, local){
9934 var left = parseInt(this.getStyle("left"), 10) || 0;
9935 var top = parseInt(this.getStyle("top"), 10) || 0;
9938 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
9940 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
9942 var l = this.getBorderWidth("l")+this.getPadding("l");
9943 var r = this.getBorderWidth("r")+this.getPadding("r");
9944 var t = this.getBorderWidth("t")+this.getPadding("t");
9945 var b = this.getBorderWidth("b")+this.getPadding("b");
9946 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)};
9948 bx.right = bx.x + bx.width;
9949 bx.bottom = bx.y + bx.height;
9954 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9955 for more information about the sides.
9956 * @param {String} sides
9959 getFrameWidth : function(sides, onlyContentBox){
9960 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9964 * 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.
9965 * @param {Object} box The box to fill {x, y, width, height}
9966 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9967 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9968 * @return {Roo.Element} this
9970 setBox : function(box, adjust, animate){
9971 var w = box.width, h = box.height;
9972 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9973 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9974 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9976 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9981 * Forces the browser to repaint this element
9982 * @return {Roo.Element} this
9984 repaint : function(){
9986 this.addClass("x-repaint");
9987 setTimeout(function(){
9988 Roo.get(dom).removeClass("x-repaint");
9994 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9995 * then it returns the calculated width of the sides (see getPadding)
9996 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9997 * @return {Object/Number}
9999 getMargins : function(side){
10002 top: parseInt(this.getStyle("margin-top"), 10) || 0,
10003 left: parseInt(this.getStyle("margin-left"), 10) || 0,
10004 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
10005 right: parseInt(this.getStyle("margin-right"), 10) || 0
10008 return this.addStyles(side, El.margins);
10013 addStyles : function(sides, styles){
10015 for(var i = 0, len = sides.length; i < len; i++){
10016 v = this.getStyle(styles[sides.charAt(i)]);
10018 w = parseInt(v, 10);
10026 * Creates a proxy element of this element
10027 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
10028 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
10029 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
10030 * @return {Roo.Element} The new proxy element
10032 createProxy : function(config, renderTo, matchBox){
10034 renderTo = Roo.getDom(renderTo);
10036 renderTo = document.body;
10038 config = typeof config == "object" ?
10039 config : {tag : "div", cls: config};
10040 var proxy = Roo.DomHelper.append(renderTo, config, true);
10042 proxy.setBox(this.getBox());
10048 * Puts a mask over this element to disable user interaction. Requires core.css.
10049 * This method can only be applied to elements which accept child nodes.
10050 * @param {String} msg (optional) A message to display in the mask
10051 * @param {String} msgCls (optional) A css class to apply to the msg element - use no-spinner to hide the spinner on bootstrap
10052 * @return {Element} The mask element
10054 mask : function(msg, msgCls)
10056 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
10057 this.setStyle("position", "relative");
10060 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
10063 this.addClass("x-masked");
10064 this._mask.setDisplayed(true);
10068 var dom = this.dom;
10069 while (dom && dom.style) {
10070 if (!isNaN(parseInt(dom.style.zIndex))) {
10071 z = Math.max(z, parseInt(dom.style.zIndex));
10073 dom = dom.parentNode;
10075 // if we are masking the body - then it hides everything..
10076 if (this.dom == document.body) {
10078 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
10079 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
10082 if(typeof msg == 'string'){
10083 if(!this._maskMsg){
10084 this._maskMsg = Roo.DomHelper.append(this.dom, {
10085 cls: "roo-el-mask-msg",
10089 cls: 'fa fa-spinner fa-spin'
10097 var mm = this._maskMsg;
10098 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
10099 if (mm.dom.lastChild) { // weird IE issue?
10100 mm.dom.lastChild.innerHTML = msg;
10102 mm.setDisplayed(true);
10104 mm.setStyle('z-index', z + 102);
10106 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
10107 this._mask.setHeight(this.getHeight());
10109 this._mask.setStyle('z-index', z + 100);
10115 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
10116 * it is cached for reuse.
10118 unmask : function(removeEl){
10120 if(removeEl === true){
10121 this._mask.remove();
10124 this._maskMsg.remove();
10125 delete this._maskMsg;
10128 this._mask.setDisplayed(false);
10130 this._maskMsg.setDisplayed(false);
10134 this.removeClass("x-masked");
10138 * Returns true if this element is masked
10139 * @return {Boolean}
10141 isMasked : function(){
10142 return this._mask && this._mask.isVisible();
10146 * Creates an iframe shim for this element to keep selects and other windowed objects from
10148 * @return {Roo.Element} The new shim element
10150 createShim : function(){
10151 var el = document.createElement('iframe');
10152 el.frameBorder = 'no';
10153 el.className = 'roo-shim';
10154 if(Roo.isIE && Roo.isSecure){
10155 el.src = Roo.SSL_SECURE_URL;
10157 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
10158 shim.autoBoxAdjust = false;
10163 * Removes this element from the DOM and deletes it from the cache
10165 remove : function(){
10166 if(this.dom.parentNode){
10167 this.dom.parentNode.removeChild(this.dom);
10169 delete El.cache[this.dom.id];
10173 * Sets up event handlers to add and remove a css class when the mouse is over this element
10174 * @param {String} className
10175 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
10176 * mouseout events for children elements
10177 * @return {Roo.Element} this
10179 addClassOnOver : function(className, preventFlicker){
10180 this.on("mouseover", function(){
10181 Roo.fly(this, '_internal').addClass(className);
10183 var removeFn = function(e){
10184 if(preventFlicker !== true || !e.within(this, true)){
10185 Roo.fly(this, '_internal').removeClass(className);
10188 this.on("mouseout", removeFn, this.dom);
10193 * Sets up event handlers to add and remove a css class when this element has the focus
10194 * @param {String} className
10195 * @return {Roo.Element} this
10197 addClassOnFocus : function(className){
10198 this.on("focus", function(){
10199 Roo.fly(this, '_internal').addClass(className);
10201 this.on("blur", function(){
10202 Roo.fly(this, '_internal').removeClass(className);
10207 * 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)
10208 * @param {String} className
10209 * @return {Roo.Element} this
10211 addClassOnClick : function(className){
10212 var dom = this.dom;
10213 this.on("mousedown", function(){
10214 Roo.fly(dom, '_internal').addClass(className);
10215 var d = Roo.get(document);
10216 var fn = function(){
10217 Roo.fly(dom, '_internal').removeClass(className);
10218 d.removeListener("mouseup", fn);
10220 d.on("mouseup", fn);
10226 * Stops the specified event from bubbling and optionally prevents the default action
10227 * @param {String} eventName
10228 * @param {Boolean} preventDefault (optional) true to prevent the default action too
10229 * @return {Roo.Element} this
10231 swallowEvent : function(eventName, preventDefault){
10232 var fn = function(e){
10233 e.stopPropagation();
10234 if(preventDefault){
10235 e.preventDefault();
10238 if(eventName instanceof Array){
10239 for(var i = 0, len = eventName.length; i < len; i++){
10240 this.on(eventName[i], fn);
10244 this.on(eventName, fn);
10251 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
10254 * Sizes this element to its parent element's dimensions performing
10255 * neccessary box adjustments.
10256 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
10257 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
10258 * @return {Roo.Element} this
10260 fitToParent : function(monitorResize, targetParent) {
10261 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
10262 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
10263 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
10266 var p = Roo.get(targetParent || this.dom.parentNode);
10267 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
10268 if (monitorResize === true) {
10269 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
10270 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
10276 * Gets the next sibling, skipping text nodes
10277 * @return {HTMLElement} The next sibling or null
10279 getNextSibling : function(){
10280 var n = this.dom.nextSibling;
10281 while(n && n.nodeType != 1){
10288 * Gets the previous sibling, skipping text nodes
10289 * @return {HTMLElement} The previous sibling or null
10291 getPrevSibling : function(){
10292 var n = this.dom.previousSibling;
10293 while(n && n.nodeType != 1){
10294 n = n.previousSibling;
10301 * Appends the passed element(s) to this element
10302 * @param {String/HTMLElement/Array/Element/CompositeElement} el
10303 * @return {Roo.Element} this
10305 appendChild: function(el){
10312 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
10313 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
10314 * automatically generated with the specified attributes.
10315 * @param {HTMLElement} insertBefore (optional) a child element of this element
10316 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
10317 * @return {Roo.Element} The new child element
10319 createChild: function(config, insertBefore, returnDom){
10320 config = config || {tag:'div'};
10322 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
10324 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
10328 * Appends this element to the passed element
10329 * @param {String/HTMLElement/Element} el The new parent element
10330 * @return {Roo.Element} this
10332 appendTo: function(el){
10333 el = Roo.getDom(el);
10334 el.appendChild(this.dom);
10339 * Inserts this element before the passed element in the DOM
10340 * @param {String/HTMLElement/Element} el The element to insert before
10341 * @return {Roo.Element} this
10343 insertBefore: function(el){
10344 el = Roo.getDom(el);
10345 el.parentNode.insertBefore(this.dom, el);
10350 * Inserts this element after the passed element in the DOM
10351 * @param {String/HTMLElement/Element} el The element to insert after
10352 * @return {Roo.Element} this
10354 insertAfter: function(el){
10355 el = Roo.getDom(el);
10356 el.parentNode.insertBefore(this.dom, el.nextSibling);
10361 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
10362 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10363 * @return {Roo.Element} The new child
10365 insertFirst: function(el, returnDom){
10367 if(typeof el == 'object' && !el.nodeType){ // dh config
10368 return this.createChild(el, this.dom.firstChild, returnDom);
10370 el = Roo.getDom(el);
10371 this.dom.insertBefore(el, this.dom.firstChild);
10372 return !returnDom ? Roo.get(el) : el;
10377 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
10378 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10379 * @param {String} where (optional) 'before' or 'after' defaults to before
10380 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10381 * @return {Roo.Element} the inserted Element
10383 insertSibling: function(el, where, returnDom){
10384 where = where ? where.toLowerCase() : 'before';
10386 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
10388 if(typeof el == 'object' && !el.nodeType){ // dh config
10389 if(where == 'after' && !this.dom.nextSibling){
10390 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
10392 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
10396 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
10397 where == 'before' ? this.dom : this.dom.nextSibling);
10406 * Creates and wraps this element with another element
10407 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
10408 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10409 * @return {HTMLElement/Element} The newly created wrapper element
10411 wrap: function(config, returnDom){
10413 config = {tag: "div"};
10415 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
10416 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
10421 * Replaces the passed element with this element
10422 * @param {String/HTMLElement/Element} el The element to replace
10423 * @return {Roo.Element} this
10425 replace: function(el){
10427 this.insertBefore(el);
10433 * Inserts an html fragment into this element
10434 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
10435 * @param {String} html The HTML fragment
10436 * @param {Boolean} returnEl True to return an Roo.Element
10437 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
10439 insertHtml : function(where, html, returnEl){
10440 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
10441 return returnEl ? Roo.get(el) : el;
10445 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
10446 * @param {Object} o The object with the attributes
10447 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
10448 * @return {Roo.Element} this
10450 set : function(o, useSet){
10452 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
10453 for(var attr in o){
10454 if(attr == "style" || typeof o[attr] == "function") { continue; }
10456 el.className = o["cls"];
10459 el.setAttribute(attr, o[attr]);
10461 el[attr] = o[attr];
10466 Roo.DomHelper.applyStyles(el, o.style);
10472 * Convenience method for constructing a KeyMap
10473 * @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:
10474 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
10475 * @param {Function} fn The function to call
10476 * @param {Object} scope (optional) The scope of the function
10477 * @return {Roo.KeyMap} The KeyMap created
10479 addKeyListener : function(key, fn, scope){
10481 if(typeof key != "object" || key instanceof Array){
10497 return new Roo.KeyMap(this, config);
10501 * Creates a KeyMap for this element
10502 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
10503 * @return {Roo.KeyMap} The KeyMap created
10505 addKeyMap : function(config){
10506 return new Roo.KeyMap(this, config);
10510 * Returns true if this element is scrollable.
10511 * @return {Boolean}
10513 isScrollable : function(){
10514 var dom = this.dom;
10515 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
10519 * 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().
10520 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
10521 * @param {Number} value The new scroll value
10522 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10523 * @return {Element} this
10526 scrollTo : function(side, value, animate){
10527 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
10528 if(!animate || !A){
10529 this.dom[prop] = value;
10531 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
10532 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
10538 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
10539 * within this element's scrollable range.
10540 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
10541 * @param {Number} distance How far to scroll the element in pixels
10542 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10543 * @return {Boolean} Returns true if a scroll was triggered or false if the element
10544 * was scrolled as far as it could go.
10546 scroll : function(direction, distance, animate){
10547 if(!this.isScrollable()){
10551 var l = el.scrollLeft, t = el.scrollTop;
10552 var w = el.scrollWidth, h = el.scrollHeight;
10553 var cw = el.clientWidth, ch = el.clientHeight;
10554 direction = direction.toLowerCase();
10555 var scrolled = false;
10556 var a = this.preanim(arguments, 2);
10561 var v = Math.min(l + distance, w-cw);
10562 this.scrollTo("left", v, a);
10569 var v = Math.max(l - distance, 0);
10570 this.scrollTo("left", v, a);
10578 var v = Math.max(t - distance, 0);
10579 this.scrollTo("top", v, a);
10587 var v = Math.min(t + distance, h-ch);
10588 this.scrollTo("top", v, a);
10597 * Translates the passed page coordinates into left/top css values for this element
10598 * @param {Number/Array} x The page x or an array containing [x, y]
10599 * @param {Number} y The page y
10600 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
10602 translatePoints : function(x, y){
10603 if(typeof x == 'object' || x instanceof Array){
10604 y = x[1]; x = x[0];
10606 var p = this.getStyle('position');
10607 var o = this.getXY();
10609 var l = parseInt(this.getStyle('left'), 10);
10610 var t = parseInt(this.getStyle('top'), 10);
10613 l = (p == "relative") ? 0 : this.dom.offsetLeft;
10616 t = (p == "relative") ? 0 : this.dom.offsetTop;
10619 return {left: (x - o[0] + l), top: (y - o[1] + t)};
10623 * Returns the current scroll position of the element.
10624 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
10626 getScroll : function(){
10627 var d = this.dom, doc = document;
10628 if(d == doc || d == doc.body){
10629 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
10630 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
10631 return {left: l, top: t};
10633 return {left: d.scrollLeft, top: d.scrollTop};
10638 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
10639 * are convert to standard 6 digit hex color.
10640 * @param {String} attr The css attribute
10641 * @param {String} defaultValue The default value to use when a valid color isn't found
10642 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
10645 getColor : function(attr, defaultValue, prefix){
10646 var v = this.getStyle(attr);
10647 if(!v || v == "transparent" || v == "inherit") {
10648 return defaultValue;
10650 var color = typeof prefix == "undefined" ? "#" : prefix;
10651 if(v.substr(0, 4) == "rgb("){
10652 var rvs = v.slice(4, v.length -1).split(",");
10653 for(var i = 0; i < 3; i++){
10654 var h = parseInt(rvs[i]).toString(16);
10661 if(v.substr(0, 1) == "#"){
10662 if(v.length == 4) {
10663 for(var i = 1; i < 4; i++){
10664 var c = v.charAt(i);
10667 }else if(v.length == 7){
10668 color += v.substr(1);
10672 return(color.length > 5 ? color.toLowerCase() : defaultValue);
10676 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
10677 * gradient background, rounded corners and a 4-way shadow.
10678 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
10679 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
10680 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
10681 * @return {Roo.Element} this
10683 boxWrap : function(cls){
10684 cls = cls || 'x-box';
10685 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
10686 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
10691 * Returns the value of a namespaced attribute from the element's underlying DOM node.
10692 * @param {String} namespace The namespace in which to look for the attribute
10693 * @param {String} name The attribute name
10694 * @return {String} The attribute value
10696 getAttributeNS : Roo.isIE ? function(ns, name){
10698 var type = typeof d[ns+":"+name];
10699 if(type != 'undefined' && type != 'unknown'){
10700 return d[ns+":"+name];
10703 } : function(ns, name){
10705 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
10710 * Sets or Returns the value the dom attribute value
10711 * @param {String|Object} name The attribute name (or object to set multiple attributes)
10712 * @param {String} value (optional) The value to set the attribute to
10713 * @return {String} The attribute value
10715 attr : function(name){
10716 if (arguments.length > 1) {
10717 this.dom.setAttribute(name, arguments[1]);
10718 return arguments[1];
10720 if (typeof(name) == 'object') {
10721 for(var i in name) {
10722 this.attr(i, name[i]);
10728 if (!this.dom.hasAttribute(name)) {
10731 return this.dom.getAttribute(name);
10738 var ep = El.prototype;
10741 * Appends an event handler (Shorthand for addListener)
10742 * @param {String} eventName The type of event to append
10743 * @param {Function} fn The method the event invokes
10744 * @param {Object} scope (optional) The scope (this object) of the fn
10745 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
10748 ep.on = ep.addListener;
10749 // backwards compat
10750 ep.mon = ep.addListener;
10753 * Removes an event handler from this element (shorthand for removeListener)
10754 * @param {String} eventName the type of event to remove
10755 * @param {Function} fn the method the event invokes
10756 * @return {Roo.Element} this
10759 ep.un = ep.removeListener;
10762 * true to automatically adjust width and height settings for box-model issues (default to true)
10764 ep.autoBoxAdjust = true;
10767 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
10770 El.addUnits = function(v, defaultUnit){
10771 if(v === "" || v == "auto"){
10774 if(v === undefined){
10777 if(typeof v == "number" || !El.unitPattern.test(v)){
10778 return v + (defaultUnit || 'px');
10783 // special markup used throughout Roo when box wrapping elements
10784 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>';
10786 * Visibility mode constant - Use visibility to hide element
10792 * Visibility mode constant - Use display to hide element
10798 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
10799 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
10800 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
10812 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10813 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10814 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10815 * @return {Element} The Element object
10818 El.get = function(el){
10820 if(!el){ return null; }
10821 if(typeof el == "string"){ // element id
10822 if(!(elm = document.getElementById(el))){
10825 if(ex = El.cache[el]){
10828 ex = El.cache[el] = new El(elm);
10831 }else if(el.tagName){ // dom element
10835 if(ex = El.cache[id]){
10838 ex = El.cache[id] = new El(el);
10841 }else if(el instanceof El){
10843 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
10844 // catch case where it hasn't been appended
10845 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
10848 }else if(el.isComposite){
10850 }else if(el instanceof Array){
10851 return El.select(el);
10852 }else if(el == document){
10853 // create a bogus element object representing the document object
10855 var f = function(){};
10856 f.prototype = El.prototype;
10858 docEl.dom = document;
10866 El.uncache = function(el){
10867 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
10869 delete El.cache[a[i].id || a[i]];
10875 // Garbage collection - uncache elements/purge listeners on orphaned elements
10876 // so we don't hold a reference and cause the browser to retain them
10877 El.garbageCollect = function(){
10878 if(!Roo.enableGarbageCollector){
10879 clearInterval(El.collectorThread);
10882 for(var eid in El.cache){
10883 var el = El.cache[eid], d = el.dom;
10884 // -------------------------------------------------------
10885 // Determining what is garbage:
10886 // -------------------------------------------------------
10888 // dom node is null, definitely garbage
10889 // -------------------------------------------------------
10891 // no parentNode == direct orphan, definitely garbage
10892 // -------------------------------------------------------
10893 // !d.offsetParent && !document.getElementById(eid)
10894 // display none elements have no offsetParent so we will
10895 // also try to look it up by it's id. However, check
10896 // offsetParent first so we don't do unneeded lookups.
10897 // This enables collection of elements that are not orphans
10898 // directly, but somewhere up the line they have an orphan
10900 // -------------------------------------------------------
10901 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
10902 delete El.cache[eid];
10903 if(d && Roo.enableListenerCollection){
10909 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
10913 El.Flyweight = function(dom){
10916 El.Flyweight.prototype = El.prototype;
10918 El._flyweights = {};
10920 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10921 * the dom node can be overwritten by other code.
10922 * @param {String/HTMLElement} el The dom node or id
10923 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10924 * prevent conflicts (e.g. internally Roo uses "_internal")
10926 * @return {Element} The shared Element object
10928 El.fly = function(el, named){
10929 named = named || '_global';
10930 el = Roo.getDom(el);
10934 if(!El._flyweights[named]){
10935 El._flyweights[named] = new El.Flyweight();
10937 El._flyweights[named].dom = el;
10938 return El._flyweights[named];
10942 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10943 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10944 * Shorthand of {@link Roo.Element#get}
10945 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10946 * @return {Element} The Element object
10952 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10953 * the dom node can be overwritten by other code.
10954 * Shorthand of {@link Roo.Element#fly}
10955 * @param {String/HTMLElement} el The dom node or id
10956 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10957 * prevent conflicts (e.g. internally Roo uses "_internal")
10959 * @return {Element} The shared Element object
10965 // speedy lookup for elements never to box adjust
10966 var noBoxAdjust = Roo.isStrict ? {
10969 input:1, select:1, textarea:1
10971 if(Roo.isIE || Roo.isGecko){
10972 noBoxAdjust['button'] = 1;
10976 Roo.EventManager.on(window, 'unload', function(){
10978 delete El._flyweights;
10986 Roo.Element.selectorFunction = Roo.DomQuery.select;
10989 Roo.Element.select = function(selector, unique, root){
10991 if(typeof selector == "string"){
10992 els = Roo.Element.selectorFunction(selector, root);
10993 }else if(selector.length !== undefined){
10996 throw "Invalid selector";
10998 if(unique === true){
10999 return new Roo.CompositeElement(els);
11001 return new Roo.CompositeElementLite(els);
11005 * Selects elements based on the passed CSS selector to enable working on them as 1.
11006 * @param {String/Array} selector The CSS selector or an array of elements
11007 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
11008 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
11009 * @return {CompositeElementLite/CompositeElement}
11013 Roo.select = Roo.Element.select;
11030 * Ext JS Library 1.1.1
11031 * Copyright(c) 2006-2007, Ext JS, LLC.
11033 * Originally Released Under LGPL - original licence link has changed is not relivant.
11036 * <script type="text/javascript">
11041 //Notifies Element that fx methods are available
11042 Roo.enableFx = true;
11046 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
11047 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
11048 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
11049 * Element effects to work.</p><br/>
11051 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
11052 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
11053 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
11054 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
11055 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
11056 * expected results and should be done with care.</p><br/>
11058 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
11059 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
11062 ----- -----------------------------
11063 tl The top left corner
11064 t The center of the top edge
11065 tr The top right corner
11066 l The center of the left edge
11067 r The center of the right edge
11068 bl The bottom left corner
11069 b The center of the bottom edge
11070 br The bottom right corner
11072 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
11073 * below are common options that can be passed to any Fx method.</b>
11074 * @cfg {Function} callback A function called when the effect is finished
11075 * @cfg {Object} scope The scope of the effect function
11076 * @cfg {String} easing A valid Easing value for the effect
11077 * @cfg {String} afterCls A css class to apply after the effect
11078 * @cfg {Number} duration The length of time (in seconds) that the effect should last
11079 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
11080 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
11081 * effects that end with the element being visually hidden, ignored otherwise)
11082 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
11083 * a function which returns such a specification that will be applied to the Element after the effect finishes
11084 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
11085 * @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
11086 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
11090 * Slides the element into view. An anchor point can be optionally passed to set the point of
11091 * origin for the slide effect. This function automatically handles wrapping the element with
11092 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
11095 // default: slide the element in from the top
11098 // custom: slide the element in from the right with a 2-second duration
11099 el.slideIn('r', { duration: 2 });
11101 // common config options shown with default values
11107 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11108 * @param {Object} options (optional) Object literal with any of the Fx config options
11109 * @return {Roo.Element} The Element
11111 slideIn : function(anchor, o){
11112 var el = this.getFxEl();
11115 el.queueFx(o, function(){
11117 anchor = anchor || "t";
11119 // fix display to visibility
11122 // restore values after effect
11123 var r = this.getFxRestore();
11124 var b = this.getBox();
11125 // fixed size for slide
11129 var wrap = this.fxWrap(r.pos, o, "hidden");
11131 var st = this.dom.style;
11132 st.visibility = "visible";
11133 st.position = "absolute";
11135 // clear out temp styles after slide and unwrap
11136 var after = function(){
11137 el.fxUnwrap(wrap, r.pos, o);
11138 st.width = r.width;
11139 st.height = r.height;
11142 // time to calc the positions
11143 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
11145 switch(anchor.toLowerCase()){
11147 wrap.setSize(b.width, 0);
11148 st.left = st.bottom = "0";
11152 wrap.setSize(0, b.height);
11153 st.right = st.top = "0";
11157 wrap.setSize(0, b.height);
11158 wrap.setX(b.right);
11159 st.left = st.top = "0";
11160 a = {width: bw, points: pt};
11163 wrap.setSize(b.width, 0);
11164 wrap.setY(b.bottom);
11165 st.left = st.top = "0";
11166 a = {height: bh, points: pt};
11169 wrap.setSize(0, 0);
11170 st.right = st.bottom = "0";
11171 a = {width: bw, height: bh};
11174 wrap.setSize(0, 0);
11175 wrap.setY(b.y+b.height);
11176 st.right = st.top = "0";
11177 a = {width: bw, height: bh, points: pt};
11180 wrap.setSize(0, 0);
11181 wrap.setXY([b.right, b.bottom]);
11182 st.left = st.top = "0";
11183 a = {width: bw, height: bh, points: pt};
11186 wrap.setSize(0, 0);
11187 wrap.setX(b.x+b.width);
11188 st.left = st.bottom = "0";
11189 a = {width: bw, height: bh, points: pt};
11192 this.dom.style.visibility = "visible";
11195 arguments.callee.anim = wrap.fxanim(a,
11205 * Slides the element out of view. An anchor point can be optionally passed to set the end point
11206 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
11207 * 'hidden') but block elements will still take up space in the document. The element must be removed
11208 * from the DOM using the 'remove' config option if desired. This function automatically handles
11209 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
11212 // default: slide the element out to the top
11215 // custom: slide the element out to the right with a 2-second duration
11216 el.slideOut('r', { duration: 2 });
11218 // common config options shown with default values
11226 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11227 * @param {Object} options (optional) Object literal with any of the Fx config options
11228 * @return {Roo.Element} The Element
11230 slideOut : function(anchor, o){
11231 var el = this.getFxEl();
11234 el.queueFx(o, function(){
11236 anchor = anchor || "t";
11238 // restore values after effect
11239 var r = this.getFxRestore();
11241 var b = this.getBox();
11242 // fixed size for slide
11246 var wrap = this.fxWrap(r.pos, o, "visible");
11248 var st = this.dom.style;
11249 st.visibility = "visible";
11250 st.position = "absolute";
11254 var after = function(){
11256 el.setDisplayed(false);
11261 el.fxUnwrap(wrap, r.pos, o);
11263 st.width = r.width;
11264 st.height = r.height;
11269 var a, zero = {to: 0};
11270 switch(anchor.toLowerCase()){
11272 st.left = st.bottom = "0";
11273 a = {height: zero};
11276 st.right = st.top = "0";
11280 st.left = st.top = "0";
11281 a = {width: zero, points: {to:[b.right, b.y]}};
11284 st.left = st.top = "0";
11285 a = {height: zero, points: {to:[b.x, b.bottom]}};
11288 st.right = st.bottom = "0";
11289 a = {width: zero, height: zero};
11292 st.right = st.top = "0";
11293 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
11296 st.left = st.top = "0";
11297 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
11300 st.left = st.bottom = "0";
11301 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
11305 arguments.callee.anim = wrap.fxanim(a,
11315 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
11316 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
11317 * The element must be removed from the DOM using the 'remove' config option if desired.
11323 // common config options shown with default values
11331 * @param {Object} options (optional) Object literal with any of the Fx config options
11332 * @return {Roo.Element} The Element
11334 puff : function(o){
11335 var el = this.getFxEl();
11338 el.queueFx(o, function(){
11339 this.clearOpacity();
11342 // restore values after effect
11343 var r = this.getFxRestore();
11344 var st = this.dom.style;
11346 var after = function(){
11348 el.setDisplayed(false);
11355 el.setPositioning(r.pos);
11356 st.width = r.width;
11357 st.height = r.height;
11362 var width = this.getWidth();
11363 var height = this.getHeight();
11365 arguments.callee.anim = this.fxanim({
11366 width : {to: this.adjustWidth(width * 2)},
11367 height : {to: this.adjustHeight(height * 2)},
11368 points : {by: [-(width * .5), -(height * .5)]},
11370 fontSize: {to:200, unit: "%"}
11381 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
11382 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
11383 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
11389 // all config options shown with default values
11397 * @param {Object} options (optional) Object literal with any of the Fx config options
11398 * @return {Roo.Element} The Element
11400 switchOff : function(o){
11401 var el = this.getFxEl();
11404 el.queueFx(o, function(){
11405 this.clearOpacity();
11408 // restore values after effect
11409 var r = this.getFxRestore();
11410 var st = this.dom.style;
11412 var after = function(){
11414 el.setDisplayed(false);
11420 el.setPositioning(r.pos);
11421 st.width = r.width;
11422 st.height = r.height;
11427 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
11428 this.clearOpacity();
11432 points:{by:[0, this.getHeight() * .5]}
11433 }, o, 'motion', 0.3, 'easeIn', after);
11434 }).defer(100, this);
11441 * Highlights the Element by setting a color (applies to the background-color by default, but can be
11442 * changed using the "attr" config option) and then fading back to the original color. If no original
11443 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
11446 // default: highlight background to yellow
11449 // custom: highlight foreground text to blue for 2 seconds
11450 el.highlight("0000ff", { attr: 'color', duration: 2 });
11452 // common config options shown with default values
11453 el.highlight("ffff9c", {
11454 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
11455 endColor: (current color) or "ffffff",
11460 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
11461 * @param {Object} options (optional) Object literal with any of the Fx config options
11462 * @return {Roo.Element} The Element
11464 highlight : function(color, o){
11465 var el = this.getFxEl();
11468 el.queueFx(o, function(){
11469 color = color || "ffff9c";
11470 attr = o.attr || "backgroundColor";
11472 this.clearOpacity();
11475 var origColor = this.getColor(attr);
11476 var restoreColor = this.dom.style[attr];
11477 endColor = (o.endColor || origColor) || "ffffff";
11479 var after = function(){
11480 el.dom.style[attr] = restoreColor;
11485 a[attr] = {from: color, to: endColor};
11486 arguments.callee.anim = this.fxanim(a,
11496 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
11499 // default: a single light blue ripple
11502 // custom: 3 red ripples lasting 3 seconds total
11503 el.frame("ff0000", 3, { duration: 3 });
11505 // common config options shown with default values
11506 el.frame("C3DAF9", 1, {
11507 duration: 1 //duration of entire animation (not each individual ripple)
11508 // Note: Easing is not configurable and will be ignored if included
11511 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
11512 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
11513 * @param {Object} options (optional) Object literal with any of the Fx config options
11514 * @return {Roo.Element} The Element
11516 frame : function(color, count, o){
11517 var el = this.getFxEl();
11520 el.queueFx(o, function(){
11521 color = color || "#C3DAF9";
11522 if(color.length == 6){
11523 color = "#" + color;
11525 count = count || 1;
11526 duration = o.duration || 1;
11529 var b = this.getBox();
11530 var animFn = function(){
11531 var proxy = this.createProxy({
11534 visbility:"hidden",
11535 position:"absolute",
11536 "z-index":"35000", // yee haw
11537 border:"0px solid " + color
11540 var scale = Roo.isBorderBox ? 2 : 1;
11542 top:{from:b.y, to:b.y - 20},
11543 left:{from:b.x, to:b.x - 20},
11544 borderWidth:{from:0, to:10},
11545 opacity:{from:1, to:0},
11546 height:{from:b.height, to:(b.height + (20*scale))},
11547 width:{from:b.width, to:(b.width + (20*scale))}
11548 }, duration, function(){
11552 animFn.defer((duration/2)*1000, this);
11563 * Creates a pause before any subsequent queued effects begin. If there are
11564 * no effects queued after the pause it will have no effect.
11569 * @param {Number} seconds The length of time to pause (in seconds)
11570 * @return {Roo.Element} The Element
11572 pause : function(seconds){
11573 var el = this.getFxEl();
11576 el.queueFx(o, function(){
11577 setTimeout(function(){
11579 }, seconds * 1000);
11585 * Fade an element in (from transparent to opaque). The ending opacity can be specified
11586 * using the "endOpacity" config option.
11589 // default: fade in from opacity 0 to 100%
11592 // custom: fade in from opacity 0 to 75% over 2 seconds
11593 el.fadeIn({ endOpacity: .75, duration: 2});
11595 // common config options shown with default values
11597 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
11602 * @param {Object} options (optional) Object literal with any of the Fx config options
11603 * @return {Roo.Element} The Element
11605 fadeIn : function(o){
11606 var el = this.getFxEl();
11608 el.queueFx(o, function(){
11609 this.setOpacity(0);
11611 this.dom.style.visibility = 'visible';
11612 var to = o.endOpacity || 1;
11613 arguments.callee.anim = this.fxanim({opacity:{to:to}},
11614 o, null, .5, "easeOut", function(){
11616 this.clearOpacity();
11625 * Fade an element out (from opaque to transparent). The ending opacity can be specified
11626 * using the "endOpacity" config option.
11629 // default: fade out from the element's current opacity to 0
11632 // custom: fade out from the element's current opacity to 25% over 2 seconds
11633 el.fadeOut({ endOpacity: .25, duration: 2});
11635 // common config options shown with default values
11637 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
11644 * @param {Object} options (optional) Object literal with any of the Fx config options
11645 * @return {Roo.Element} The Element
11647 fadeOut : function(o){
11648 var el = this.getFxEl();
11650 el.queueFx(o, function(){
11651 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
11652 o, null, .5, "easeOut", function(){
11653 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
11654 this.dom.style.display = "none";
11656 this.dom.style.visibility = "hidden";
11658 this.clearOpacity();
11666 * Animates the transition of an element's dimensions from a starting height/width
11667 * to an ending height/width.
11670 // change height and width to 100x100 pixels
11671 el.scale(100, 100);
11673 // common config options shown with default values. The height and width will default to
11674 // the element's existing values if passed as null.
11677 [element's height], {
11682 * @param {Number} width The new width (pass undefined to keep the original width)
11683 * @param {Number} height The new height (pass undefined to keep the original height)
11684 * @param {Object} options (optional) Object literal with any of the Fx config options
11685 * @return {Roo.Element} The Element
11687 scale : function(w, h, o){
11688 this.shift(Roo.apply({}, o, {
11696 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
11697 * Any of these properties not specified in the config object will not be changed. This effect
11698 * requires that at least one new dimension, position or opacity setting must be passed in on
11699 * the config object in order for the function to have any effect.
11702 // slide the element horizontally to x position 200 while changing the height and opacity
11703 el.shift({ x: 200, height: 50, opacity: .8 });
11705 // common config options shown with default values.
11707 width: [element's width],
11708 height: [element's height],
11709 x: [element's x position],
11710 y: [element's y position],
11711 opacity: [element's opacity],
11716 * @param {Object} options Object literal with any of the Fx config options
11717 * @return {Roo.Element} The Element
11719 shift : function(o){
11720 var el = this.getFxEl();
11722 el.queueFx(o, function(){
11723 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
11724 if(w !== undefined){
11725 a.width = {to: this.adjustWidth(w)};
11727 if(h !== undefined){
11728 a.height = {to: this.adjustHeight(h)};
11730 if(x !== undefined || y !== undefined){
11732 x !== undefined ? x : this.getX(),
11733 y !== undefined ? y : this.getY()
11736 if(op !== undefined){
11737 a.opacity = {to: op};
11739 if(o.xy !== undefined){
11740 a.points = {to: o.xy};
11742 arguments.callee.anim = this.fxanim(a,
11743 o, 'motion', .35, "easeOut", function(){
11751 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
11752 * ending point of the effect.
11755 // default: slide the element downward while fading out
11758 // custom: slide the element out to the right with a 2-second duration
11759 el.ghost('r', { duration: 2 });
11761 // common config options shown with default values
11769 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
11770 * @param {Object} options (optional) Object literal with any of the Fx config options
11771 * @return {Roo.Element} The Element
11773 ghost : function(anchor, o){
11774 var el = this.getFxEl();
11777 el.queueFx(o, function(){
11778 anchor = anchor || "b";
11780 // restore values after effect
11781 var r = this.getFxRestore();
11782 var w = this.getWidth(),
11783 h = this.getHeight();
11785 var st = this.dom.style;
11787 var after = function(){
11789 el.setDisplayed(false);
11795 el.setPositioning(r.pos);
11796 st.width = r.width;
11797 st.height = r.height;
11802 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
11803 switch(anchor.toLowerCase()){
11830 arguments.callee.anim = this.fxanim(a,
11840 * Ensures that all effects queued after syncFx is called on the element are
11841 * run concurrently. This is the opposite of {@link #sequenceFx}.
11842 * @return {Roo.Element} The Element
11844 syncFx : function(){
11845 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11854 * Ensures that all effects queued after sequenceFx is called on the element are
11855 * run in sequence. This is the opposite of {@link #syncFx}.
11856 * @return {Roo.Element} The Element
11858 sequenceFx : function(){
11859 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11861 concurrent : false,
11868 nextFx : function(){
11869 var ef = this.fxQueue[0];
11876 * Returns true if the element has any effects actively running or queued, else returns false.
11877 * @return {Boolean} True if element has active effects, else false
11879 hasActiveFx : function(){
11880 return this.fxQueue && this.fxQueue[0];
11884 * Stops any running effects and clears the element's internal effects queue if it contains
11885 * any additional effects that haven't started yet.
11886 * @return {Roo.Element} The Element
11888 stopFx : function(){
11889 if(this.hasActiveFx()){
11890 var cur = this.fxQueue[0];
11891 if(cur && cur.anim && cur.anim.isAnimated()){
11892 this.fxQueue = [cur]; // clear out others
11893 cur.anim.stop(true);
11900 beforeFx : function(o){
11901 if(this.hasActiveFx() && !o.concurrent){
11912 * Returns true if the element is currently blocking so that no other effect can be queued
11913 * until this effect is finished, else returns false if blocking is not set. This is commonly
11914 * used to ensure that an effect initiated by a user action runs to completion prior to the
11915 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
11916 * @return {Boolean} True if blocking, else false
11918 hasFxBlock : function(){
11919 var q = this.fxQueue;
11920 return q && q[0] && q[0].block;
11924 queueFx : function(o, fn){
11928 if(!this.hasFxBlock()){
11929 Roo.applyIf(o, this.fxDefaults);
11931 var run = this.beforeFx(o);
11932 fn.block = o.block;
11933 this.fxQueue.push(fn);
11945 fxWrap : function(pos, o, vis){
11947 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
11950 wrapXY = this.getXY();
11952 var div = document.createElement("div");
11953 div.style.visibility = vis;
11954 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
11955 wrap.setPositioning(pos);
11956 if(wrap.getStyle("position") == "static"){
11957 wrap.position("relative");
11959 this.clearPositioning('auto');
11961 wrap.dom.appendChild(this.dom);
11963 wrap.setXY(wrapXY);
11970 fxUnwrap : function(wrap, pos, o){
11971 this.clearPositioning();
11972 this.setPositioning(pos);
11974 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11980 getFxRestore : function(){
11981 var st = this.dom.style;
11982 return {pos: this.getPositioning(), width: st.width, height : st.height};
11986 afterFx : function(o){
11988 this.applyStyles(o.afterStyle);
11991 this.addClass(o.afterCls);
11993 if(o.remove === true){
11996 Roo.callback(o.callback, o.scope, [this]);
11998 this.fxQueue.shift();
12004 getFxEl : function(){ // support for composite element fx
12005 return Roo.get(this.dom);
12009 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
12010 animType = animType || 'run';
12012 var anim = Roo.lib.Anim[animType](
12014 (opt.duration || defaultDur) || .35,
12015 (opt.easing || defaultEase) || 'easeOut',
12017 Roo.callback(cb, this);
12026 // backwords compat
12027 Roo.Fx.resize = Roo.Fx.scale;
12029 //When included, Roo.Fx is automatically applied to Element so that all basic
12030 //effects are available directly via the Element API
12031 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
12033 * Ext JS Library 1.1.1
12034 * Copyright(c) 2006-2007, Ext JS, LLC.
12036 * Originally Released Under LGPL - original licence link has changed is not relivant.
12039 * <script type="text/javascript">
12044 * @class Roo.CompositeElement
12045 * Standard composite class. Creates a Roo.Element for every element in the collection.
12047 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12048 * actions will be performed on all the elements in this collection.</b>
12050 * All methods return <i>this</i> and can be chained.
12052 var els = Roo.select("#some-el div.some-class", true);
12053 // or select directly from an existing element
12054 var el = Roo.get('some-el');
12055 el.select('div.some-class', true);
12057 els.setWidth(100); // all elements become 100 width
12058 els.hide(true); // all elements fade out and hide
12060 els.setWidth(100).hide(true);
12063 Roo.CompositeElement = function(els){
12064 this.elements = [];
12065 this.addElements(els);
12067 Roo.CompositeElement.prototype = {
12069 addElements : function(els){
12073 if(typeof els == "string"){
12074 els = Roo.Element.selectorFunction(els);
12076 var yels = this.elements;
12077 var index = yels.length-1;
12078 for(var i = 0, len = els.length; i < len; i++) {
12079 yels[++index] = Roo.get(els[i]);
12085 * Clears this composite and adds the elements returned by the passed selector.
12086 * @param {String/Array} els A string CSS selector, an array of elements or an element
12087 * @return {CompositeElement} this
12089 fill : function(els){
12090 this.elements = [];
12096 * Filters this composite to only elements that match the passed selector.
12097 * @param {String} selector A string CSS selector
12098 * @param {Boolean} inverse return inverse filter (not matches)
12099 * @return {CompositeElement} this
12101 filter : function(selector, inverse){
12103 inverse = inverse || false;
12104 this.each(function(el){
12105 var match = inverse ? !el.is(selector) : el.is(selector);
12107 els[els.length] = el.dom;
12114 invoke : function(fn, args){
12115 var els = this.elements;
12116 for(var i = 0, len = els.length; i < len; i++) {
12117 Roo.Element.prototype[fn].apply(els[i], args);
12122 * Adds elements to this composite.
12123 * @param {String/Array} els A string CSS selector, an array of elements or an element
12124 * @return {CompositeElement} this
12126 add : function(els){
12127 if(typeof els == "string"){
12128 this.addElements(Roo.Element.selectorFunction(els));
12129 }else if(els.length !== undefined){
12130 this.addElements(els);
12132 this.addElements([els]);
12137 * Calls the passed function passing (el, this, index) for each element in this composite.
12138 * @param {Function} fn The function to call
12139 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12140 * @return {CompositeElement} this
12142 each : function(fn, scope){
12143 var els = this.elements;
12144 for(var i = 0, len = els.length; i < len; i++){
12145 if(fn.call(scope || els[i], els[i], this, i) === false) {
12153 * Returns the Element object at the specified index
12154 * @param {Number} index
12155 * @return {Roo.Element}
12157 item : function(index){
12158 return this.elements[index] || null;
12162 * Returns the first Element
12163 * @return {Roo.Element}
12165 first : function(){
12166 return this.item(0);
12170 * Returns the last Element
12171 * @return {Roo.Element}
12174 return this.item(this.elements.length-1);
12178 * Returns the number of elements in this composite
12181 getCount : function(){
12182 return this.elements.length;
12186 * Returns true if this composite contains the passed element
12189 contains : function(el){
12190 return this.indexOf(el) !== -1;
12194 * Returns true if this composite contains the passed element
12197 indexOf : function(el){
12198 return this.elements.indexOf(Roo.get(el));
12203 * Removes the specified element(s).
12204 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
12205 * or an array of any of those.
12206 * @param {Boolean} removeDom (optional) True to also remove the element from the document
12207 * @return {CompositeElement} this
12209 removeElement : function(el, removeDom){
12210 if(el instanceof Array){
12211 for(var i = 0, len = el.length; i < len; i++){
12212 this.removeElement(el[i]);
12216 var index = typeof el == 'number' ? el : this.indexOf(el);
12219 var d = this.elements[index];
12223 d.parentNode.removeChild(d);
12226 this.elements.splice(index, 1);
12232 * Replaces the specified element with the passed element.
12233 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
12235 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
12236 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
12237 * @return {CompositeElement} this
12239 replaceElement : function(el, replacement, domReplace){
12240 var index = typeof el == 'number' ? el : this.indexOf(el);
12243 this.elements[index].replaceWith(replacement);
12245 this.elements.splice(index, 1, Roo.get(replacement))
12252 * Removes all elements.
12254 clear : function(){
12255 this.elements = [];
12259 Roo.CompositeElement.createCall = function(proto, fnName){
12260 if(!proto[fnName]){
12261 proto[fnName] = function(){
12262 return this.invoke(fnName, arguments);
12266 for(var fnName in Roo.Element.prototype){
12267 if(typeof Roo.Element.prototype[fnName] == "function"){
12268 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
12274 * Ext JS Library 1.1.1
12275 * Copyright(c) 2006-2007, Ext JS, LLC.
12277 * Originally Released Under LGPL - original licence link has changed is not relivant.
12280 * <script type="text/javascript">
12284 * @class Roo.CompositeElementLite
12285 * @extends Roo.CompositeElement
12286 * Flyweight composite class. Reuses the same Roo.Element for element operations.
12288 var els = Roo.select("#some-el div.some-class");
12289 // or select directly from an existing element
12290 var el = Roo.get('some-el');
12291 el.select('div.some-class');
12293 els.setWidth(100); // all elements become 100 width
12294 els.hide(true); // all elements fade out and hide
12296 els.setWidth(100).hide(true);
12297 </code></pre><br><br>
12298 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12299 * actions will be performed on all the elements in this collection.</b>
12301 Roo.CompositeElementLite = function(els){
12302 Roo.CompositeElementLite.superclass.constructor.call(this, els);
12303 this.el = new Roo.Element.Flyweight();
12305 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
12306 addElements : function(els){
12308 if(els instanceof Array){
12309 this.elements = this.elements.concat(els);
12311 var yels = this.elements;
12312 var index = yels.length-1;
12313 for(var i = 0, len = els.length; i < len; i++) {
12314 yels[++index] = els[i];
12320 invoke : function(fn, args){
12321 var els = this.elements;
12323 for(var i = 0, len = els.length; i < len; i++) {
12325 Roo.Element.prototype[fn].apply(el, args);
12330 * Returns a flyweight Element of the dom element object at the specified index
12331 * @param {Number} index
12332 * @return {Roo.Element}
12334 item : function(index){
12335 if(!this.elements[index]){
12338 this.el.dom = this.elements[index];
12342 // fixes scope with flyweight
12343 addListener : function(eventName, handler, scope, opt){
12344 var els = this.elements;
12345 for(var i = 0, len = els.length; i < len; i++) {
12346 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
12352 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
12353 * passed is the flyweight (shared) Roo.Element instance, so if you require a
12354 * a reference to the dom node, use el.dom.</b>
12355 * @param {Function} fn The function to call
12356 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12357 * @return {CompositeElement} this
12359 each : function(fn, scope){
12360 var els = this.elements;
12362 for(var i = 0, len = els.length; i < len; i++){
12364 if(fn.call(scope || el, el, this, i) === false){
12371 indexOf : function(el){
12372 return this.elements.indexOf(Roo.getDom(el));
12375 replaceElement : function(el, replacement, domReplace){
12376 var index = typeof el == 'number' ? el : this.indexOf(el);
12378 replacement = Roo.getDom(replacement);
12380 var d = this.elements[index];
12381 d.parentNode.insertBefore(replacement, d);
12382 d.parentNode.removeChild(d);
12384 this.elements.splice(index, 1, replacement);
12389 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
12393 * Ext JS Library 1.1.1
12394 * Copyright(c) 2006-2007, Ext JS, LLC.
12396 * Originally Released Under LGPL - original licence link has changed is not relivant.
12399 * <script type="text/javascript">
12405 * @class Roo.data.Connection
12406 * @extends Roo.util.Observable
12407 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
12408 * either to a configured URL, or to a URL specified at request time.
12410 * Requests made by this class are asynchronous, and will return immediately. No data from
12411 * the server will be available to the statement immediately following the {@link #request} call.
12412 * To process returned data, use a callback in the request options object, or an event listener.
12414 * Note: If you are doing a file upload, you will not get a normal response object sent back to
12415 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
12416 * The response object is created using the innerHTML of the IFRAME's document as the responseText
12417 * property and, if present, the IFRAME's XML document as the responseXML property.
12419 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
12420 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
12421 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
12422 * standard DOM methods.
12424 * @param {Object} config a configuration object.
12426 Roo.data.Connection = function(config){
12427 Roo.apply(this, config);
12430 * @event beforerequest
12431 * Fires before a network request is made to retrieve a data object.
12432 * @param {Connection} conn This Connection object.
12433 * @param {Object} options The options config object passed to the {@link #request} method.
12435 "beforerequest" : true,
12437 * @event requestcomplete
12438 * Fires if the request was successfully completed.
12439 * @param {Connection} conn This Connection object.
12440 * @param {Object} response The XHR object containing the response data.
12441 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12442 * @param {Object} options The options config object passed to the {@link #request} method.
12444 "requestcomplete" : true,
12446 * @event requestexception
12447 * Fires if an error HTTP status was returned from the server.
12448 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
12449 * @param {Connection} conn This Connection object.
12450 * @param {Object} response The XHR object containing the response data.
12451 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12452 * @param {Object} options The options config object passed to the {@link #request} method.
12454 "requestexception" : true
12456 Roo.data.Connection.superclass.constructor.call(this);
12459 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
12461 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12464 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12465 * extra parameters to each request made by this object. (defaults to undefined)
12468 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12469 * to each request made by this object. (defaults to undefined)
12472 * @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)
12475 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12479 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12485 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12488 disableCaching: true,
12491 * Sends an HTTP request to a remote server.
12492 * @param {Object} options An object which may contain the following properties:<ul>
12493 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
12494 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
12495 * request, a url encoded string or a function to call to get either.</li>
12496 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
12497 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
12498 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
12499 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
12500 * <li>options {Object} The parameter to the request call.</li>
12501 * <li>success {Boolean} True if the request succeeded.</li>
12502 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12504 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
12505 * The callback is passed the following parameters:<ul>
12506 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12507 * <li>options {Object} The parameter to the request call.</li>
12509 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
12510 * The callback is passed the following parameters:<ul>
12511 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12512 * <li>options {Object} The parameter to the request call.</li>
12514 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
12515 * for the callback function. Defaults to the browser window.</li>
12516 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
12517 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
12518 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
12519 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
12520 * params for the post data. Any params will be appended to the URL.</li>
12521 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
12523 * @return {Number} transactionId
12525 request : function(o){
12526 if(this.fireEvent("beforerequest", this, o) !== false){
12529 if(typeof p == "function"){
12530 p = p.call(o.scope||window, o);
12532 if(typeof p == "object"){
12533 p = Roo.urlEncode(o.params);
12535 if(this.extraParams){
12536 var extras = Roo.urlEncode(this.extraParams);
12537 p = p ? (p + '&' + extras) : extras;
12540 var url = o.url || this.url;
12541 if(typeof url == 'function'){
12542 url = url.call(o.scope||window, o);
12546 var form = Roo.getDom(o.form);
12547 url = url || form.action;
12549 var enctype = form.getAttribute("enctype");
12552 return this.doFormDataUpload(o, url);
12555 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
12556 return this.doFormUpload(o, p, url);
12558 var f = Roo.lib.Ajax.serializeForm(form);
12559 p = p ? (p + '&' + f) : f;
12562 if (!o.form && o.formData) {
12563 o.formData = o.formData === true ? new FormData() : o.formData;
12564 for (var k in o.params) {
12565 o.formData.append(k,o.params[k]);
12568 return this.doFormDataUpload(o, url);
12572 var hs = o.headers;
12573 if(this.defaultHeaders){
12574 hs = Roo.apply(hs || {}, this.defaultHeaders);
12581 success: this.handleResponse,
12582 failure: this.handleFailure,
12584 argument: {options: o},
12585 timeout : o.timeout || this.timeout
12588 var method = o.method||this.method||(p ? "POST" : "GET");
12590 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
12591 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
12594 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
12598 }else if(this.autoAbort !== false){
12602 if((method == 'GET' && p) || o.xmlData){
12603 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
12606 Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
12607 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
12608 Roo.lib.Ajax.useDefaultHeader == true;
12609 return this.transId;
12611 Roo.callback(o.callback, o.scope, [o, null, null]);
12617 * Determine whether this object has a request outstanding.
12618 * @param {Number} transactionId (Optional) defaults to the last transaction
12619 * @return {Boolean} True if there is an outstanding request.
12621 isLoading : function(transId){
12623 return Roo.lib.Ajax.isCallInProgress(transId);
12625 return this.transId ? true : false;
12630 * Aborts any outstanding request.
12631 * @param {Number} transactionId (Optional) defaults to the last transaction
12633 abort : function(transId){
12634 if(transId || this.isLoading()){
12635 Roo.lib.Ajax.abort(transId || this.transId);
12640 handleResponse : function(response){
12641 this.transId = false;
12642 var options = response.argument.options;
12643 response.argument = options ? options.argument : null;
12644 this.fireEvent("requestcomplete", this, response, options);
12645 Roo.callback(options.success, options.scope, [response, options]);
12646 Roo.callback(options.callback, options.scope, [options, true, response]);
12650 handleFailure : function(response, e){
12651 this.transId = false;
12652 var options = response.argument.options;
12653 response.argument = options ? options.argument : null;
12654 this.fireEvent("requestexception", this, response, options, e);
12655 Roo.callback(options.failure, options.scope, [response, options]);
12656 Roo.callback(options.callback, options.scope, [options, false, response]);
12660 doFormUpload : function(o, ps, url){
12662 var frame = document.createElement('iframe');
12665 frame.className = 'x-hidden';
12667 frame.src = Roo.SSL_SECURE_URL;
12669 document.body.appendChild(frame);
12672 document.frames[id].name = id;
12675 var form = Roo.getDom(o.form);
12677 form.method = 'POST';
12678 form.enctype = form.encoding = 'multipart/form-data';
12684 if(ps){ // add dynamic params
12686 ps = Roo.urlDecode(ps, false);
12688 if(ps.hasOwnProperty(k)){
12689 hd = document.createElement('input');
12690 hd.type = 'hidden';
12693 form.appendChild(hd);
12700 var r = { // bogus response object
12705 r.argument = o ? o.argument : null;
12710 doc = frame.contentWindow.document;
12712 doc = (frame.contentDocument || window.frames[id].document);
12714 if(doc && doc.body){
12715 r.responseText = doc.body.innerHTML;
12717 if(doc && doc.XMLDocument){
12718 r.responseXML = doc.XMLDocument;
12720 r.responseXML = doc;
12727 Roo.EventManager.removeListener(frame, 'load', cb, this);
12729 this.fireEvent("requestcomplete", this, r, o);
12730 Roo.callback(o.success, o.scope, [r, o]);
12731 Roo.callback(o.callback, o.scope, [o, true, r]);
12733 setTimeout(function(){document.body.removeChild(frame);}, 100);
12736 Roo.EventManager.on(frame, 'load', cb, this);
12739 if(hiddens){ // remove dynamic params
12740 for(var i = 0, len = hiddens.length; i < len; i++){
12741 form.removeChild(hiddens[i]);
12745 // this is a 'formdata version???'
12748 doFormDataUpload : function(o, url)
12752 var form = Roo.getDom(o.form);
12753 form.enctype = form.encoding = 'multipart/form-data';
12754 formData = o.formData === true ? new FormData(form) : o.formData;
12756 formData = o.formData === true ? new FormData() : o.formData;
12761 success: this.handleResponse,
12762 failure: this.handleFailure,
12764 argument: {options: o},
12765 timeout : o.timeout || this.timeout
12768 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
12772 }else if(this.autoAbort !== false){
12776 //Roo.lib.Ajax.defaultPostHeader = null;
12777 Roo.lib.Ajax.useDefaultHeader = false;
12778 this.transId = Roo.lib.Ajax.request( "POST", url, cb, formData, o);
12779 Roo.lib.Ajax.useDefaultHeader = true;
12787 * Ext JS Library 1.1.1
12788 * Copyright(c) 2006-2007, Ext JS, LLC.
12790 * Originally Released Under LGPL - original licence link has changed is not relivant.
12793 * <script type="text/javascript">
12797 * Global Ajax request class.
12800 * @extends Roo.data.Connection
12803 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
12804 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
12805 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
12806 * @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)
12807 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12808 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
12809 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12811 Roo.Ajax = new Roo.data.Connection({
12820 * Serialize the passed form into a url encoded string
12822 * @param {String/HTMLElement} form
12825 serializeForm : function(form){
12826 return Roo.lib.Ajax.serializeForm(form);
12830 * Ext JS Library 1.1.1
12831 * Copyright(c) 2006-2007, Ext JS, LLC.
12833 * Originally Released Under LGPL - original licence link has changed is not relivant.
12836 * <script type="text/javascript">
12841 * @class Roo.UpdateManager
12842 * @extends Roo.util.Observable
12843 * Provides AJAX-style update for Element object.<br><br>
12846 * // Get it from a Roo.Element object
12847 * var el = Roo.get("foo");
12848 * var mgr = el.getUpdateManager();
12849 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
12851 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
12853 * // or directly (returns the same UpdateManager instance)
12854 * var mgr = new Roo.UpdateManager("myElementId");
12855 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
12856 * mgr.on("update", myFcnNeedsToKnow);
12858 // short handed call directly from the element object
12859 Roo.get("foo").load({
12863 text: "Loading Foo..."
12867 * Create new UpdateManager directly.
12868 * @param {String/HTMLElement/Roo.Element} el The element to update
12869 * @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).
12871 Roo.UpdateManager = function(el, forceNew){
12873 if(!forceNew && el.updateManager){
12874 return el.updateManager;
12877 * The Element object
12878 * @type Roo.Element
12882 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
12885 this.defaultUrl = null;
12889 * @event beforeupdate
12890 * Fired before an update is made, return false from your handler and the update is cancelled.
12891 * @param {Roo.Element} el
12892 * @param {String/Object/Function} url
12893 * @param {String/Object} params
12895 "beforeupdate": true,
12898 * Fired after successful update is made.
12899 * @param {Roo.Element} el
12900 * @param {Object} oResponseObject The response Object
12905 * Fired on update failure.
12906 * @param {Roo.Element} el
12907 * @param {Object} oResponseObject The response Object
12911 var d = Roo.UpdateManager.defaults;
12913 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
12916 this.sslBlankUrl = d.sslBlankUrl;
12918 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
12921 this.disableCaching = d.disableCaching;
12923 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
12926 this.indicatorText = d.indicatorText;
12928 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
12931 this.showLoadIndicator = d.showLoadIndicator;
12933 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
12936 this.timeout = d.timeout;
12939 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
12942 this.loadScripts = d.loadScripts;
12945 * Transaction object of current executing transaction
12947 this.transaction = null;
12952 this.autoRefreshProcId = null;
12954 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
12957 this.refreshDelegate = this.refresh.createDelegate(this);
12959 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
12962 this.updateDelegate = this.update.createDelegate(this);
12964 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
12967 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
12971 this.successDelegate = this.processSuccess.createDelegate(this);
12975 this.failureDelegate = this.processFailure.createDelegate(this);
12977 if(!this.renderer){
12979 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
12981 this.renderer = new Roo.UpdateManager.BasicRenderer();
12984 Roo.UpdateManager.superclass.constructor.call(this);
12987 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
12989 * Get the Element this UpdateManager is bound to
12990 * @return {Roo.Element} The element
12992 getEl : function(){
12996 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
12997 * @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:
13000 url: "your-url.php",<br/>
13001 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
13002 callback: yourFunction,<br/>
13003 scope: yourObject, //(optional scope) <br/>
13004 discardUrl: false, <br/>
13005 nocache: false,<br/>
13006 text: "Loading...",<br/>
13008 scripts: false<br/>
13011 * The only required property is url. The optional properties nocache, text and scripts
13012 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
13013 * @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}
13014 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13015 * @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.
13017 update : function(url, params, callback, discardUrl){
13018 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
13019 var method = this.method,
13021 if(typeof url == "object"){ // must be config object
13024 params = params || cfg.params;
13025 callback = callback || cfg.callback;
13026 discardUrl = discardUrl || cfg.discardUrl;
13027 if(callback && cfg.scope){
13028 callback = callback.createDelegate(cfg.scope);
13030 if(typeof cfg.method != "undefined"){method = cfg.method;};
13031 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
13032 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
13033 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
13034 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
13036 this.showLoading();
13038 this.defaultUrl = url;
13040 if(typeof url == "function"){
13041 url = url.call(this);
13044 method = method || (params ? "POST" : "GET");
13045 if(method == "GET"){
13046 url = this.prepareUrl(url);
13049 var o = Roo.apply(cfg ||{}, {
13052 success: this.successDelegate,
13053 failure: this.failureDelegate,
13054 callback: undefined,
13055 timeout: (this.timeout*1000),
13056 argument: {"url": url, "form": null, "callback": callback, "params": params}
13058 Roo.log("updated manager called with timeout of " + o.timeout);
13059 this.transaction = Roo.Ajax.request(o);
13064 * 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.
13065 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
13066 * @param {String/HTMLElement} form The form Id or form element
13067 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
13068 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
13069 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13071 formUpdate : function(form, url, reset, callback){
13072 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
13073 if(typeof url == "function"){
13074 url = url.call(this);
13076 form = Roo.getDom(form);
13077 this.transaction = Roo.Ajax.request({
13080 success: this.successDelegate,
13081 failure: this.failureDelegate,
13082 timeout: (this.timeout*1000),
13083 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
13085 this.showLoading.defer(1, this);
13090 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
13091 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13093 refresh : function(callback){
13094 if(this.defaultUrl == null){
13097 this.update(this.defaultUrl, null, callback, true);
13101 * Set this element to auto refresh.
13102 * @param {Number} interval How often to update (in seconds).
13103 * @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)
13104 * @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}
13105 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13106 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
13108 startAutoRefresh : function(interval, url, params, callback, refreshNow){
13110 this.update(url || this.defaultUrl, params, callback, true);
13112 if(this.autoRefreshProcId){
13113 clearInterval(this.autoRefreshProcId);
13115 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
13119 * Stop auto refresh on this element.
13121 stopAutoRefresh : function(){
13122 if(this.autoRefreshProcId){
13123 clearInterval(this.autoRefreshProcId);
13124 delete this.autoRefreshProcId;
13128 isAutoRefreshing : function(){
13129 return this.autoRefreshProcId ? true : false;
13132 * Called to update the element to "Loading" state. Override to perform custom action.
13134 showLoading : function(){
13135 if(this.showLoadIndicator){
13136 this.el.update(this.indicatorText);
13141 * Adds unique parameter to query string if disableCaching = true
13144 prepareUrl : function(url){
13145 if(this.disableCaching){
13146 var append = "_dc=" + (new Date().getTime());
13147 if(url.indexOf("?") !== -1){
13148 url += "&" + append;
13150 url += "?" + append;
13159 processSuccess : function(response){
13160 this.transaction = null;
13161 if(response.argument.form && response.argument.reset){
13162 try{ // put in try/catch since some older FF releases had problems with this
13163 response.argument.form.reset();
13166 if(this.loadScripts){
13167 this.renderer.render(this.el, response, this,
13168 this.updateComplete.createDelegate(this, [response]));
13170 this.renderer.render(this.el, response, this);
13171 this.updateComplete(response);
13175 updateComplete : function(response){
13176 this.fireEvent("update", this.el, response);
13177 if(typeof response.argument.callback == "function"){
13178 response.argument.callback(this.el, true, response);
13185 processFailure : function(response){
13186 this.transaction = null;
13187 this.fireEvent("failure", this.el, response);
13188 if(typeof response.argument.callback == "function"){
13189 response.argument.callback(this.el, false, response);
13194 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
13195 * @param {Object} renderer The object implementing the render() method
13197 setRenderer : function(renderer){
13198 this.renderer = renderer;
13201 getRenderer : function(){
13202 return this.renderer;
13206 * Set the defaultUrl used for updates
13207 * @param {String/Function} defaultUrl The url or a function to call to get the url
13209 setDefaultUrl : function(defaultUrl){
13210 this.defaultUrl = defaultUrl;
13214 * Aborts the executing transaction
13216 abort : function(){
13217 if(this.transaction){
13218 Roo.Ajax.abort(this.transaction);
13223 * Returns true if an update is in progress
13224 * @return {Boolean}
13226 isUpdating : function(){
13227 if(this.transaction){
13228 return Roo.Ajax.isLoading(this.transaction);
13235 * @class Roo.UpdateManager.defaults
13236 * @static (not really - but it helps the doc tool)
13237 * The defaults collection enables customizing the default properties of UpdateManager
13239 Roo.UpdateManager.defaults = {
13241 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
13247 * True to process scripts by default (Defaults to false).
13250 loadScripts : false,
13253 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
13256 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
13258 * Whether to append unique parameter on get request to disable caching (Defaults to false).
13261 disableCaching : false,
13263 * Whether to show indicatorText when loading (Defaults to true).
13266 showLoadIndicator : true,
13268 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
13271 indicatorText : '<div class="loading-indicator">Loading...</div>'
13275 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
13277 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
13278 * @param {String/HTMLElement/Roo.Element} el The element to update
13279 * @param {String} url The url
13280 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
13281 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
13284 * @member Roo.UpdateManager
13286 Roo.UpdateManager.updateElement = function(el, url, params, options){
13287 var um = Roo.get(el, true).getUpdateManager();
13288 Roo.apply(um, options);
13289 um.update(url, params, options ? options.callback : null);
13291 // alias for backwards compat
13292 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
13294 * @class Roo.UpdateManager.BasicRenderer
13295 * Default Content renderer. Updates the elements innerHTML with the responseText.
13297 Roo.UpdateManager.BasicRenderer = function(){};
13299 Roo.UpdateManager.BasicRenderer.prototype = {
13301 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
13302 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
13303 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
13304 * @param {Roo.Element} el The element being rendered
13305 * @param {Object} response The YUI Connect response object
13306 * @param {UpdateManager} updateManager The calling update manager
13307 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
13309 render : function(el, response, updateManager, callback){
13310 el.update(response.responseText, updateManager.loadScripts, callback);
13316 * (c)) Alan Knowles
13322 * @class Roo.DomTemplate
13323 * @extends Roo.Template
13324 * An effort at a dom based template engine..
13326 * Similar to XTemplate, except it uses dom parsing to create the template..
13328 * Supported features:
13333 {a_variable} - output encoded.
13334 {a_variable.format:("Y-m-d")} - call a method on the variable
13335 {a_variable:raw} - unencoded output
13336 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
13337 {a_variable:this.method_on_template(...)} - call a method on the template object.
13342 <div roo-for="a_variable or condition.."></div>
13343 <div roo-if="a_variable or condition"></div>
13344 <div roo-exec="some javascript"></div>
13345 <div roo-name="named_template"></div>
13350 Roo.DomTemplate = function()
13352 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
13359 Roo.extend(Roo.DomTemplate, Roo.Template, {
13361 * id counter for sub templates.
13365 * flag to indicate if dom parser is inside a pre,
13366 * it will strip whitespace if not.
13371 * The various sub templates
13379 * basic tag replacing syntax
13382 * // you can fake an object call by doing this
13386 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
13387 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
13389 iterChild : function (node, method) {
13391 var oldPre = this.inPre;
13392 if (node.tagName == 'PRE') {
13395 for( var i = 0; i < node.childNodes.length; i++) {
13396 method.call(this, node.childNodes[i]);
13398 this.inPre = oldPre;
13404 * compile the template
13406 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
13409 compile: function()
13413 // covert the html into DOM...
13417 doc = document.implementation.createHTMLDocument("");
13418 doc.documentElement.innerHTML = this.html ;
13419 div = doc.documentElement;
13421 // old IE... - nasty -- it causes all sorts of issues.. with
13422 // images getting pulled from server..
13423 div = document.createElement('div');
13424 div.innerHTML = this.html;
13426 //doc.documentElement.innerHTML = htmlBody
13432 this.iterChild(div, function(n) {_t.compileNode(n, true); });
13434 var tpls = this.tpls;
13436 // create a top level template from the snippet..
13438 //Roo.log(div.innerHTML);
13445 body : div.innerHTML,
13458 Roo.each(tpls, function(tp){
13459 this.compileTpl(tp);
13460 this.tpls[tp.id] = tp;
13463 this.master = tpls[0];
13469 compileNode : function(node, istop) {
13474 // skip anything not a tag..
13475 if (node.nodeType != 1) {
13476 if (node.nodeType == 3 && !this.inPre) {
13477 // reduce white space..
13478 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
13501 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
13502 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
13503 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
13504 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
13510 // just itterate children..
13511 this.iterChild(node,this.compileNode);
13514 tpl.uid = this.id++;
13515 tpl.value = node.getAttribute('roo-' + tpl.attr);
13516 node.removeAttribute('roo-'+ tpl.attr);
13517 if (tpl.attr != 'name') {
13518 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
13519 node.parentNode.replaceChild(placeholder, node);
13522 var placeholder = document.createElement('span');
13523 placeholder.className = 'roo-tpl-' + tpl.value;
13524 node.parentNode.replaceChild(placeholder, node);
13527 // parent now sees '{domtplXXXX}
13528 this.iterChild(node,this.compileNode);
13530 // we should now have node body...
13531 var div = document.createElement('div');
13532 div.appendChild(node);
13534 // this has the unfortunate side effect of converting tagged attributes
13535 // eg. href="{...}" into %7C...%7D
13536 // this has been fixed by searching for those combo's although it's a bit hacky..
13539 tpl.body = div.innerHTML;
13546 switch (tpl.value) {
13547 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
13548 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
13549 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
13554 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13558 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13562 tpl.id = tpl.value; // replace non characters???
13568 this.tpls.push(tpl);
13578 * Compile a segment of the template into a 'sub-template'
13584 compileTpl : function(tpl)
13586 var fm = Roo.util.Format;
13587 var useF = this.disableFormats !== true;
13589 var sep = Roo.isGecko ? "+\n" : ",\n";
13591 var undef = function(str) {
13592 Roo.debug && Roo.log("Property not found :" + str);
13596 //Roo.log(tpl.body);
13600 var fn = function(m, lbrace, name, format, args)
13603 //Roo.log(arguments);
13604 args = args ? args.replace(/\\'/g,"'") : args;
13605 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
13606 if (typeof(format) == 'undefined') {
13607 format = 'htmlEncode';
13609 if (format == 'raw' ) {
13613 if(name.substr(0, 6) == 'domtpl'){
13614 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
13617 // build an array of options to determine if value is undefined..
13619 // basically get 'xxxx.yyyy' then do
13620 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
13621 // (function () { Roo.log("Property not found"); return ''; })() :
13626 Roo.each(name.split('.'), function(st) {
13627 lookfor += (lookfor.length ? '.': '') + st;
13628 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
13631 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
13634 if(format && useF){
13636 args = args ? ',' + args : "";
13638 if(format.substr(0, 5) != "this."){
13639 format = "fm." + format + '(';
13641 format = 'this.call("'+ format.substr(5) + '", ';
13645 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
13648 if (args && args.length) {
13649 // called with xxyx.yuu:(test,test)
13651 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
13653 // raw.. - :raw modifier..
13654 return "'"+ sep + udef_st + name + ")"+sep+"'";
13658 // branched to use + in gecko and [].join() in others
13660 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
13661 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
13664 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
13665 body.push(tpl.body.replace(/(\r\n|\n)/g,
13666 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
13667 body.push("'].join('');};};");
13668 body = body.join('');
13671 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
13673 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
13680 * same as applyTemplate, except it's done to one of the subTemplates
13681 * when using named templates, you can do:
13683 * var str = pl.applySubTemplate('your-name', values);
13686 * @param {Number} id of the template
13687 * @param {Object} values to apply to template
13688 * @param {Object} parent (normaly the instance of this object)
13690 applySubTemplate : function(id, values, parent)
13694 var t = this.tpls[id];
13698 if(t.ifCall && !t.ifCall.call(this, values, parent)){
13699 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
13703 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
13710 if(t.execCall && t.execCall.call(this, values, parent)){
13714 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
13720 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
13721 parent = t.target ? values : parent;
13722 if(t.forCall && vs instanceof Array){
13724 for(var i = 0, len = vs.length; i < len; i++){
13726 buf[buf.length] = t.compiled.call(this, vs[i], parent);
13728 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
13730 //Roo.log(t.compiled);
13734 return buf.join('');
13737 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
13742 return t.compiled.call(this, vs, parent);
13744 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
13746 //Roo.log(t.compiled);
13754 applyTemplate : function(values){
13755 return this.master.compiled.call(this, values, {});
13756 //var s = this.subs;
13759 apply : function(){
13760 return this.applyTemplate.apply(this, arguments);
13765 Roo.DomTemplate.from = function(el){
13766 el = Roo.getDom(el);
13767 return new Roo.Domtemplate(el.value || el.innerHTML);
13770 * Ext JS Library 1.1.1
13771 * Copyright(c) 2006-2007, Ext JS, LLC.
13773 * Originally Released Under LGPL - original licence link has changed is not relivant.
13776 * <script type="text/javascript">
13780 * @class Roo.util.DelayedTask
13781 * Provides a convenient method of performing setTimeout where a new
13782 * timeout cancels the old timeout. An example would be performing validation on a keypress.
13783 * You can use this class to buffer
13784 * the keypress events for a certain number of milliseconds, and perform only if they stop
13785 * for that amount of time.
13786 * @constructor The parameters to this constructor serve as defaults and are not required.
13787 * @param {Function} fn (optional) The default function to timeout
13788 * @param {Object} scope (optional) The default scope of that timeout
13789 * @param {Array} args (optional) The default Array of arguments
13791 Roo.util.DelayedTask = function(fn, scope, args){
13792 var id = null, d, t;
13794 var call = function(){
13795 var now = new Date().getTime();
13799 fn.apply(scope, args || []);
13803 * Cancels any pending timeout and queues a new one
13804 * @param {Number} delay The milliseconds to delay
13805 * @param {Function} newFn (optional) Overrides function passed to constructor
13806 * @param {Object} newScope (optional) Overrides scope passed to constructor
13807 * @param {Array} newArgs (optional) Overrides args passed to constructor
13809 this.delay = function(delay, newFn, newScope, newArgs){
13810 if(id && delay != d){
13814 t = new Date().getTime();
13816 scope = newScope || scope;
13817 args = newArgs || args;
13819 id = setInterval(call, d);
13824 * Cancel the last queued timeout
13826 this.cancel = function(){
13834 * Ext JS Library 1.1.1
13835 * Copyright(c) 2006-2007, Ext JS, LLC.
13837 * Originally Released Under LGPL - original licence link has changed is not relivant.
13840 * <script type="text/javascript">
13843 * @class Roo.util.TaskRunner
13844 * Manage background tasks - not sure why this is better that setInterval?
13849 Roo.util.TaskRunner = function(interval){
13850 interval = interval || 10;
13851 var tasks = [], removeQueue = [];
13853 var running = false;
13855 var stopThread = function(){
13861 var startThread = function(){
13864 id = setInterval(runTasks, interval);
13868 var removeTask = function(task){
13869 removeQueue.push(task);
13875 var runTasks = function(){
13876 if(removeQueue.length > 0){
13877 for(var i = 0, len = removeQueue.length; i < len; i++){
13878 tasks.remove(removeQueue[i]);
13881 if(tasks.length < 1){
13886 var now = new Date().getTime();
13887 for(var i = 0, len = tasks.length; i < len; ++i){
13889 var itime = now - t.taskRunTime;
13890 if(t.interval <= itime){
13891 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
13892 t.taskRunTime = now;
13893 if(rt === false || t.taskRunCount === t.repeat){
13898 if(t.duration && t.duration <= (now - t.taskStartTime)){
13905 * Queues a new task.
13906 * @param {Object} task
13908 * Task property : interval = how frequent to run.
13909 * Task object should implement
13911 * Task object may implement
13912 * function onStop()
13914 this.start = function(task){
13916 task.taskStartTime = new Date().getTime();
13917 task.taskRunTime = 0;
13918 task.taskRunCount = 0;
13924 * @param {Object} task
13926 this.stop = function(task){
13933 this.stopAll = function(){
13935 for(var i = 0, len = tasks.length; i < len; i++){
13936 if(tasks[i].onStop){
13945 Roo.TaskMgr = new Roo.util.TaskRunner();/*
13947 * Ext JS Library 1.1.1
13948 * Copyright(c) 2006-2007, Ext JS, LLC.
13950 * Originally Released Under LGPL - original licence link has changed is not relivant.
13953 * <script type="text/javascript">
13958 * @class Roo.util.MixedCollection
13959 * @extends Roo.util.Observable
13960 * A Collection class that maintains both numeric indexes and keys and exposes events.
13962 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
13963 * collection (defaults to false)
13964 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
13965 * and return the key value for that item. This is used when available to look up the key on items that
13966 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
13967 * equivalent to providing an implementation for the {@link #getKey} method.
13969 Roo.util.MixedCollection = function(allowFunctions, keyFn){
13977 * Fires when the collection is cleared.
13982 * Fires when an item is added to the collection.
13983 * @param {Number} index The index at which the item was added.
13984 * @param {Object} o The item added.
13985 * @param {String} key The key associated with the added item.
13990 * Fires when an item is replaced in the collection.
13991 * @param {String} key he key associated with the new added.
13992 * @param {Object} old The item being replaced.
13993 * @param {Object} new The new item.
13998 * Fires when an item is removed from the collection.
13999 * @param {Object} o The item being removed.
14000 * @param {String} key (optional) The key associated with the removed item.
14005 this.allowFunctions = allowFunctions === true;
14007 this.getKey = keyFn;
14009 Roo.util.MixedCollection.superclass.constructor.call(this);
14012 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
14013 allowFunctions : false,
14016 * Adds an item to the collection.
14017 * @param {String} key The key to associate with the item
14018 * @param {Object} o The item to add.
14019 * @return {Object} The item added.
14021 add : function(key, o){
14022 if(arguments.length == 1){
14024 key = this.getKey(o);
14026 if(typeof key == "undefined" || key === null){
14028 this.items.push(o);
14029 this.keys.push(null);
14031 var old = this.map[key];
14033 return this.replace(key, o);
14036 this.items.push(o);
14038 this.keys.push(key);
14040 this.fireEvent("add", this.length-1, o, key);
14045 * MixedCollection has a generic way to fetch keys if you implement getKey.
14048 var mc = new Roo.util.MixedCollection();
14049 mc.add(someEl.dom.id, someEl);
14050 mc.add(otherEl.dom.id, otherEl);
14054 var mc = new Roo.util.MixedCollection();
14055 mc.getKey = function(el){
14061 // or via the constructor
14062 var mc = new Roo.util.MixedCollection(false, function(el){
14068 * @param o {Object} The item for which to find the key.
14069 * @return {Object} The key for the passed item.
14071 getKey : function(o){
14076 * Replaces an item in the collection.
14077 * @param {String} key The key associated with the item to replace, or the item to replace.
14078 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
14079 * @return {Object} The new item.
14081 replace : function(key, o){
14082 if(arguments.length == 1){
14084 key = this.getKey(o);
14086 var old = this.item(key);
14087 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
14088 return this.add(key, o);
14090 var index = this.indexOfKey(key);
14091 this.items[index] = o;
14093 this.fireEvent("replace", key, old, o);
14098 * Adds all elements of an Array or an Object to the collection.
14099 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
14100 * an Array of values, each of which are added to the collection.
14102 addAll : function(objs){
14103 if(arguments.length > 1 || objs instanceof Array){
14104 var args = arguments.length > 1 ? arguments : objs;
14105 for(var i = 0, len = args.length; i < len; i++){
14109 for(var key in objs){
14110 if(this.allowFunctions || typeof objs[key] != "function"){
14111 this.add(key, objs[key]);
14118 * Executes the specified function once for every item in the collection, passing each
14119 * item as the first and only parameter. returning false from the function will stop the iteration.
14120 * @param {Function} fn The function to execute for each item.
14121 * @param {Object} scope (optional) The scope in which to execute the function.
14123 each : function(fn, scope){
14124 var items = [].concat(this.items); // each safe for removal
14125 for(var i = 0, len = items.length; i < len; i++){
14126 if(fn.call(scope || items[i], items[i], i, len) === false){
14133 * Executes the specified function once for every key in the collection, passing each
14134 * key, and its associated item as the first two parameters.
14135 * @param {Function} fn The function to execute for each item.
14136 * @param {Object} scope (optional) The scope in which to execute the function.
14138 eachKey : function(fn, scope){
14139 for(var i = 0, len = this.keys.length; i < len; i++){
14140 fn.call(scope || window, this.keys[i], this.items[i], i, len);
14145 * Returns the first item in the collection which elicits a true return value from the
14146 * passed selection function.
14147 * @param {Function} fn The selection function to execute for each item.
14148 * @param {Object} scope (optional) The scope in which to execute the function.
14149 * @return {Object} The first item in the collection which returned true from the selection function.
14151 find : function(fn, scope){
14152 for(var i = 0, len = this.items.length; i < len; i++){
14153 if(fn.call(scope || window, this.items[i], this.keys[i])){
14154 return this.items[i];
14161 * Inserts an item at the specified index in the collection.
14162 * @param {Number} index The index to insert the item at.
14163 * @param {String} key The key to associate with the new item, or the item itself.
14164 * @param {Object} o (optional) If the second parameter was a key, the new item.
14165 * @return {Object} The item inserted.
14167 insert : function(index, key, o){
14168 if(arguments.length == 2){
14170 key = this.getKey(o);
14172 if(index >= this.length){
14173 return this.add(key, o);
14176 this.items.splice(index, 0, o);
14177 if(typeof key != "undefined" && key != null){
14180 this.keys.splice(index, 0, key);
14181 this.fireEvent("add", index, o, key);
14186 * Removed an item from the collection.
14187 * @param {Object} o The item to remove.
14188 * @return {Object} The item removed.
14190 remove : function(o){
14191 return this.removeAt(this.indexOf(o));
14195 * Remove an item from a specified index in the collection.
14196 * @param {Number} index The index within the collection of the item to remove.
14198 removeAt : function(index){
14199 if(index < this.length && index >= 0){
14201 var o = this.items[index];
14202 this.items.splice(index, 1);
14203 var key = this.keys[index];
14204 if(typeof key != "undefined"){
14205 delete this.map[key];
14207 this.keys.splice(index, 1);
14208 this.fireEvent("remove", o, key);
14213 * Removed an item associated with the passed key fom the collection.
14214 * @param {String} key The key of the item to remove.
14216 removeKey : function(key){
14217 return this.removeAt(this.indexOfKey(key));
14221 * Returns the number of items in the collection.
14222 * @return {Number} the number of items in the collection.
14224 getCount : function(){
14225 return this.length;
14229 * Returns index within the collection of the passed Object.
14230 * @param {Object} o The item to find the index of.
14231 * @return {Number} index of the item.
14233 indexOf : function(o){
14234 if(!this.items.indexOf){
14235 for(var i = 0, len = this.items.length; i < len; i++){
14236 if(this.items[i] == o) {
14242 return this.items.indexOf(o);
14247 * Returns index within the collection of the passed key.
14248 * @param {String} key The key to find the index of.
14249 * @return {Number} index of the key.
14251 indexOfKey : function(key){
14252 if(!this.keys.indexOf){
14253 for(var i = 0, len = this.keys.length; i < len; i++){
14254 if(this.keys[i] == key) {
14260 return this.keys.indexOf(key);
14265 * Returns the item associated with the passed key OR index. Key has priority over index.
14266 * @param {String/Number} key The key or index of the item.
14267 * @return {Object} The item associated with the passed key.
14269 item : function(key){
14270 if (key === 'length') {
14273 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
14274 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
14278 * Returns the item at the specified index.
14279 * @param {Number} index The index of the item.
14282 itemAt : function(index){
14283 return this.items[index];
14287 * Returns the item associated with the passed key.
14288 * @param {String/Number} key The key of the item.
14289 * @return {Object} The item associated with the passed key.
14291 key : function(key){
14292 return this.map[key];
14296 * Returns true if the collection contains the passed Object as an item.
14297 * @param {Object} o The Object to look for in the collection.
14298 * @return {Boolean} True if the collection contains the Object as an item.
14300 contains : function(o){
14301 return this.indexOf(o) != -1;
14305 * Returns true if the collection contains the passed Object as a key.
14306 * @param {String} key The key to look for in the collection.
14307 * @return {Boolean} True if the collection contains the Object as a key.
14309 containsKey : function(key){
14310 return typeof this.map[key] != "undefined";
14314 * Removes all items from the collection.
14316 clear : function(){
14321 this.fireEvent("clear");
14325 * Returns the first item in the collection.
14326 * @return {Object} the first item in the collection..
14328 first : function(){
14329 return this.items[0];
14333 * Returns the last item in the collection.
14334 * @return {Object} the last item in the collection..
14337 return this.items[this.length-1];
14340 _sort : function(property, dir, fn){
14341 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
14342 fn = fn || function(a, b){
14345 var c = [], k = this.keys, items = this.items;
14346 for(var i = 0, len = items.length; i < len; i++){
14347 c[c.length] = {key: k[i], value: items[i], index: i};
14349 c.sort(function(a, b){
14350 var v = fn(a[property], b[property]) * dsc;
14352 v = (a.index < b.index ? -1 : 1);
14356 for(var i = 0, len = c.length; i < len; i++){
14357 items[i] = c[i].value;
14360 this.fireEvent("sort", this);
14364 * Sorts this collection with the passed comparison function
14365 * @param {String} direction (optional) "ASC" or "DESC"
14366 * @param {Function} fn (optional) comparison function
14368 sort : function(dir, fn){
14369 this._sort("value", dir, fn);
14373 * Sorts this collection by keys
14374 * @param {String} direction (optional) "ASC" or "DESC"
14375 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
14377 keySort : function(dir, fn){
14378 this._sort("key", dir, fn || function(a, b){
14379 return String(a).toUpperCase()-String(b).toUpperCase();
14384 * Returns a range of items in this collection
14385 * @param {Number} startIndex (optional) defaults to 0
14386 * @param {Number} endIndex (optional) default to the last item
14387 * @return {Array} An array of items
14389 getRange : function(start, end){
14390 var items = this.items;
14391 if(items.length < 1){
14394 start = start || 0;
14395 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
14398 for(var i = start; i <= end; i++) {
14399 r[r.length] = items[i];
14402 for(var i = start; i >= end; i--) {
14403 r[r.length] = items[i];
14410 * Filter the <i>objects</i> in this collection by a specific property.
14411 * Returns a new collection that has been filtered.
14412 * @param {String} property A property on your objects
14413 * @param {String/RegExp} value Either string that the property values
14414 * should start with or a RegExp to test against the property
14415 * @return {MixedCollection} The new filtered collection
14417 filter : function(property, value){
14418 if(!value.exec){ // not a regex
14419 value = String(value);
14420 if(value.length == 0){
14421 return this.clone();
14423 value = new RegExp("^" + Roo.escapeRe(value), "i");
14425 return this.filterBy(function(o){
14426 return o && value.test(o[property]);
14431 * Filter by a function. * Returns a new collection that has been filtered.
14432 * The passed function will be called with each
14433 * object in the collection. If the function returns true, the value is included
14434 * otherwise it is filtered.
14435 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
14436 * @param {Object} scope (optional) The scope of the function (defaults to this)
14437 * @return {MixedCollection} The new filtered collection
14439 filterBy : function(fn, scope){
14440 var r = new Roo.util.MixedCollection();
14441 r.getKey = this.getKey;
14442 var k = this.keys, it = this.items;
14443 for(var i = 0, len = it.length; i < len; i++){
14444 if(fn.call(scope||this, it[i], k[i])){
14445 r.add(k[i], it[i]);
14452 * Creates a duplicate of this collection
14453 * @return {MixedCollection}
14455 clone : function(){
14456 var r = new Roo.util.MixedCollection();
14457 var k = this.keys, it = this.items;
14458 for(var i = 0, len = it.length; i < len; i++){
14459 r.add(k[i], it[i]);
14461 r.getKey = this.getKey;
14466 * Returns the item associated with the passed key or index.
14468 * @param {String/Number} key The key or index of the item.
14469 * @return {Object} The item associated with the passed key.
14471 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
14473 * Ext JS Library 1.1.1
14474 * Copyright(c) 2006-2007, Ext JS, LLC.
14476 * Originally Released Under LGPL - original licence link has changed is not relivant.
14479 * <script type="text/javascript">
14482 * @class Roo.util.JSON
14483 * Modified version of Douglas Crockford"s json.js that doesn"t
14484 * mess with the Object prototype
14485 * http://www.json.org/js.html
14488 Roo.util.JSON = new (function(){
14489 var useHasOwn = {}.hasOwnProperty ? true : false;
14491 // crashes Safari in some instances
14492 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
14494 var pad = function(n) {
14495 return n < 10 ? "0" + n : n;
14508 var encodeString = function(s){
14509 if (/["\\\x00-\x1f]/.test(s)) {
14510 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
14515 c = b.charCodeAt();
14517 Math.floor(c / 16).toString(16) +
14518 (c % 16).toString(16);
14521 return '"' + s + '"';
14524 var encodeArray = function(o){
14525 var a = ["["], b, i, l = o.length, v;
14526 for (i = 0; i < l; i += 1) {
14528 switch (typeof v) {
14537 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
14545 var encodeDate = function(o){
14546 return '"' + o.getFullYear() + "-" +
14547 pad(o.getMonth() + 1) + "-" +
14548 pad(o.getDate()) + "T" +
14549 pad(o.getHours()) + ":" +
14550 pad(o.getMinutes()) + ":" +
14551 pad(o.getSeconds()) + '"';
14555 * Encodes an Object, Array or other value
14556 * @param {Mixed} o The variable to encode
14557 * @return {String} The JSON string
14559 this.encode = function(o)
14561 // should this be extended to fully wrap stringify..
14563 if(typeof o == "undefined" || o === null){
14565 }else if(o instanceof Array){
14566 return encodeArray(o);
14567 }else if(o instanceof Date){
14568 return encodeDate(o);
14569 }else if(typeof o == "string"){
14570 return encodeString(o);
14571 }else if(typeof o == "number"){
14572 return isFinite(o) ? String(o) : "null";
14573 }else if(typeof o == "boolean"){
14576 var a = ["{"], b, i, v;
14578 if(!useHasOwn || o.hasOwnProperty(i)) {
14580 switch (typeof v) {
14589 a.push(this.encode(i), ":",
14590 v === null ? "null" : this.encode(v));
14601 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
14602 * @param {String} json The JSON string
14603 * @return {Object} The resulting object
14605 this.decode = function(json){
14607 return /** eval:var:json */ eval("(" + json + ')');
14611 * Shorthand for {@link Roo.util.JSON#encode}
14612 * @member Roo encode
14614 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
14616 * Shorthand for {@link Roo.util.JSON#decode}
14617 * @member Roo decode
14619 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
14622 * Ext JS Library 1.1.1
14623 * Copyright(c) 2006-2007, Ext JS, LLC.
14625 * Originally Released Under LGPL - original licence link has changed is not relivant.
14628 * <script type="text/javascript">
14632 * @class Roo.util.Format
14633 * Reusable data formatting functions
14636 Roo.util.Format = function(){
14637 var trimRe = /^\s+|\s+$/g;
14640 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
14641 * @param {String} value The string to truncate
14642 * @param {Number} length The maximum length to allow before truncating
14643 * @return {String} The converted text
14645 ellipsis : function(value, len){
14646 if(value && value.length > len){
14647 return value.substr(0, len-3)+"...";
14653 * Checks a reference and converts it to empty string if it is undefined
14654 * @param {Mixed} value Reference to check
14655 * @return {Mixed} Empty string if converted, otherwise the original value
14657 undef : function(value){
14658 return typeof value != "undefined" ? value : "";
14662 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
14663 * @param {String} value The string to encode
14664 * @return {String} The encoded text
14666 htmlEncode : function(value){
14667 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
14671 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
14672 * @param {String} value The string to decode
14673 * @return {String} The decoded text
14675 htmlDecode : function(value){
14676 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
14680 * Trims any whitespace from either side of a string
14681 * @param {String} value The text to trim
14682 * @return {String} The trimmed text
14684 trim : function(value){
14685 return String(value).replace(trimRe, "");
14689 * Returns a substring from within an original string
14690 * @param {String} value The original text
14691 * @param {Number} start The start index of the substring
14692 * @param {Number} length The length of the substring
14693 * @return {String} The substring
14695 substr : function(value, start, length){
14696 return String(value).substr(start, length);
14700 * Converts a string to all lower case letters
14701 * @param {String} value The text to convert
14702 * @return {String} The converted text
14704 lowercase : function(value){
14705 return String(value).toLowerCase();
14709 * Converts a string to all upper case letters
14710 * @param {String} value The text to convert
14711 * @return {String} The converted text
14713 uppercase : function(value){
14714 return String(value).toUpperCase();
14718 * Converts the first character only of a string to upper case
14719 * @param {String} value The text to convert
14720 * @return {String} The converted text
14722 capitalize : function(value){
14723 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
14727 call : function(value, fn){
14728 if(arguments.length > 2){
14729 var args = Array.prototype.slice.call(arguments, 2);
14730 args.unshift(value);
14732 return /** eval:var:value */ eval(fn).apply(window, args);
14734 /** eval:var:value */
14735 return /** eval:var:value */ eval(fn).call(window, value);
14741 * safer version of Math.toFixed..??/
14742 * @param {Number/String} value The numeric value to format
14743 * @param {Number/String} value Decimal places
14744 * @return {String} The formatted currency string
14746 toFixed : function(v, n)
14748 // why not use to fixed - precision is buggered???
14750 return Math.round(v-0);
14752 var fact = Math.pow(10,n+1);
14753 v = (Math.round((v-0)*fact))/fact;
14754 var z = (''+fact).substring(2);
14755 if (v == Math.floor(v)) {
14756 return Math.floor(v) + '.' + z;
14759 // now just padd decimals..
14760 var ps = String(v).split('.');
14761 var fd = (ps[1] + z);
14762 var r = fd.substring(0,n);
14763 var rm = fd.substring(n);
14765 return ps[0] + '.' + r;
14767 r*=1; // turn it into a number;
14769 if (String(r).length != n) {
14772 r = String(r).substring(1); // chop the end off.
14775 return ps[0] + '.' + r;
14780 * Format a number as US currency
14781 * @param {Number/String} value The numeric value to format
14782 * @return {String} The formatted currency string
14784 usMoney : function(v){
14785 return '$' + Roo.util.Format.number(v);
14790 * eventually this should probably emulate php's number_format
14791 * @param {Number/String} value The numeric value to format
14792 * @param {Number} decimals number of decimal places
14793 * @param {String} delimiter for thousands (default comma)
14794 * @return {String} The formatted currency string
14796 number : function(v, decimals, thousandsDelimiter)
14798 // multiply and round.
14799 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
14800 thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
14802 var mul = Math.pow(10, decimals);
14803 var zero = String(mul).substring(1);
14804 v = (Math.round((v-0)*mul))/mul;
14806 // if it's '0' number.. then
14808 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
14810 var ps = v.split('.');
14813 var r = /(\d+)(\d{3})/;
14816 if(thousandsDelimiter.length != 0) {
14817 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
14822 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
14823 // does not have decimals
14824 (decimals ? ('.' + zero) : '');
14827 return whole + sub ;
14831 * Parse a value into a formatted date using the specified format pattern.
14832 * @param {Mixed} value The value to format
14833 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
14834 * @return {String} The formatted date string
14836 date : function(v, format){
14840 if(!(v instanceof Date)){
14841 v = new Date(Date.parse(v));
14843 return v.dateFormat(format || Roo.util.Format.defaults.date);
14847 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
14848 * @param {String} format Any valid date format string
14849 * @return {Function} The date formatting function
14851 dateRenderer : function(format){
14852 return function(v){
14853 return Roo.util.Format.date(v, format);
14858 stripTagsRE : /<\/?[^>]+>/gi,
14861 * Strips all HTML tags
14862 * @param {Mixed} value The text from which to strip tags
14863 * @return {String} The stripped text
14865 stripTags : function(v){
14866 return !v ? v : String(v).replace(this.stripTagsRE, "");
14870 * Size in Mb,Gb etc.
14871 * @param {Number} value The number to be formated
14872 * @param {number} decimals how many decimal places
14873 * @return {String} the formated string
14875 size : function(value, decimals)
14877 var sizes = ['b', 'k', 'M', 'G', 'T'];
14881 var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
14882 return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals) + sizes[i];
14889 Roo.util.Format.defaults = {
14893 * Ext JS Library 1.1.1
14894 * Copyright(c) 2006-2007, Ext JS, LLC.
14896 * Originally Released Under LGPL - original licence link has changed is not relivant.
14899 * <script type="text/javascript">
14906 * @class Roo.MasterTemplate
14907 * @extends Roo.Template
14908 * Provides a template that can have child templates. The syntax is:
14910 var t = new Roo.MasterTemplate(
14911 '<select name="{name}">',
14912 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
14915 t.add('options', {value: 'foo', text: 'bar'});
14916 // or you can add multiple child elements in one shot
14917 t.addAll('options', [
14918 {value: 'foo', text: 'bar'},
14919 {value: 'foo2', text: 'bar2'},
14920 {value: 'foo3', text: 'bar3'}
14922 // then append, applying the master template values
14923 t.append('my-form', {name: 'my-select'});
14925 * A name attribute for the child template is not required if you have only one child
14926 * template or you want to refer to them by index.
14928 Roo.MasterTemplate = function(){
14929 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
14930 this.originalHtml = this.html;
14932 var m, re = this.subTemplateRe;
14935 while(m = re.exec(this.html)){
14936 var name = m[1], content = m[2];
14941 tpl : new Roo.Template(content)
14944 st[name] = st[subIndex];
14946 st[subIndex].tpl.compile();
14947 st[subIndex].tpl.call = this.call.createDelegate(this);
14950 this.subCount = subIndex;
14953 Roo.extend(Roo.MasterTemplate, Roo.Template, {
14955 * The regular expression used to match sub templates
14959 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
14962 * Applies the passed values to a child template.
14963 * @param {String/Number} name (optional) The name or index of the child template
14964 * @param {Array/Object} values The values to be applied to the template
14965 * @return {MasterTemplate} this
14967 add : function(name, values){
14968 if(arguments.length == 1){
14969 values = arguments[0];
14972 var s = this.subs[name];
14973 s.buffer[s.buffer.length] = s.tpl.apply(values);
14978 * Applies all the passed values to a child template.
14979 * @param {String/Number} name (optional) The name or index of the child template
14980 * @param {Array} values The values to be applied to the template, this should be an array of objects.
14981 * @param {Boolean} reset (optional) True to reset the template first
14982 * @return {MasterTemplate} this
14984 fill : function(name, values, reset){
14986 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
14994 for(var i = 0, len = values.length; i < len; i++){
14995 this.add(name, values[i]);
15001 * Resets the template for reuse
15002 * @return {MasterTemplate} this
15004 reset : function(){
15006 for(var i = 0; i < this.subCount; i++){
15012 applyTemplate : function(values){
15014 var replaceIndex = -1;
15015 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
15016 return s[++replaceIndex].buffer.join("");
15018 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
15021 apply : function(){
15022 return this.applyTemplate.apply(this, arguments);
15025 compile : function(){return this;}
15029 * Alias for fill().
15032 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
15034 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
15035 * var tpl = Roo.MasterTemplate.from('element-id');
15036 * @param {String/HTMLElement} el
15037 * @param {Object} config
15040 Roo.MasterTemplate.from = function(el, config){
15041 el = Roo.getDom(el);
15042 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
15045 * Ext JS Library 1.1.1
15046 * Copyright(c) 2006-2007, Ext JS, LLC.
15048 * Originally Released Under LGPL - original licence link has changed is not relivant.
15051 * <script type="text/javascript">
15056 * @class Roo.util.CSS
15057 * Utility class for manipulating CSS rules
15061 Roo.util.CSS = function(){
15063 var doc = document;
15065 var camelRe = /(-[a-z])/gi;
15066 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
15070 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
15071 * tag and appended to the HEAD of the document.
15072 * @param {String|Object} cssText The text containing the css rules
15073 * @param {String} id An id to add to the stylesheet for later removal
15074 * @return {StyleSheet}
15076 createStyleSheet : function(cssText, id){
15078 var head = doc.getElementsByTagName("head")[0];
15079 var nrules = doc.createElement("style");
15080 nrules.setAttribute("type", "text/css");
15082 nrules.setAttribute("id", id);
15084 if (typeof(cssText) != 'string') {
15085 // support object maps..
15086 // not sure if this a good idea..
15087 // perhaps it should be merged with the general css handling
15088 // and handle js style props.
15089 var cssTextNew = [];
15090 for(var n in cssText) {
15092 for(var k in cssText[n]) {
15093 citems.push( k + ' : ' +cssText[n][k] + ';' );
15095 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
15098 cssText = cssTextNew.join("\n");
15104 head.appendChild(nrules);
15105 ss = nrules.styleSheet;
15106 ss.cssText = cssText;
15109 nrules.appendChild(doc.createTextNode(cssText));
15111 nrules.cssText = cssText;
15113 head.appendChild(nrules);
15114 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
15116 this.cacheStyleSheet(ss);
15121 * Removes a style or link tag by id
15122 * @param {String} id The id of the tag
15124 removeStyleSheet : function(id){
15125 var existing = doc.getElementById(id);
15127 existing.parentNode.removeChild(existing);
15132 * Dynamically swaps an existing stylesheet reference for a new one
15133 * @param {String} id The id of an existing link tag to remove
15134 * @param {String} url The href of the new stylesheet to include
15136 swapStyleSheet : function(id, url){
15137 this.removeStyleSheet(id);
15138 var ss = doc.createElement("link");
15139 ss.setAttribute("rel", "stylesheet");
15140 ss.setAttribute("type", "text/css");
15141 ss.setAttribute("id", id);
15142 ss.setAttribute("href", url);
15143 doc.getElementsByTagName("head")[0].appendChild(ss);
15147 * Refresh the rule cache if you have dynamically added stylesheets
15148 * @return {Object} An object (hash) of rules indexed by selector
15150 refreshCache : function(){
15151 return this.getRules(true);
15155 cacheStyleSheet : function(stylesheet){
15159 try{// try catch for cross domain access issue
15160 var ssRules = stylesheet.cssRules || stylesheet.rules;
15161 for(var j = ssRules.length-1; j >= 0; --j){
15162 rules[ssRules[j].selectorText] = ssRules[j];
15168 * Gets all css rules for the document
15169 * @param {Boolean} refreshCache true to refresh the internal cache
15170 * @return {Object} An object (hash) of rules indexed by selector
15172 getRules : function(refreshCache){
15173 if(rules == null || refreshCache){
15175 var ds = doc.styleSheets;
15176 for(var i =0, len = ds.length; i < len; i++){
15178 this.cacheStyleSheet(ds[i]);
15186 * Gets an an individual CSS rule by selector(s)
15187 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
15188 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
15189 * @return {CSSRule} The CSS rule or null if one is not found
15191 getRule : function(selector, refreshCache){
15192 var rs = this.getRules(refreshCache);
15193 if(!(selector instanceof Array)){
15194 return rs[selector];
15196 for(var i = 0; i < selector.length; i++){
15197 if(rs[selector[i]]){
15198 return rs[selector[i]];
15206 * Updates a rule property
15207 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
15208 * @param {String} property The css property
15209 * @param {String} value The new value for the property
15210 * @return {Boolean} true If a rule was found and updated
15212 updateRule : function(selector, property, value){
15213 if(!(selector instanceof Array)){
15214 var rule = this.getRule(selector);
15216 rule.style[property.replace(camelRe, camelFn)] = value;
15220 for(var i = 0; i < selector.length; i++){
15221 if(this.updateRule(selector[i], property, value)){
15231 * Ext JS Library 1.1.1
15232 * Copyright(c) 2006-2007, Ext JS, LLC.
15234 * Originally Released Under LGPL - original licence link has changed is not relivant.
15237 * <script type="text/javascript">
15243 * @class Roo.util.ClickRepeater
15244 * @extends Roo.util.Observable
15246 * A wrapper class which can be applied to any element. Fires a "click" event while the
15247 * mouse is pressed. The interval between firings may be specified in the config but
15248 * defaults to 10 milliseconds.
15250 * Optionally, a CSS class may be applied to the element during the time it is pressed.
15252 * @cfg {String/HTMLElement/Element} el The element to act as a button.
15253 * @cfg {Number} delay The initial delay before the repeating event begins firing.
15254 * Similar to an autorepeat key delay.
15255 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
15256 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
15257 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
15258 * "interval" and "delay" are ignored. "immediate" is honored.
15259 * @cfg {Boolean} preventDefault True to prevent the default click event
15260 * @cfg {Boolean} stopDefault True to stop the default click event
15263 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
15264 * 2007-02-02 jvs Renamed to ClickRepeater
15265 * 2007-02-03 jvs Modifications for FF Mac and Safari
15268 * @param {String/HTMLElement/Element} el The element to listen on
15269 * @param {Object} config
15271 Roo.util.ClickRepeater = function(el, config)
15273 this.el = Roo.get(el);
15274 this.el.unselectable();
15276 Roo.apply(this, config);
15281 * Fires when the mouse button is depressed.
15282 * @param {Roo.util.ClickRepeater} this
15284 "mousedown" : true,
15287 * Fires on a specified interval during the time the element is pressed.
15288 * @param {Roo.util.ClickRepeater} this
15293 * Fires when the mouse key is released.
15294 * @param {Roo.util.ClickRepeater} this
15299 this.el.on("mousedown", this.handleMouseDown, this);
15300 if(this.preventDefault || this.stopDefault){
15301 this.el.on("click", function(e){
15302 if(this.preventDefault){
15303 e.preventDefault();
15305 if(this.stopDefault){
15311 // allow inline handler
15313 this.on("click", this.handler, this.scope || this);
15316 Roo.util.ClickRepeater.superclass.constructor.call(this);
15319 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
15322 preventDefault : true,
15323 stopDefault : false,
15327 handleMouseDown : function(){
15328 clearTimeout(this.timer);
15330 if(this.pressClass){
15331 this.el.addClass(this.pressClass);
15333 this.mousedownTime = new Date();
15335 Roo.get(document).on("mouseup", this.handleMouseUp, this);
15336 this.el.on("mouseout", this.handleMouseOut, this);
15338 this.fireEvent("mousedown", this);
15339 this.fireEvent("click", this);
15341 this.timer = this.click.defer(this.delay || this.interval, this);
15345 click : function(){
15346 this.fireEvent("click", this);
15347 this.timer = this.click.defer(this.getInterval(), this);
15351 getInterval: function(){
15352 if(!this.accelerate){
15353 return this.interval;
15355 var pressTime = this.mousedownTime.getElapsed();
15356 if(pressTime < 500){
15358 }else if(pressTime < 1700){
15360 }else if(pressTime < 2600){
15362 }else if(pressTime < 3500){
15364 }else if(pressTime < 4400){
15366 }else if(pressTime < 5300){
15368 }else if(pressTime < 6200){
15376 handleMouseOut : function(){
15377 clearTimeout(this.timer);
15378 if(this.pressClass){
15379 this.el.removeClass(this.pressClass);
15381 this.el.on("mouseover", this.handleMouseReturn, this);
15385 handleMouseReturn : function(){
15386 this.el.un("mouseover", this.handleMouseReturn);
15387 if(this.pressClass){
15388 this.el.addClass(this.pressClass);
15394 handleMouseUp : function(){
15395 clearTimeout(this.timer);
15396 this.el.un("mouseover", this.handleMouseReturn);
15397 this.el.un("mouseout", this.handleMouseOut);
15398 Roo.get(document).un("mouseup", this.handleMouseUp);
15399 this.el.removeClass(this.pressClass);
15400 this.fireEvent("mouseup", this);
15403 * @class Roo.util.Clipboard
15409 Roo.util.Clipboard = {
15411 * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
15412 * @param {String} text to copy to clipboard
15414 write : function(text) {
15415 // navigator clipboard api needs a secure context (https)
15416 if (navigator.clipboard && window.isSecureContext) {
15417 // navigator clipboard api method'
15418 navigator.clipboard.writeText(text);
15421 // text area method
15422 var ta = document.createElement("textarea");
15424 // make the textarea out of viewport
15425 ta.style.position = "fixed";
15426 ta.style.left = "-999999px";
15427 ta.style.top = "-999999px";
15428 document.body.appendChild(ta);
15431 document.execCommand('copy');
15441 * Ext JS Library 1.1.1
15442 * Copyright(c) 2006-2007, Ext JS, LLC.
15444 * Originally Released Under LGPL - original licence link has changed is not relivant.
15447 * <script type="text/javascript">
15452 * @class Roo.KeyNav
15453 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
15454 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
15455 * way to implement custom navigation schemes for any UI component.</p>
15456 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
15457 * pageUp, pageDown, del, home, end. Usage:</p>
15459 var nav = new Roo.KeyNav("my-element", {
15460 "left" : function(e){
15461 this.moveLeft(e.ctrlKey);
15463 "right" : function(e){
15464 this.moveRight(e.ctrlKey);
15466 "enter" : function(e){
15473 * @param {String/HTMLElement/Roo.Element} el The element to bind to
15474 * @param {Object} config The config
15476 Roo.KeyNav = function(el, config){
15477 this.el = Roo.get(el);
15478 Roo.apply(this, config);
15479 if(!this.disabled){
15480 this.disabled = true;
15485 Roo.KeyNav.prototype = {
15487 * @cfg {Boolean} disabled
15488 * True to disable this KeyNav instance (defaults to false)
15492 * @cfg {String} defaultEventAction
15493 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
15494 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
15495 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
15497 defaultEventAction: "stopEvent",
15499 * @cfg {Boolean} forceKeyDown
15500 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
15501 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
15502 * handle keydown instead of keypress.
15504 forceKeyDown : false,
15507 prepareEvent : function(e){
15508 var k = e.getKey();
15509 var h = this.keyToHandler[k];
15510 //if(h && this[h]){
15511 // e.stopPropagation();
15513 if(Roo.isSafari && h && k >= 37 && k <= 40){
15519 relay : function(e){
15520 var k = e.getKey();
15521 var h = this.keyToHandler[k];
15523 if(this.doRelay(e, this[h], h) !== true){
15524 e[this.defaultEventAction]();
15530 doRelay : function(e, h, hname){
15531 return h.call(this.scope || this, e);
15534 // possible handlers
15548 // quick lookup hash
15565 * Enable this KeyNav
15567 enable: function(){
15569 // ie won't do special keys on keypress, no one else will repeat keys with keydown
15570 // the EventObject will normalize Safari automatically
15571 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15572 this.el.on("keydown", this.relay, this);
15574 this.el.on("keydown", this.prepareEvent, this);
15575 this.el.on("keypress", this.relay, this);
15577 this.disabled = false;
15582 * Disable this KeyNav
15584 disable: function(){
15585 if(!this.disabled){
15586 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15587 this.el.un("keydown", this.relay);
15589 this.el.un("keydown", this.prepareEvent);
15590 this.el.un("keypress", this.relay);
15592 this.disabled = true;
15597 * Ext JS Library 1.1.1
15598 * Copyright(c) 2006-2007, Ext JS, LLC.
15600 * Originally Released Under LGPL - original licence link has changed is not relivant.
15603 * <script type="text/javascript">
15608 * @class Roo.KeyMap
15609 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
15610 * The constructor accepts the same config object as defined by {@link #addBinding}.
15611 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
15612 * combination it will call the function with this signature (if the match is a multi-key
15613 * combination the callback will still be called only once): (String key, Roo.EventObject e)
15614 * A KeyMap can also handle a string representation of keys.<br />
15617 // map one key by key code
15618 var map = new Roo.KeyMap("my-element", {
15619 key: 13, // or Roo.EventObject.ENTER
15624 // map multiple keys to one action by string
15625 var map = new Roo.KeyMap("my-element", {
15631 // map multiple keys to multiple actions by strings and array of codes
15632 var map = new Roo.KeyMap("my-element", [
15635 fn: function(){ alert("Return was pressed"); }
15638 fn: function(){ alert('a, b or c was pressed'); }
15643 fn: function(){ alert('Control + shift + tab was pressed.'); }
15647 * <b>Note: A KeyMap starts enabled</b>
15649 * @param {String/HTMLElement/Roo.Element} el The element to bind to
15650 * @param {Object} config The config (see {@link #addBinding})
15651 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
15653 Roo.KeyMap = function(el, config, eventName){
15654 this.el = Roo.get(el);
15655 this.eventName = eventName || "keydown";
15656 this.bindings = [];
15658 this.addBinding(config);
15663 Roo.KeyMap.prototype = {
15665 * True to stop the event from bubbling and prevent the default browser action if the
15666 * key was handled by the KeyMap (defaults to false)
15672 * Add a new binding to this KeyMap. The following config object properties are supported:
15674 Property Type Description
15675 ---------- --------------- ----------------------------------------------------------------------
15676 key String/Array A single keycode or an array of keycodes to handle
15677 shift Boolean True to handle key only when shift is pressed (defaults to false)
15678 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
15679 alt Boolean True to handle key only when alt is pressed (defaults to false)
15680 fn Function The function to call when KeyMap finds the expected key combination
15681 scope Object The scope of the callback function
15687 var map = new Roo.KeyMap(document, {
15688 key: Roo.EventObject.ENTER,
15693 //Add a new binding to the existing KeyMap later
15701 * @param {Object/Array} config A single KeyMap config or an array of configs
15703 addBinding : function(config){
15704 if(config instanceof Array){
15705 for(var i = 0, len = config.length; i < len; i++){
15706 this.addBinding(config[i]);
15710 var keyCode = config.key,
15711 shift = config.shift,
15712 ctrl = config.ctrl,
15715 scope = config.scope;
15716 if(typeof keyCode == "string"){
15718 var keyString = keyCode.toUpperCase();
15719 for(var j = 0, len = keyString.length; j < len; j++){
15720 ks.push(keyString.charCodeAt(j));
15724 var keyArray = keyCode instanceof Array;
15725 var handler = function(e){
15726 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
15727 var k = e.getKey();
15729 for(var i = 0, len = keyCode.length; i < len; i++){
15730 if(keyCode[i] == k){
15731 if(this.stopEvent){
15734 fn.call(scope || window, k, e);
15740 if(this.stopEvent){
15743 fn.call(scope || window, k, e);
15748 this.bindings.push(handler);
15752 * Shorthand for adding a single key listener
15753 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
15754 * following options:
15755 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
15756 * @param {Function} fn The function to call
15757 * @param {Object} scope (optional) The scope of the function
15759 on : function(key, fn, scope){
15760 var keyCode, shift, ctrl, alt;
15761 if(typeof key == "object" && !(key instanceof Array)){
15780 handleKeyDown : function(e){
15781 if(this.enabled){ //just in case
15782 var b = this.bindings;
15783 for(var i = 0, len = b.length; i < len; i++){
15784 b[i].call(this, e);
15790 * Returns true if this KeyMap is enabled
15791 * @return {Boolean}
15793 isEnabled : function(){
15794 return this.enabled;
15798 * Enables this KeyMap
15800 enable: function(){
15802 this.el.on(this.eventName, this.handleKeyDown, this);
15803 this.enabled = true;
15808 * Disable this KeyMap
15810 disable: function(){
15812 this.el.removeListener(this.eventName, this.handleKeyDown, this);
15813 this.enabled = false;
15818 * Ext JS Library 1.1.1
15819 * Copyright(c) 2006-2007, Ext JS, LLC.
15821 * Originally Released Under LGPL - original licence link has changed is not relivant.
15824 * <script type="text/javascript">
15829 * @class Roo.util.TextMetrics
15830 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
15831 * wide, in pixels, a given block of text will be.
15834 Roo.util.TextMetrics = function(){
15838 * Measures the size of the specified text
15839 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
15840 * that can affect the size of the rendered text
15841 * @param {String} text The text to measure
15842 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15843 * in order to accurately measure the text height
15844 * @return {Object} An object containing the text's size {width: (width), height: (height)}
15846 measure : function(el, text, fixedWidth){
15848 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
15851 shared.setFixedWidth(fixedWidth || 'auto');
15852 return shared.getSize(text);
15856 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
15857 * the overhead of multiple calls to initialize the style properties on each measurement.
15858 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
15859 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15860 * in order to accurately measure the text height
15861 * @return {Roo.util.TextMetrics.Instance} instance The new instance
15863 createInstance : function(el, fixedWidth){
15864 return Roo.util.TextMetrics.Instance(el, fixedWidth);
15870 * @class Roo.util.TextMetrics.Instance
15871 * Instance of TextMetrics Calcuation
15873 * Create a new TextMetrics Instance
15874 * @param {Object} bindto
15875 * @param {Boolean} fixedWidth
15878 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth)
15880 var ml = new Roo.Element(document.createElement('div'));
15881 document.body.appendChild(ml.dom);
15882 ml.position('absolute');
15883 ml.setLeftTop(-1000, -1000);
15887 ml.setWidth(fixedWidth);
15892 * Returns the size of the specified text based on the internal element's style and width properties
15893 * @param {String} text The text to measure
15894 * @return {Object} An object containing the text's size {width: (width), height: (height)}
15896 getSize : function(text){
15898 var s = ml.getSize();
15904 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
15905 * that can affect the size of the rendered text
15906 * @param {String/HTMLElement} el The element, dom node or id
15908 bind : function(el){
15910 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
15915 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
15916 * to set a fixed width in order to accurately measure the text height.
15917 * @param {Number} width The width to set on the element
15919 setFixedWidth : function(width){
15920 ml.setWidth(width);
15924 * Returns the measured width of the specified text
15925 * @param {String} text The text to measure
15926 * @return {Number} width The width in pixels
15928 getWidth : function(text){
15929 ml.dom.style.width = 'auto';
15930 return this.getSize(text).width;
15934 * Returns the measured height of the specified text. For multiline text, be sure to call
15935 * {@link #setFixedWidth} if necessary.
15936 * @param {String} text The text to measure
15937 * @return {Number} height The height in pixels
15939 getHeight : function(text){
15940 return this.getSize(text).height;
15944 instance.bind(bindTo);
15949 // backwards compat
15950 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
15952 * Ext JS Library 1.1.1
15953 * Copyright(c) 2006-2007, Ext JS, LLC.
15955 * Originally Released Under LGPL - original licence link has changed is not relivant.
15958 * <script type="text/javascript">
15962 * @class Roo.state.Provider
15963 * Abstract base class for state provider implementations. This class provides methods
15964 * for encoding and decoding <b>typed</b> variables including dates and defines the
15965 * Provider interface.
15967 Roo.state.Provider = function(){
15969 * @event statechange
15970 * Fires when a state change occurs.
15971 * @param {Provider} this This state provider
15972 * @param {String} key The state key which was changed
15973 * @param {String} value The encoded value for the state
15976 "statechange": true
15979 Roo.state.Provider.superclass.constructor.call(this);
15981 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
15983 * Returns the current value for a key
15984 * @param {String} name The key name
15985 * @param {Mixed} defaultValue A default value to return if the key's value is not found
15986 * @return {Mixed} The state data
15988 get : function(name, defaultValue){
15989 return typeof this.state[name] == "undefined" ?
15990 defaultValue : this.state[name];
15994 * Clears a value from the state
15995 * @param {String} name The key name
15997 clear : function(name){
15998 delete this.state[name];
15999 this.fireEvent("statechange", this, name, null);
16003 * Sets the value for a key
16004 * @param {String} name The key name
16005 * @param {Mixed} value The value to set
16007 set : function(name, value){
16008 this.state[name] = value;
16009 this.fireEvent("statechange", this, name, value);
16013 * Decodes a string previously encoded with {@link #encodeValue}.
16014 * @param {String} value The value to decode
16015 * @return {Mixed} The decoded value
16017 decodeValue : function(cookie){
16018 var re = /^(a|n|d|b|s|o)\:(.*)$/;
16019 var matches = re.exec(unescape(cookie));
16020 if(!matches || !matches[1]) {
16021 return; // non state cookie
16023 var type = matches[1];
16024 var v = matches[2];
16027 return parseFloat(v);
16029 return new Date(Date.parse(v));
16034 var values = v.split("^");
16035 for(var i = 0, len = values.length; i < len; i++){
16036 all.push(this.decodeValue(values[i]));
16041 var values = v.split("^");
16042 for(var i = 0, len = values.length; i < len; i++){
16043 var kv = values[i].split("=");
16044 all[kv[0]] = this.decodeValue(kv[1]);
16053 * Encodes a value including type information. Decode with {@link #decodeValue}.
16054 * @param {Mixed} value The value to encode
16055 * @return {String} The encoded value
16057 encodeValue : function(v){
16059 if(typeof v == "number"){
16061 }else if(typeof v == "boolean"){
16062 enc = "b:" + (v ? "1" : "0");
16063 }else if(v instanceof Date){
16064 enc = "d:" + v.toGMTString();
16065 }else if(v instanceof Array){
16067 for(var i = 0, len = v.length; i < len; i++){
16068 flat += this.encodeValue(v[i]);
16074 }else if(typeof v == "object"){
16077 if(typeof v[key] != "function"){
16078 flat += key + "=" + this.encodeValue(v[key]) + "^";
16081 enc = "o:" + flat.substring(0, flat.length-1);
16085 return escape(enc);
16091 * Ext JS Library 1.1.1
16092 * Copyright(c) 2006-2007, Ext JS, LLC.
16094 * Originally Released Under LGPL - original licence link has changed is not relivant.
16097 * <script type="text/javascript">
16100 * @class Roo.state.Manager
16101 * This is the global state manager. By default all components that are "state aware" check this class
16102 * for state information if you don't pass them a custom state provider. In order for this class
16103 * to be useful, it must be initialized with a provider when your application initializes.
16105 // in your initialization function
16107 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
16109 // supposed you have a {@link Roo.BorderLayout}
16110 var layout = new Roo.BorderLayout(...);
16111 layout.restoreState();
16112 // or a {Roo.BasicDialog}
16113 var dialog = new Roo.BasicDialog(...);
16114 dialog.restoreState();
16118 Roo.state.Manager = function(){
16119 var provider = new Roo.state.Provider();
16123 * Configures the default state provider for your application
16124 * @param {Provider} stateProvider The state provider to set
16126 setProvider : function(stateProvider){
16127 provider = stateProvider;
16131 * Returns the current value for a key
16132 * @param {String} name The key name
16133 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
16134 * @return {Mixed} The state data
16136 get : function(key, defaultValue){
16137 return provider.get(key, defaultValue);
16141 * Sets the value for a key
16142 * @param {String} name The key name
16143 * @param {Mixed} value The state data
16145 set : function(key, value){
16146 provider.set(key, value);
16150 * Clears a value from the state
16151 * @param {String} name The key name
16153 clear : function(key){
16154 provider.clear(key);
16158 * Gets the currently configured state provider
16159 * @return {Provider} The state provider
16161 getProvider : function(){
16168 * Ext JS Library 1.1.1
16169 * Copyright(c) 2006-2007, Ext JS, LLC.
16171 * Originally Released Under LGPL - original licence link has changed is not relivant.
16174 * <script type="text/javascript">
16177 * @class Roo.state.CookieProvider
16178 * @extends Roo.state.Provider
16179 * The default Provider implementation which saves state via cookies.
16182 var cp = new Roo.state.CookieProvider({
16184 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
16185 domain: "roojs.com"
16187 Roo.state.Manager.setProvider(cp);
16189 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
16190 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
16191 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
16192 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
16193 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
16194 * domain the page is running on including the 'www' like 'www.roojs.com')
16195 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
16197 * Create a new CookieProvider
16198 * @param {Object} config The configuration object
16200 Roo.state.CookieProvider = function(config){
16201 Roo.state.CookieProvider.superclass.constructor.call(this);
16203 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
16204 this.domain = null;
16205 this.secure = false;
16206 Roo.apply(this, config);
16207 this.state = this.readCookies();
16210 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
16212 set : function(name, value){
16213 if(typeof value == "undefined" || value === null){
16217 this.setCookie(name, value);
16218 Roo.state.CookieProvider.superclass.set.call(this, name, value);
16222 clear : function(name){
16223 this.clearCookie(name);
16224 Roo.state.CookieProvider.superclass.clear.call(this, name);
16228 readCookies : function(){
16230 var c = document.cookie + ";";
16231 var re = /\s?(.*?)=(.*?);/g;
16233 while((matches = re.exec(c)) != null){
16234 var name = matches[1];
16235 var value = matches[2];
16236 if(name && name.substring(0,3) == "ys-"){
16237 cookies[name.substr(3)] = this.decodeValue(value);
16244 setCookie : function(name, value){
16245 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
16246 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
16247 ((this.path == null) ? "" : ("; path=" + this.path)) +
16248 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16249 ((this.secure == true) ? "; secure" : "");
16253 clearCookie : function(name){
16254 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
16255 ((this.path == null) ? "" : ("; path=" + this.path)) +
16256 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16257 ((this.secure == true) ? "; secure" : "");
16261 * Ext JS Library 1.1.1
16262 * Copyright(c) 2006-2007, Ext JS, LLC.
16264 * Originally Released Under LGPL - original licence link has changed is not relivant.
16267 * <script type="text/javascript">
16272 * @class Roo.ComponentMgr
16273 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
16276 Roo.ComponentMgr = function(){
16277 var all = new Roo.util.MixedCollection();
16281 * Registers a component.
16282 * @param {Roo.Component} c The component
16284 register : function(c){
16289 * Unregisters a component.
16290 * @param {Roo.Component} c The component
16292 unregister : function(c){
16297 * Returns a component by id
16298 * @param {String} id The component id
16300 get : function(id){
16301 return all.get(id);
16305 * Registers a function that will be called when a specified component is added to ComponentMgr
16306 * @param {String} id The component id
16307 * @param {Funtction} fn The callback function
16308 * @param {Object} scope The scope of the callback
16310 onAvailable : function(id, fn, scope){
16311 all.on("add", function(index, o){
16313 fn.call(scope || o, o);
16314 all.un("add", fn, scope);
16321 * Ext JS Library 1.1.1
16322 * Copyright(c) 2006-2007, Ext JS, LLC.
16324 * Originally Released Under LGPL - original licence link has changed is not relivant.
16327 * <script type="text/javascript">
16331 * @class Roo.Component
16332 * @extends Roo.util.Observable
16333 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
16334 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
16335 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
16336 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
16337 * All visual components (widgets) that require rendering into a layout should subclass Component.
16339 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
16340 * 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
16341 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
16343 Roo.Component = function(config){
16344 config = config || {};
16345 if(config.tagName || config.dom || typeof config == "string"){ // element object
16346 config = {el: config, id: config.id || config};
16348 this.initialConfig = config;
16350 Roo.apply(this, config);
16354 * Fires after the component is disabled.
16355 * @param {Roo.Component} this
16360 * Fires after the component is enabled.
16361 * @param {Roo.Component} this
16365 * @event beforeshow
16366 * Fires before the component is shown. Return false to stop the show.
16367 * @param {Roo.Component} this
16372 * Fires after the component is shown.
16373 * @param {Roo.Component} this
16377 * @event beforehide
16378 * Fires before the component is hidden. Return false to stop the hide.
16379 * @param {Roo.Component} this
16384 * Fires after the component is hidden.
16385 * @param {Roo.Component} this
16389 * @event beforerender
16390 * Fires before the component is rendered. Return false to stop the render.
16391 * @param {Roo.Component} this
16393 beforerender : true,
16396 * Fires after the component is rendered.
16397 * @param {Roo.Component} this
16401 * @event beforedestroy
16402 * Fires before the component is destroyed. Return false to stop the destroy.
16403 * @param {Roo.Component} this
16405 beforedestroy : true,
16408 * Fires after the component is destroyed.
16409 * @param {Roo.Component} this
16414 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
16416 Roo.ComponentMgr.register(this);
16417 Roo.Component.superclass.constructor.call(this);
16418 this.initComponent();
16419 if(this.renderTo){ // not supported by all components yet. use at your own risk!
16420 this.render(this.renderTo);
16421 delete this.renderTo;
16426 Roo.Component.AUTO_ID = 1000;
16428 Roo.extend(Roo.Component, Roo.util.Observable, {
16430 * @scope Roo.Component.prototype
16432 * true if this component is hidden. Read-only.
16437 * true if this component is disabled. Read-only.
16442 * true if this component has been rendered. Read-only.
16446 /** @cfg {String} disableClass
16447 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
16449 disabledClass : "x-item-disabled",
16450 /** @cfg {Boolean} allowDomMove
16451 * Whether the component can move the Dom node when rendering (defaults to true).
16453 allowDomMove : true,
16454 /** @cfg {String} hideMode (display|visibility)
16455 * How this component should hidden. Supported values are
16456 * "visibility" (css visibility), "offsets" (negative offset position) and
16457 * "display" (css display) - defaults to "display".
16459 hideMode: 'display',
16462 ctype : "Roo.Component",
16465 * @cfg {String} actionMode
16466 * which property holds the element that used for hide() / show() / disable() / enable()
16467 * default is 'el' for forms you probably want to set this to fieldEl
16472 getActionEl : function(){
16473 return this[this.actionMode];
16476 initComponent : Roo.emptyFn,
16478 * If this is a lazy rendering component, render it to its container element.
16479 * @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.
16481 render : function(container, position){
16487 if(this.fireEvent("beforerender", this) === false){
16491 if(!container && this.el){
16492 this.el = Roo.get(this.el);
16493 container = this.el.dom.parentNode;
16494 this.allowDomMove = false;
16496 this.container = Roo.get(container);
16497 this.rendered = true;
16498 if(position !== undefined){
16499 if(typeof position == 'number'){
16500 position = this.container.dom.childNodes[position];
16502 position = Roo.getDom(position);
16505 this.onRender(this.container, position || null);
16507 this.el.addClass(this.cls);
16511 this.el.applyStyles(this.style);
16514 this.fireEvent("render", this);
16515 this.afterRender(this.container);
16528 // default function is not really useful
16529 onRender : function(ct, position){
16531 this.el = Roo.get(this.el);
16532 if(this.allowDomMove !== false){
16533 ct.dom.insertBefore(this.el.dom, position);
16539 getAutoCreate : function(){
16540 var cfg = typeof this.autoCreate == "object" ?
16541 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
16542 if(this.id && !cfg.id){
16549 afterRender : Roo.emptyFn,
16552 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
16553 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
16555 destroy : function(){
16556 if(this.fireEvent("beforedestroy", this) !== false){
16557 this.purgeListeners();
16558 this.beforeDestroy();
16560 this.el.removeAllListeners();
16562 if(this.actionMode == "container"){
16563 this.container.remove();
16567 Roo.ComponentMgr.unregister(this);
16568 this.fireEvent("destroy", this);
16573 beforeDestroy : function(){
16578 onDestroy : function(){
16583 * Returns the underlying {@link Roo.Element}.
16584 * @return {Roo.Element} The element
16586 getEl : function(){
16591 * Returns the id of this component.
16594 getId : function(){
16599 * Try to focus this component.
16600 * @param {Boolean} selectText True to also select the text in this component (if applicable)
16601 * @return {Roo.Component} this
16603 focus : function(selectText){
16606 if(selectText === true){
16607 this.el.dom.select();
16622 * Disable this component.
16623 * @return {Roo.Component} this
16625 disable : function(){
16629 this.disabled = true;
16630 this.fireEvent("disable", this);
16635 onDisable : function(){
16636 this.getActionEl().addClass(this.disabledClass);
16637 this.el.dom.disabled = true;
16641 * Enable this component.
16642 * @return {Roo.Component} this
16644 enable : function(){
16648 this.disabled = false;
16649 this.fireEvent("enable", this);
16654 onEnable : function(){
16655 this.getActionEl().removeClass(this.disabledClass);
16656 this.el.dom.disabled = false;
16660 * Convenience function for setting disabled/enabled by boolean.
16661 * @param {Boolean} disabled
16663 setDisabled : function(disabled){
16664 this[disabled ? "disable" : "enable"]();
16668 * Show this component.
16669 * @return {Roo.Component} this
16672 if(this.fireEvent("beforeshow", this) !== false){
16673 this.hidden = false;
16677 this.fireEvent("show", this);
16683 onShow : function(){
16684 var ae = this.getActionEl();
16685 if(this.hideMode == 'visibility'){
16686 ae.dom.style.visibility = "visible";
16687 }else if(this.hideMode == 'offsets'){
16688 ae.removeClass('x-hidden');
16690 ae.dom.style.display = "";
16695 * Hide this component.
16696 * @return {Roo.Component} this
16699 if(this.fireEvent("beforehide", this) !== false){
16700 this.hidden = true;
16704 this.fireEvent("hide", this);
16710 onHide : function(){
16711 var ae = this.getActionEl();
16712 if(this.hideMode == 'visibility'){
16713 ae.dom.style.visibility = "hidden";
16714 }else if(this.hideMode == 'offsets'){
16715 ae.addClass('x-hidden');
16717 ae.dom.style.display = "none";
16722 * Convenience function to hide or show this component by boolean.
16723 * @param {Boolean} visible True to show, false to hide
16724 * @return {Roo.Component} this
16726 setVisible: function(visible){
16736 * Returns true if this component is visible.
16738 isVisible : function(){
16739 return this.getActionEl().isVisible();
16742 cloneConfig : function(overrides){
16743 overrides = overrides || {};
16744 var id = overrides.id || Roo.id();
16745 var cfg = Roo.applyIf(overrides, this.initialConfig);
16746 cfg.id = id; // prevent dup id
16747 return new this.constructor(cfg);
16751 * Ext JS Library 1.1.1
16752 * Copyright(c) 2006-2007, Ext JS, LLC.
16754 * Originally Released Under LGPL - original licence link has changed is not relivant.
16757 * <script type="text/javascript">
16761 * @class Roo.BoxComponent
16762 * @extends Roo.Component
16763 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
16764 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
16765 * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
16766 * layout containers.
16768 * @param {Roo.Element/String/Object} config The configuration options.
16770 Roo.BoxComponent = function(config){
16771 Roo.Component.call(this, config);
16775 * Fires after the component is resized.
16776 * @param {Roo.Component} this
16777 * @param {Number} adjWidth The box-adjusted width that was set
16778 * @param {Number} adjHeight The box-adjusted height that was set
16779 * @param {Number} rawWidth The width that was originally specified
16780 * @param {Number} rawHeight The height that was originally specified
16785 * Fires after the component is moved.
16786 * @param {Roo.Component} this
16787 * @param {Number} x The new x position
16788 * @param {Number} y The new y position
16794 Roo.extend(Roo.BoxComponent, Roo.Component, {
16795 // private, set in afterRender to signify that the component has been rendered
16797 // private, used to defer height settings to subclasses
16798 deferHeight: false,
16799 /** @cfg {Number} width
16800 * width (optional) size of component
16802 /** @cfg {Number} height
16803 * height (optional) size of component
16807 * Sets the width and height of the component. This method fires the resize event. This method can accept
16808 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
16809 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
16810 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
16811 * @return {Roo.BoxComponent} this
16813 setSize : function(w, h){
16814 // support for standard size objects
16815 if(typeof w == 'object'){
16820 if(!this.boxReady){
16826 // prevent recalcs when not needed
16827 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
16830 this.lastSize = {width: w, height: h};
16832 var adj = this.adjustSize(w, h);
16833 var aw = adj.width, ah = adj.height;
16834 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
16835 var rz = this.getResizeEl();
16836 if(!this.deferHeight && aw !== undefined && ah !== undefined){
16837 rz.setSize(aw, ah);
16838 }else if(!this.deferHeight && ah !== undefined){
16840 }else if(aw !== undefined){
16843 this.onResize(aw, ah, w, h);
16844 this.fireEvent('resize', this, aw, ah, w, h);
16850 * Gets the current size of the component's underlying element.
16851 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
16853 getSize : function(){
16854 return this.el.getSize();
16858 * Gets the current XY position of the component's underlying element.
16859 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16860 * @return {Array} The XY position of the element (e.g., [100, 200])
16862 getPosition : function(local){
16863 if(local === true){
16864 return [this.el.getLeft(true), this.el.getTop(true)];
16866 return this.xy || this.el.getXY();
16870 * Gets the current box measurements of the component's underlying element.
16871 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16872 * @returns {Object} box An object in the format {x, y, width, height}
16874 getBox : function(local){
16875 var s = this.el.getSize();
16877 s.x = this.el.getLeft(true);
16878 s.y = this.el.getTop(true);
16880 var xy = this.xy || this.el.getXY();
16888 * Sets the current box measurements of the component's underlying element.
16889 * @param {Object} box An object in the format {x, y, width, height}
16890 * @returns {Roo.BoxComponent} this
16892 updateBox : function(box){
16893 this.setSize(box.width, box.height);
16894 this.setPagePosition(box.x, box.y);
16899 getResizeEl : function(){
16900 return this.resizeEl || this.el;
16904 getPositionEl : function(){
16905 return this.positionEl || this.el;
16909 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
16910 * This method fires the move event.
16911 * @param {Number} left The new left
16912 * @param {Number} top The new top
16913 * @returns {Roo.BoxComponent} this
16915 setPosition : function(x, y){
16918 if(!this.boxReady){
16921 var adj = this.adjustPosition(x, y);
16922 var ax = adj.x, ay = adj.y;
16924 var el = this.getPositionEl();
16925 if(ax !== undefined || ay !== undefined){
16926 if(ax !== undefined && ay !== undefined){
16927 el.setLeftTop(ax, ay);
16928 }else if(ax !== undefined){
16930 }else if(ay !== undefined){
16933 this.onPosition(ax, ay);
16934 this.fireEvent('move', this, ax, ay);
16940 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
16941 * This method fires the move event.
16942 * @param {Number} x The new x position
16943 * @param {Number} y The new y position
16944 * @returns {Roo.BoxComponent} this
16946 setPagePosition : function(x, y){
16949 if(!this.boxReady){
16952 if(x === undefined || y === undefined){ // cannot translate undefined points
16955 var p = this.el.translatePoints(x, y);
16956 this.setPosition(p.left, p.top);
16961 onRender : function(ct, position){
16962 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
16964 this.resizeEl = Roo.get(this.resizeEl);
16966 if(this.positionEl){
16967 this.positionEl = Roo.get(this.positionEl);
16972 afterRender : function(){
16973 Roo.BoxComponent.superclass.afterRender.call(this);
16974 this.boxReady = true;
16975 this.setSize(this.width, this.height);
16976 if(this.x || this.y){
16977 this.setPosition(this.x, this.y);
16979 if(this.pageX || this.pageY){
16980 this.setPagePosition(this.pageX, this.pageY);
16985 * Force the component's size to recalculate based on the underlying element's current height and width.
16986 * @returns {Roo.BoxComponent} this
16988 syncSize : function(){
16989 delete this.lastSize;
16990 this.setSize(this.el.getWidth(), this.el.getHeight());
16995 * Called after the component is resized, this method is empty by default but can be implemented by any
16996 * subclass that needs to perform custom logic after a resize occurs.
16997 * @param {Number} adjWidth The box-adjusted width that was set
16998 * @param {Number} adjHeight The box-adjusted height that was set
16999 * @param {Number} rawWidth The width that was originally specified
17000 * @param {Number} rawHeight The height that was originally specified
17002 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
17007 * Called after the component is moved, this method is empty by default but can be implemented by any
17008 * subclass that needs to perform custom logic after a move occurs.
17009 * @param {Number} x The new x position
17010 * @param {Number} y The new y position
17012 onPosition : function(x, y){
17017 adjustSize : function(w, h){
17018 if(this.autoWidth){
17021 if(this.autoHeight){
17024 return {width : w, height: h};
17028 adjustPosition : function(x, y){
17029 return {x : x, y: y};
17033 * Ext JS Library 1.1.1
17034 * Copyright(c) 2006-2007, Ext JS, LLC.
17036 * Originally Released Under LGPL - original licence link has changed is not relivant.
17039 * <script type="text/javascript">
17044 * @extends Roo.Element
17045 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
17046 * automatic maintaining of shadow/shim positions.
17047 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
17048 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
17049 * you can pass a string with a CSS class name. False turns off the shadow.
17050 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
17051 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
17052 * @cfg {String} cls CSS class to add to the element
17053 * @cfg {Number} zindex Starting z-index (defaults to 11000)
17054 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
17056 * @param {Object} config An object with config options.
17057 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
17060 Roo.Layer = function(config, existingEl){
17061 config = config || {};
17062 var dh = Roo.DomHelper;
17063 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
17065 this.dom = Roo.getDom(existingEl);
17068 var o = config.dh || {tag: "div", cls: "x-layer"};
17069 this.dom = dh.append(pel, o);
17072 this.addClass(config.cls);
17074 this.constrain = config.constrain !== false;
17075 this.visibilityMode = Roo.Element.VISIBILITY;
17077 this.id = this.dom.id = config.id;
17079 this.id = Roo.id(this.dom);
17081 this.zindex = config.zindex || this.getZIndex();
17082 this.position("absolute", this.zindex);
17084 this.shadowOffset = config.shadowOffset || 4;
17085 this.shadow = new Roo.Shadow({
17086 offset : this.shadowOffset,
17087 mode : config.shadow
17090 this.shadowOffset = 0;
17092 this.useShim = config.shim !== false && Roo.useShims;
17093 this.useDisplay = config.useDisplay;
17097 var supr = Roo.Element.prototype;
17099 // shims are shared among layer to keep from having 100 iframes
17102 Roo.extend(Roo.Layer, Roo.Element, {
17104 getZIndex : function(){
17105 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
17108 getShim : function(){
17115 var shim = shims.shift();
17117 shim = this.createShim();
17118 shim.enableDisplayMode('block');
17119 shim.dom.style.display = 'none';
17120 shim.dom.style.visibility = 'visible';
17122 var pn = this.dom.parentNode;
17123 if(shim.dom.parentNode != pn){
17124 pn.insertBefore(shim.dom, this.dom);
17126 shim.setStyle('z-index', this.getZIndex()-2);
17131 hideShim : function(){
17133 this.shim.setDisplayed(false);
17134 shims.push(this.shim);
17139 disableShadow : function(){
17141 this.shadowDisabled = true;
17142 this.shadow.hide();
17143 this.lastShadowOffset = this.shadowOffset;
17144 this.shadowOffset = 0;
17148 enableShadow : function(show){
17150 this.shadowDisabled = false;
17151 this.shadowOffset = this.lastShadowOffset;
17152 delete this.lastShadowOffset;
17160 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
17161 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
17162 sync : function(doShow){
17163 var sw = this.shadow;
17164 if(!this.updating && this.isVisible() && (sw || this.useShim)){
17165 var sh = this.getShim();
17167 var w = this.getWidth(),
17168 h = this.getHeight();
17170 var l = this.getLeft(true),
17171 t = this.getTop(true);
17173 if(sw && !this.shadowDisabled){
17174 if(doShow && !sw.isVisible()){
17177 sw.realign(l, t, w, h);
17183 // fit the shim behind the shadow, so it is shimmed too
17184 var a = sw.adjusts, s = sh.dom.style;
17185 s.left = (Math.min(l, l+a.l))+"px";
17186 s.top = (Math.min(t, t+a.t))+"px";
17187 s.width = (w+a.w)+"px";
17188 s.height = (h+a.h)+"px";
17195 sh.setLeftTop(l, t);
17202 destroy : function(){
17205 this.shadow.hide();
17207 this.removeAllListeners();
17208 var pn = this.dom.parentNode;
17210 pn.removeChild(this.dom);
17212 Roo.Element.uncache(this.id);
17215 remove : function(){
17220 beginUpdate : function(){
17221 this.updating = true;
17225 endUpdate : function(){
17226 this.updating = false;
17231 hideUnders : function(negOffset){
17233 this.shadow.hide();
17239 constrainXY : function(){
17240 if(this.constrain){
17241 var vw = Roo.lib.Dom.getViewWidth(),
17242 vh = Roo.lib.Dom.getViewHeight();
17243 var s = Roo.get(document).getScroll();
17245 var xy = this.getXY();
17246 var x = xy[0], y = xy[1];
17247 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
17248 // only move it if it needs it
17250 // first validate right/bottom
17251 if((x + w) > vw+s.left){
17252 x = vw - w - this.shadowOffset;
17255 if((y + h) > vh+s.top){
17256 y = vh - h - this.shadowOffset;
17259 // then make sure top/left isn't negative
17270 var ay = this.avoidY;
17271 if(y <= ay && (y+h) >= ay){
17277 supr.setXY.call(this, xy);
17283 isVisible : function(){
17284 return this.visible;
17288 showAction : function(){
17289 this.visible = true; // track visibility to prevent getStyle calls
17290 if(this.useDisplay === true){
17291 this.setDisplayed("");
17292 }else if(this.lastXY){
17293 supr.setXY.call(this, this.lastXY);
17294 }else if(this.lastLT){
17295 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
17300 hideAction : function(){
17301 this.visible = false;
17302 if(this.useDisplay === true){
17303 this.setDisplayed(false);
17305 this.setLeftTop(-10000,-10000);
17309 // overridden Element method
17310 setVisible : function(v, a, d, c, e){
17315 var cb = function(){
17320 }.createDelegate(this);
17321 supr.setVisible.call(this, true, true, d, cb, e);
17324 this.hideUnders(true);
17333 }.createDelegate(this);
17335 supr.setVisible.call(this, v, a, d, cb, e);
17344 storeXY : function(xy){
17345 delete this.lastLT;
17349 storeLeftTop : function(left, top){
17350 delete this.lastXY;
17351 this.lastLT = [left, top];
17355 beforeFx : function(){
17356 this.beforeAction();
17357 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
17361 afterFx : function(){
17362 Roo.Layer.superclass.afterFx.apply(this, arguments);
17363 this.sync(this.isVisible());
17367 beforeAction : function(){
17368 if(!this.updating && this.shadow){
17369 this.shadow.hide();
17373 // overridden Element method
17374 setLeft : function(left){
17375 this.storeLeftTop(left, this.getTop(true));
17376 supr.setLeft.apply(this, arguments);
17380 setTop : function(top){
17381 this.storeLeftTop(this.getLeft(true), top);
17382 supr.setTop.apply(this, arguments);
17386 setLeftTop : function(left, top){
17387 this.storeLeftTop(left, top);
17388 supr.setLeftTop.apply(this, arguments);
17392 setXY : function(xy, a, d, c, e){
17394 this.beforeAction();
17396 var cb = this.createCB(c);
17397 supr.setXY.call(this, xy, a, d, cb, e);
17404 createCB : function(c){
17415 // overridden Element method
17416 setX : function(x, a, d, c, e){
17417 this.setXY([x, this.getY()], a, d, c, e);
17420 // overridden Element method
17421 setY : function(y, a, d, c, e){
17422 this.setXY([this.getX(), y], a, d, c, e);
17425 // overridden Element method
17426 setSize : function(w, h, a, d, c, e){
17427 this.beforeAction();
17428 var cb = this.createCB(c);
17429 supr.setSize.call(this, w, h, a, d, cb, e);
17435 // overridden Element method
17436 setWidth : function(w, a, d, c, e){
17437 this.beforeAction();
17438 var cb = this.createCB(c);
17439 supr.setWidth.call(this, w, a, d, cb, e);
17445 // overridden Element method
17446 setHeight : function(h, a, d, c, e){
17447 this.beforeAction();
17448 var cb = this.createCB(c);
17449 supr.setHeight.call(this, h, a, d, cb, e);
17455 // overridden Element method
17456 setBounds : function(x, y, w, h, a, d, c, e){
17457 this.beforeAction();
17458 var cb = this.createCB(c);
17460 this.storeXY([x, y]);
17461 supr.setXY.call(this, [x, y]);
17462 supr.setSize.call(this, w, h, a, d, cb, e);
17465 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
17471 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
17472 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
17473 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
17474 * @param {Number} zindex The new z-index to set
17475 * @return {this} The Layer
17477 setZIndex : function(zindex){
17478 this.zindex = zindex;
17479 this.setStyle("z-index", zindex + 2);
17481 this.shadow.setZIndex(zindex + 1);
17484 this.shim.setStyle("z-index", zindex);
17489 * Original code for Roojs - LGPL
17490 * <script type="text/javascript">
17494 * @class Roo.XComponent
17495 * A delayed Element creator...
17496 * Or a way to group chunks of interface together.
17497 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
17498 * used in conjunction with XComponent.build() it will create an instance of each element,
17499 * then call addxtype() to build the User interface.
17501 * Mypart.xyx = new Roo.XComponent({
17503 parent : 'Mypart.xyz', // empty == document.element.!!
17507 disabled : function() {}
17509 tree : function() { // return an tree of xtype declared components
17513 xtype : 'NestedLayoutPanel',
17520 * It can be used to build a big heiracy, with parent etc.
17521 * or you can just use this to render a single compoent to a dom element
17522 * MYPART.render(Roo.Element | String(id) | dom_element )
17529 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
17530 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
17532 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
17534 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
17535 * - if mulitple topModules exist, the last one is defined as the top module.
17539 * When the top level or multiple modules are to embedded into a existing HTML page,
17540 * the parent element can container '#id' of the element where the module will be drawn.
17544 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
17545 * it relies more on a include mechanism, where sub modules are included into an outer page.
17546 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
17548 * Bootstrap Roo Included elements
17550 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
17551 * hence confusing the component builder as it thinks there are multiple top level elements.
17553 * String Over-ride & Translations
17555 * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
17556 * and also the 'overlaying of string values - needed when different versions of the same application with different text content
17557 * are needed. @see Roo.XComponent.overlayString
17561 * @extends Roo.util.Observable
17563 * @param cfg {Object} configuration of component
17566 Roo.XComponent = function(cfg) {
17567 Roo.apply(this, cfg);
17571 * Fires when this the componnt is built
17572 * @param {Roo.XComponent} c the component
17577 this.region = this.region || 'center'; // default..
17578 Roo.XComponent.register(this);
17579 this.modules = false;
17580 this.el = false; // where the layout goes..
17584 Roo.extend(Roo.XComponent, Roo.util.Observable, {
17587 * The created element (with Roo.factory())
17588 * @type {Roo.Layout}
17594 * for BC - use el in new code
17595 * @type {Roo.Layout}
17601 * for BC - use el in new code
17602 * @type {Roo.Layout}
17607 * @cfg {Function|boolean} disabled
17608 * If this module is disabled by some rule, return true from the funtion
17613 * @cfg {String} parent
17614 * Name of parent element which it get xtype added to..
17619 * @cfg {String} order
17620 * Used to set the order in which elements are created (usefull for multiple tabs)
17625 * @cfg {String} name
17626 * String to display while loading.
17630 * @cfg {String} region
17631 * Region to render component to (defaults to center)
17636 * @cfg {Array} items
17637 * A single item array - the first element is the root of the tree..
17638 * It's done this way to stay compatible with the Xtype system...
17644 * The method that retuns the tree of parts that make up this compoennt
17651 * render element to dom or tree
17652 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
17655 render : function(el)
17659 var hp = this.parent ? 1 : 0;
17660 Roo.debug && Roo.log(this);
17662 var tree = this._tree ? this._tree() : this.tree();
17665 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
17666 // if parent is a '#.....' string, then let's use that..
17667 var ename = this.parent.substr(1);
17668 this.parent = false;
17669 Roo.debug && Roo.log(ename);
17671 case 'bootstrap-body':
17672 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
17673 // this is the BorderLayout standard?
17674 this.parent = { el : true };
17677 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
17678 // need to insert stuff...
17680 el : new Roo.bootstrap.layout.Border({
17681 el : document.body,
17687 tabPosition: 'top',
17688 //resizeTabs: true,
17689 alwaysShowTabs: true,
17699 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
17700 this.parent = { el : new Roo.bootstrap.Body() };
17701 Roo.debug && Roo.log("setting el to doc body");
17704 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
17708 this.parent = { el : true};
17711 el = Roo.get(ename);
17712 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
17713 this.parent = { el : true};
17720 if (!el && !this.parent) {
17721 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
17726 Roo.debug && Roo.log("EL:");
17727 Roo.debug && Roo.log(el);
17728 Roo.debug && Roo.log("this.parent.el:");
17729 Roo.debug && Roo.log(this.parent.el);
17732 // altertive root elements ??? - we need a better way to indicate these.
17733 var is_alt = Roo.XComponent.is_alt ||
17734 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
17735 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
17736 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
17740 if (!this.parent && is_alt) {
17741 //el = Roo.get(document.body);
17742 this.parent = { el : true };
17747 if (!this.parent) {
17749 Roo.debug && Roo.log("no parent - creating one");
17751 el = el ? Roo.get(el) : false;
17753 if (typeof(Roo.BorderLayout) == 'undefined' ) {
17756 el : new Roo.bootstrap.layout.Border({
17757 el: el || document.body,
17763 tabPosition: 'top',
17764 //resizeTabs: true,
17765 alwaysShowTabs: false,
17768 overflow: 'visible'
17774 // it's a top level one..
17776 el : new Roo.BorderLayout(el || document.body, {
17781 tabPosition: 'top',
17782 //resizeTabs: true,
17783 alwaysShowTabs: el && hp? false : true,
17784 hideTabs: el || !hp ? true : false,
17792 if (!this.parent.el) {
17793 // probably an old style ctor, which has been disabled.
17797 // The 'tree' method is '_tree now'
17799 tree.region = tree.region || this.region;
17800 var is_body = false;
17801 if (this.parent.el === true) {
17802 // bootstrap... - body..
17806 this.parent.el = Roo.factory(tree);
17810 this.el = this.parent.el.addxtype(tree, undefined, is_body);
17811 this.fireEvent('built', this);
17813 this.panel = this.el;
17814 this.layout = this.panel.layout;
17815 this.parentLayout = this.parent.layout || false;
17821 Roo.apply(Roo.XComponent, {
17823 * @property hideProgress
17824 * true to disable the building progress bar.. usefull on single page renders.
17827 hideProgress : false,
17829 * @property buildCompleted
17830 * True when the builder has completed building the interface.
17833 buildCompleted : false,
17836 * @property topModule
17837 * the upper most module - uses document.element as it's constructor.
17844 * @property modules
17845 * array of modules to be created by registration system.
17846 * @type {Array} of Roo.XComponent
17851 * @property elmodules
17852 * array of modules to be created by which use #ID
17853 * @type {Array} of Roo.XComponent
17860 * Is an alternative Root - normally used by bootstrap or other systems,
17861 * where the top element in the tree can wrap 'body'
17862 * @type {boolean} (default false)
17867 * @property build_from_html
17868 * Build elements from html - used by bootstrap HTML stuff
17869 * - this is cleared after build is completed
17870 * @type {boolean} (default false)
17873 build_from_html : false,
17875 * Register components to be built later.
17877 * This solves the following issues
17878 * - Building is not done on page load, but after an authentication process has occured.
17879 * - Interface elements are registered on page load
17880 * - Parent Interface elements may not be loaded before child, so this handles that..
17887 module : 'Pman.Tab.projectMgr',
17889 parent : 'Pman.layout',
17890 disabled : false, // or use a function..
17893 * * @param {Object} details about module
17895 register : function(obj) {
17897 Roo.XComponent.event.fireEvent('register', obj);
17898 switch(typeof(obj.disabled) ) {
17904 if ( obj.disabled() ) {
17910 if (obj.disabled || obj.region == '#disabled') {
17916 this.modules.push(obj);
17920 * convert a string to an object..
17921 * eg. 'AAA.BBB' -> finds AAA.BBB
17925 toObject : function(str)
17927 if (!str || typeof(str) == 'object') {
17930 if (str.substring(0,1) == '#') {
17934 var ar = str.split('.');
17939 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
17941 throw "Module not found : " + str;
17945 throw "Module not found : " + str;
17947 Roo.each(ar, function(e) {
17948 if (typeof(o[e]) == 'undefined') {
17949 throw "Module not found : " + str;
17960 * move modules into their correct place in the tree..
17963 preBuild : function ()
17966 Roo.each(this.modules , function (obj)
17968 Roo.XComponent.event.fireEvent('beforebuild', obj);
17970 var opar = obj.parent;
17972 obj.parent = this.toObject(opar);
17974 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
17979 Roo.debug && Roo.log("GOT top level module");
17980 Roo.debug && Roo.log(obj);
17981 obj.modules = new Roo.util.MixedCollection(false,
17982 function(o) { return o.order + '' }
17984 this.topModule = obj;
17987 // parent is a string (usually a dom element name..)
17988 if (typeof(obj.parent) == 'string') {
17989 this.elmodules.push(obj);
17992 if (obj.parent.constructor != Roo.XComponent) {
17993 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
17995 if (!obj.parent.modules) {
17996 obj.parent.modules = new Roo.util.MixedCollection(false,
17997 function(o) { return o.order + '' }
18000 if (obj.parent.disabled) {
18001 obj.disabled = true;
18003 obj.parent.modules.add(obj);
18008 * make a list of modules to build.
18009 * @return {Array} list of modules.
18012 buildOrder : function()
18015 var cmp = function(a,b) {
18016 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
18018 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
18019 throw "No top level modules to build";
18022 // make a flat list in order of modules to build.
18023 var mods = this.topModule ? [ this.topModule ] : [];
18026 // elmodules (is a list of DOM based modules )
18027 Roo.each(this.elmodules, function(e) {
18029 if (!this.topModule &&
18030 typeof(e.parent) == 'string' &&
18031 e.parent.substring(0,1) == '#' &&
18032 Roo.get(e.parent.substr(1))
18035 _this.topModule = e;
18041 // add modules to their parents..
18042 var addMod = function(m) {
18043 Roo.debug && Roo.log("build Order: add: " + m.name);
18046 if (m.modules && !m.disabled) {
18047 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
18048 m.modules.keySort('ASC', cmp );
18049 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
18051 m.modules.each(addMod);
18053 Roo.debug && Roo.log("build Order: no child modules");
18055 // not sure if this is used any more..
18057 m.finalize.name = m.name + " (clean up) ";
18058 mods.push(m.finalize);
18062 if (this.topModule && this.topModule.modules) {
18063 this.topModule.modules.keySort('ASC', cmp );
18064 this.topModule.modules.each(addMod);
18070 * Build the registered modules.
18071 * @param {Object} parent element.
18072 * @param {Function} optional method to call after module has been added.
18076 build : function(opts)
18079 if (typeof(opts) != 'undefined') {
18080 Roo.apply(this,opts);
18084 var mods = this.buildOrder();
18086 //this.allmods = mods;
18087 //Roo.debug && Roo.log(mods);
18089 if (!mods.length) { // should not happen
18090 throw "NO modules!!!";
18094 var msg = "Building Interface...";
18095 // flash it up as modal - so we store the mask!?
18096 if (!this.hideProgress && Roo.MessageBox) {
18097 Roo.MessageBox.show({ title: 'loading' });
18098 Roo.MessageBox.show({
18099 title: "Please wait...",
18109 var total = mods.length;
18112 var progressRun = function() {
18113 if (!mods.length) {
18114 Roo.debug && Roo.log('hide?');
18115 if (!this.hideProgress && Roo.MessageBox) {
18116 Roo.MessageBox.hide();
18118 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
18120 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
18126 var m = mods.shift();
18129 Roo.debug && Roo.log(m);
18130 // not sure if this is supported any more.. - modules that are are just function
18131 if (typeof(m) == 'function') {
18133 return progressRun.defer(10, _this);
18137 msg = "Building Interface " + (total - mods.length) +
18139 (m.name ? (' - ' + m.name) : '');
18140 Roo.debug && Roo.log(msg);
18141 if (!_this.hideProgress && Roo.MessageBox) {
18142 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
18146 // is the module disabled?
18147 var disabled = (typeof(m.disabled) == 'function') ?
18148 m.disabled.call(m.module.disabled) : m.disabled;
18152 return progressRun(); // we do not update the display!
18160 // it's 10 on top level, and 1 on others??? why...
18161 return progressRun.defer(10, _this);
18164 progressRun.defer(1, _this);
18170 * Overlay a set of modified strings onto a component
18171 * This is dependant on our builder exporting the strings and 'named strings' elements.
18173 * @param {Object} element to overlay on - eg. Pman.Dialog.Login
18174 * @param {Object} associative array of 'named' string and it's new value.
18177 overlayStrings : function( component, strings )
18179 if (typeof(component['_named_strings']) == 'undefined') {
18180 throw "ERROR: component does not have _named_strings";
18182 for ( var k in strings ) {
18183 var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
18184 if (md !== false) {
18185 component['_strings'][md] = strings[k];
18187 Roo.log('could not find named string: ' + k + ' in');
18188 Roo.log(component);
18203 * wrapper for event.on - aliased later..
18204 * Typically use to register a event handler for register:
18206 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
18215 Roo.XComponent.event = new Roo.util.Observable({
18219 * Fires when an Component is registered,
18220 * set the disable property on the Component to stop registration.
18221 * @param {Roo.XComponent} c the component being registerd.
18226 * @event beforebuild
18227 * Fires before each Component is built
18228 * can be used to apply permissions.
18229 * @param {Roo.XComponent} c the component being registerd.
18232 'beforebuild' : true,
18234 * @event buildcomplete
18235 * Fires on the top level element when all elements have been built
18236 * @param {Roo.XComponent} the top level component.
18238 'buildcomplete' : true
18243 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
18246 * marked - a markdown parser
18247 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
18248 * https://github.com/chjj/marked
18254 * Roo.Markdown - is a very crude wrapper around marked..
18258 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
18260 * Note: move the sample code to the bottom of this
18261 * file before uncommenting it.
18266 Roo.Markdown.toHtml = function(text) {
18268 var c = new Roo.Markdown.marked.setOptions({
18269 renderer: new Roo.Markdown.marked.Renderer(),
18280 text = text.replace(/\\\n/g,' ');
18281 return Roo.Markdown.marked(text);
18286 // Wraps all "globals" so that the only thing
18287 // exposed is makeHtml().
18293 * eval:var:unescape
18301 var escape = function (html, encode) {
18303 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
18304 .replace(/</g, '<')
18305 .replace(/>/g, '>')
18306 .replace(/"/g, '"')
18307 .replace(/'/g, ''');
18310 var unescape = function (html) {
18311 // explicitly match decimal, hex, and named HTML entities
18312 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
18313 n = n.toLowerCase();
18314 if (n === 'colon') { return ':'; }
18315 if (n.charAt(0) === '#') {
18316 return n.charAt(1) === 'x'
18317 ? String.fromCharCode(parseInt(n.substring(2), 16))
18318 : String.fromCharCode(+n.substring(1));
18324 var replace = function (regex, opt) {
18325 regex = regex.source;
18327 return function self(name, val) {
18328 if (!name) { return new RegExp(regex, opt); }
18329 val = val.source || val;
18330 val = val.replace(/(^|[^\[])\^/g, '$1');
18331 regex = regex.replace(name, val);
18340 var noop = function () {}
18346 var merge = function (obj) {
18351 for (; i < arguments.length; i++) {
18352 target = arguments[i];
18353 for (key in target) {
18354 if (Object.prototype.hasOwnProperty.call(target, key)) {
18355 obj[key] = target[key];
18365 * Block-Level Grammar
18373 code: /^( {4}[^\n]+\n*)+/,
18375 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
18376 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
18378 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
18379 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
18380 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
18381 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
18382 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
18384 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
18388 block.bullet = /(?:[*+-]|\d+\.)/;
18389 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
18390 block.item = replace(block.item, 'gm')
18391 (/bull/g, block.bullet)
18394 block.list = replace(block.list)
18395 (/bull/g, block.bullet)
18396 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
18397 ('def', '\\n+(?=' + block.def.source + ')')
18400 block.blockquote = replace(block.blockquote)
18404 block._tag = '(?!(?:'
18405 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
18406 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
18407 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
18409 block.html = replace(block.html)
18410 ('comment', /<!--[\s\S]*?-->/)
18411 ('closed', /<(tag)[\s\S]+?<\/\1>/)
18412 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
18413 (/tag/g, block._tag)
18416 block.paragraph = replace(block.paragraph)
18418 ('heading', block.heading)
18419 ('lheading', block.lheading)
18420 ('blockquote', block.blockquote)
18421 ('tag', '<' + block._tag)
18426 * Normal Block Grammar
18429 block.normal = merge({}, block);
18432 * GFM Block Grammar
18435 block.gfm = merge({}, block.normal, {
18436 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
18438 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
18441 block.gfm.paragraph = replace(block.paragraph)
18443 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
18444 + block.list.source.replace('\\1', '\\3') + '|')
18448 * GFM + Tables Block Grammar
18451 block.tables = merge({}, block.gfm, {
18452 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
18453 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
18460 var Lexer = function (options) {
18462 this.tokens.links = {};
18463 this.options = options || marked.defaults;
18464 this.rules = block.normal;
18466 if (this.options.gfm) {
18467 if (this.options.tables) {
18468 this.rules = block.tables;
18470 this.rules = block.gfm;
18476 * Expose Block Rules
18479 Lexer.rules = block;
18482 * Static Lex Method
18485 Lexer.lex = function(src, options) {
18486 var lexer = new Lexer(options);
18487 return lexer.lex(src);
18494 Lexer.prototype.lex = function(src) {
18496 .replace(/\r\n|\r/g, '\n')
18497 .replace(/\t/g, ' ')
18498 .replace(/\u00a0/g, ' ')
18499 .replace(/\u2424/g, '\n');
18501 return this.token(src, true);
18508 Lexer.prototype.token = function(src, top, bq) {
18509 var src = src.replace(/^ +$/gm, '')
18522 if (cap = this.rules.newline.exec(src)) {
18523 src = src.substring(cap[0].length);
18524 if (cap[0].length > 1) {
18532 if (cap = this.rules.code.exec(src)) {
18533 src = src.substring(cap[0].length);
18534 cap = cap[0].replace(/^ {4}/gm, '');
18537 text: !this.options.pedantic
18538 ? cap.replace(/\n+$/, '')
18545 if (cap = this.rules.fences.exec(src)) {
18546 src = src.substring(cap[0].length);
18556 if (cap = this.rules.heading.exec(src)) {
18557 src = src.substring(cap[0].length);
18560 depth: cap[1].length,
18566 // table no leading pipe (gfm)
18567 if (top && (cap = this.rules.nptable.exec(src))) {
18568 src = src.substring(cap[0].length);
18572 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18573 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18574 cells: cap[3].replace(/\n$/, '').split('\n')
18577 for (i = 0; i < item.align.length; i++) {
18578 if (/^ *-+: *$/.test(item.align[i])) {
18579 item.align[i] = 'right';
18580 } else if (/^ *:-+: *$/.test(item.align[i])) {
18581 item.align[i] = 'center';
18582 } else if (/^ *:-+ *$/.test(item.align[i])) {
18583 item.align[i] = 'left';
18585 item.align[i] = null;
18589 for (i = 0; i < item.cells.length; i++) {
18590 item.cells[i] = item.cells[i].split(/ *\| */);
18593 this.tokens.push(item);
18599 if (cap = this.rules.lheading.exec(src)) {
18600 src = src.substring(cap[0].length);
18603 depth: cap[2] === '=' ? 1 : 2,
18610 if (cap = this.rules.hr.exec(src)) {
18611 src = src.substring(cap[0].length);
18619 if (cap = this.rules.blockquote.exec(src)) {
18620 src = src.substring(cap[0].length);
18623 type: 'blockquote_start'
18626 cap = cap[0].replace(/^ *> ?/gm, '');
18628 // Pass `top` to keep the current
18629 // "toplevel" state. This is exactly
18630 // how markdown.pl works.
18631 this.token(cap, top, true);
18634 type: 'blockquote_end'
18641 if (cap = this.rules.list.exec(src)) {
18642 src = src.substring(cap[0].length);
18646 type: 'list_start',
18647 ordered: bull.length > 1
18650 // Get each top-level item.
18651 cap = cap[0].match(this.rules.item);
18657 for (; i < l; i++) {
18660 // Remove the list item's bullet
18661 // so it is seen as the next token.
18662 space = item.length;
18663 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
18665 // Outdent whatever the
18666 // list item contains. Hacky.
18667 if (~item.indexOf('\n ')) {
18668 space -= item.length;
18669 item = !this.options.pedantic
18670 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
18671 : item.replace(/^ {1,4}/gm, '');
18674 // Determine whether the next list item belongs here.
18675 // Backpedal if it does not belong in this list.
18676 if (this.options.smartLists && i !== l - 1) {
18677 b = block.bullet.exec(cap[i + 1])[0];
18678 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
18679 src = cap.slice(i + 1).join('\n') + src;
18684 // Determine whether item is loose or not.
18685 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
18686 // for discount behavior.
18687 loose = next || /\n\n(?!\s*$)/.test(item);
18689 next = item.charAt(item.length - 1) === '\n';
18690 if (!loose) { loose = next; }
18695 ? 'loose_item_start'
18696 : 'list_item_start'
18700 this.token(item, false, bq);
18703 type: 'list_item_end'
18715 if (cap = this.rules.html.exec(src)) {
18716 src = src.substring(cap[0].length);
18718 type: this.options.sanitize
18721 pre: !this.options.sanitizer
18722 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
18729 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
18730 src = src.substring(cap[0].length);
18731 this.tokens.links[cap[1].toLowerCase()] = {
18739 if (top && (cap = this.rules.table.exec(src))) {
18740 src = src.substring(cap[0].length);
18744 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18745 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18746 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
18749 for (i = 0; i < item.align.length; i++) {
18750 if (/^ *-+: *$/.test(item.align[i])) {
18751 item.align[i] = 'right';
18752 } else if (/^ *:-+: *$/.test(item.align[i])) {
18753 item.align[i] = 'center';
18754 } else if (/^ *:-+ *$/.test(item.align[i])) {
18755 item.align[i] = 'left';
18757 item.align[i] = null;
18761 for (i = 0; i < item.cells.length; i++) {
18762 item.cells[i] = item.cells[i]
18763 .replace(/^ *\| *| *\| *$/g, '')
18767 this.tokens.push(item);
18772 // top-level paragraph
18773 if (top && (cap = this.rules.paragraph.exec(src))) {
18774 src = src.substring(cap[0].length);
18777 text: cap[1].charAt(cap[1].length - 1) === '\n'
18778 ? cap[1].slice(0, -1)
18785 if (cap = this.rules.text.exec(src)) {
18786 // Top-level should never reach here.
18787 src = src.substring(cap[0].length);
18797 Error('Infinite loop on byte: ' + src.charCodeAt(0));
18801 return this.tokens;
18805 * Inline-Level Grammar
18809 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
18810 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
18812 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
18813 link: /^!?\[(inside)\]\(href\)/,
18814 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
18815 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
18816 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
18817 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
18818 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
18819 br: /^ {2,}\n(?!\s*$)/,
18821 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
18824 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
18825 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
18827 inline.link = replace(inline.link)
18828 ('inside', inline._inside)
18829 ('href', inline._href)
18832 inline.reflink = replace(inline.reflink)
18833 ('inside', inline._inside)
18837 * Normal Inline Grammar
18840 inline.normal = merge({}, inline);
18843 * Pedantic Inline Grammar
18846 inline.pedantic = merge({}, inline.normal, {
18847 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
18848 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
18852 * GFM Inline Grammar
18855 inline.gfm = merge({}, inline.normal, {
18856 escape: replace(inline.escape)('])', '~|])')(),
18857 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
18858 del: /^~~(?=\S)([\s\S]*?\S)~~/,
18859 text: replace(inline.text)
18861 ('|', '|https?://|')
18866 * GFM + Line Breaks Inline Grammar
18869 inline.breaks = merge({}, inline.gfm, {
18870 br: replace(inline.br)('{2,}', '*')(),
18871 text: replace(inline.gfm.text)('{2,}', '*')()
18875 * Inline Lexer & Compiler
18878 var InlineLexer = function (links, options) {
18879 this.options = options || marked.defaults;
18880 this.links = links;
18881 this.rules = inline.normal;
18882 this.renderer = this.options.renderer || new Renderer;
18883 this.renderer.options = this.options;
18887 Error('Tokens array requires a `links` property.');
18890 if (this.options.gfm) {
18891 if (this.options.breaks) {
18892 this.rules = inline.breaks;
18894 this.rules = inline.gfm;
18896 } else if (this.options.pedantic) {
18897 this.rules = inline.pedantic;
18902 * Expose Inline Rules
18905 InlineLexer.rules = inline;
18908 * Static Lexing/Compiling Method
18911 InlineLexer.output = function(src, links, options) {
18912 var inline = new InlineLexer(links, options);
18913 return inline.output(src);
18920 InlineLexer.prototype.output = function(src) {
18929 if (cap = this.rules.escape.exec(src)) {
18930 src = src.substring(cap[0].length);
18936 if (cap = this.rules.autolink.exec(src)) {
18937 src = src.substring(cap[0].length);
18938 if (cap[2] === '@') {
18939 text = cap[1].charAt(6) === ':'
18940 ? this.mangle(cap[1].substring(7))
18941 : this.mangle(cap[1]);
18942 href = this.mangle('mailto:') + text;
18944 text = escape(cap[1]);
18947 out += this.renderer.link(href, null, text);
18952 if (!this.inLink && (cap = this.rules.url.exec(src))) {
18953 src = src.substring(cap[0].length);
18954 text = escape(cap[1]);
18956 out += this.renderer.link(href, null, text);
18961 if (cap = this.rules.tag.exec(src)) {
18962 if (!this.inLink && /^<a /i.test(cap[0])) {
18963 this.inLink = true;
18964 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
18965 this.inLink = false;
18967 src = src.substring(cap[0].length);
18968 out += this.options.sanitize
18969 ? this.options.sanitizer
18970 ? this.options.sanitizer(cap[0])
18977 if (cap = this.rules.link.exec(src)) {
18978 src = src.substring(cap[0].length);
18979 this.inLink = true;
18980 out += this.outputLink(cap, {
18984 this.inLink = false;
18989 if ((cap = this.rules.reflink.exec(src))
18990 || (cap = this.rules.nolink.exec(src))) {
18991 src = src.substring(cap[0].length);
18992 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
18993 link = this.links[link.toLowerCase()];
18994 if (!link || !link.href) {
18995 out += cap[0].charAt(0);
18996 src = cap[0].substring(1) + src;
18999 this.inLink = true;
19000 out += this.outputLink(cap, link);
19001 this.inLink = false;
19006 if (cap = this.rules.strong.exec(src)) {
19007 src = src.substring(cap[0].length);
19008 out += this.renderer.strong(this.output(cap[2] || cap[1]));
19013 if (cap = this.rules.em.exec(src)) {
19014 src = src.substring(cap[0].length);
19015 out += this.renderer.em(this.output(cap[2] || cap[1]));
19020 if (cap = this.rules.code.exec(src)) {
19021 src = src.substring(cap[0].length);
19022 out += this.renderer.codespan(escape(cap[2], true));
19027 if (cap = this.rules.br.exec(src)) {
19028 src = src.substring(cap[0].length);
19029 out += this.renderer.br();
19034 if (cap = this.rules.del.exec(src)) {
19035 src = src.substring(cap[0].length);
19036 out += this.renderer.del(this.output(cap[1]));
19041 if (cap = this.rules.text.exec(src)) {
19042 src = src.substring(cap[0].length);
19043 out += this.renderer.text(escape(this.smartypants(cap[0])));
19049 Error('Infinite loop on byte: ' + src.charCodeAt(0));
19060 InlineLexer.prototype.outputLink = function(cap, link) {
19061 var href = escape(link.href)
19062 , title = link.title ? escape(link.title) : null;
19064 return cap[0].charAt(0) !== '!'
19065 ? this.renderer.link(href, title, this.output(cap[1]))
19066 : this.renderer.image(href, title, escape(cap[1]));
19070 * Smartypants Transformations
19073 InlineLexer.prototype.smartypants = function(text) {
19074 if (!this.options.smartypants) { return text; }
19077 .replace(/---/g, '\u2014')
19079 .replace(/--/g, '\u2013')
19081 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
19082 // closing singles & apostrophes
19083 .replace(/'/g, '\u2019')
19085 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
19087 .replace(/"/g, '\u201d')
19089 .replace(/\.{3}/g, '\u2026');
19096 InlineLexer.prototype.mangle = function(text) {
19097 if (!this.options.mangle) { return text; }
19103 for (; i < l; i++) {
19104 ch = text.charCodeAt(i);
19105 if (Math.random() > 0.5) {
19106 ch = 'x' + ch.toString(16);
19108 out += '&#' + ch + ';';
19119 * eval:var:Renderer
19122 var Renderer = function (options) {
19123 this.options = options || {};
19126 Renderer.prototype.code = function(code, lang, escaped) {
19127 if (this.options.highlight) {
19128 var out = this.options.highlight(code, lang);
19129 if (out != null && out !== code) {
19134 // hack!!! - it's already escapeD?
19139 return '<pre><code>'
19140 + (escaped ? code : escape(code, true))
19141 + '\n</code></pre>';
19144 return '<pre><code class="'
19145 + this.options.langPrefix
19146 + escape(lang, true)
19148 + (escaped ? code : escape(code, true))
19149 + '\n</code></pre>\n';
19152 Renderer.prototype.blockquote = function(quote) {
19153 return '<blockquote>\n' + quote + '</blockquote>\n';
19156 Renderer.prototype.html = function(html) {
19160 Renderer.prototype.heading = function(text, level, raw) {
19164 + this.options.headerPrefix
19165 + raw.toLowerCase().replace(/[^\w]+/g, '-')
19173 Renderer.prototype.hr = function() {
19174 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
19177 Renderer.prototype.list = function(body, ordered) {
19178 var type = ordered ? 'ol' : 'ul';
19179 return '<' + type + '>\n' + body + '</' + type + '>\n';
19182 Renderer.prototype.listitem = function(text) {
19183 return '<li>' + text + '</li>\n';
19186 Renderer.prototype.paragraph = function(text) {
19187 return '<p>' + text + '</p>\n';
19190 Renderer.prototype.table = function(header, body) {
19191 return '<table class="table table-striped">\n'
19201 Renderer.prototype.tablerow = function(content) {
19202 return '<tr>\n' + content + '</tr>\n';
19205 Renderer.prototype.tablecell = function(content, flags) {
19206 var type = flags.header ? 'th' : 'td';
19207 var tag = flags.align
19208 ? '<' + type + ' style="text-align:' + flags.align + '">'
19209 : '<' + type + '>';
19210 return tag + content + '</' + type + '>\n';
19213 // span level renderer
19214 Renderer.prototype.strong = function(text) {
19215 return '<strong>' + text + '</strong>';
19218 Renderer.prototype.em = function(text) {
19219 return '<em>' + text + '</em>';
19222 Renderer.prototype.codespan = function(text) {
19223 return '<code>' + text + '</code>';
19226 Renderer.prototype.br = function() {
19227 return this.options.xhtml ? '<br/>' : '<br>';
19230 Renderer.prototype.del = function(text) {
19231 return '<del>' + text + '</del>';
19234 Renderer.prototype.link = function(href, title, text) {
19235 if (this.options.sanitize) {
19237 var prot = decodeURIComponent(unescape(href))
19238 .replace(/[^\w:]/g, '')
19243 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
19247 var out = '<a href="' + href + '"';
19249 out += ' title="' + title + '"';
19251 out += '>' + text + '</a>';
19255 Renderer.prototype.image = function(href, title, text) {
19256 var out = '<img src="' + href + '" alt="' + text + '"';
19258 out += ' title="' + title + '"';
19260 out += this.options.xhtml ? '/>' : '>';
19264 Renderer.prototype.text = function(text) {
19269 * Parsing & Compiling
19275 var Parser= function (options) {
19278 this.options = options || marked.defaults;
19279 this.options.renderer = this.options.renderer || new Renderer;
19280 this.renderer = this.options.renderer;
19281 this.renderer.options = this.options;
19285 * Static Parse Method
19288 Parser.parse = function(src, options, renderer) {
19289 var parser = new Parser(options, renderer);
19290 return parser.parse(src);
19297 Parser.prototype.parse = function(src) {
19298 this.inline = new InlineLexer(src.links, this.options, this.renderer);
19299 this.tokens = src.reverse();
19302 while (this.next()) {
19313 Parser.prototype.next = function() {
19314 return this.token = this.tokens.pop();
19318 * Preview Next Token
19321 Parser.prototype.peek = function() {
19322 return this.tokens[this.tokens.length - 1] || 0;
19326 * Parse Text Tokens
19329 Parser.prototype.parseText = function() {
19330 var body = this.token.text;
19332 while (this.peek().type === 'text') {
19333 body += '\n' + this.next().text;
19336 return this.inline.output(body);
19340 * Parse Current Token
19343 Parser.prototype.tok = function() {
19344 switch (this.token.type) {
19349 return this.renderer.hr();
19352 return this.renderer.heading(
19353 this.inline.output(this.token.text),
19358 return this.renderer.code(this.token.text,
19360 this.token.escaped);
19373 for (i = 0; i < this.token.header.length; i++) {
19374 flags = { header: true, align: this.token.align[i] };
19375 cell += this.renderer.tablecell(
19376 this.inline.output(this.token.header[i]),
19377 { header: true, align: this.token.align[i] }
19380 header += this.renderer.tablerow(cell);
19382 for (i = 0; i < this.token.cells.length; i++) {
19383 row = this.token.cells[i];
19386 for (j = 0; j < row.length; j++) {
19387 cell += this.renderer.tablecell(
19388 this.inline.output(row[j]),
19389 { header: false, align: this.token.align[j] }
19393 body += this.renderer.tablerow(cell);
19395 return this.renderer.table(header, body);
19397 case 'blockquote_start': {
19400 while (this.next().type !== 'blockquote_end') {
19401 body += this.tok();
19404 return this.renderer.blockquote(body);
19406 case 'list_start': {
19408 , ordered = this.token.ordered;
19410 while (this.next().type !== 'list_end') {
19411 body += this.tok();
19414 return this.renderer.list(body, ordered);
19416 case 'list_item_start': {
19419 while (this.next().type !== 'list_item_end') {
19420 body += this.token.type === 'text'
19425 return this.renderer.listitem(body);
19427 case 'loose_item_start': {
19430 while (this.next().type !== 'list_item_end') {
19431 body += this.tok();
19434 return this.renderer.listitem(body);
19437 var html = !this.token.pre && !this.options.pedantic
19438 ? this.inline.output(this.token.text)
19440 return this.renderer.html(html);
19442 case 'paragraph': {
19443 return this.renderer.paragraph(this.inline.output(this.token.text));
19446 return this.renderer.paragraph(this.parseText());
19458 var marked = function (src, opt, callback) {
19459 if (callback || typeof opt === 'function') {
19465 opt = merge({}, marked.defaults, opt || {});
19467 var highlight = opt.highlight
19473 tokens = Lexer.lex(src, opt)
19475 return callback(e);
19478 pending = tokens.length;
19482 var done = function(err) {
19484 opt.highlight = highlight;
19485 return callback(err);
19491 out = Parser.parse(tokens, opt);
19496 opt.highlight = highlight;
19500 : callback(null, out);
19503 if (!highlight || highlight.length < 3) {
19507 delete opt.highlight;
19509 if (!pending) { return done(); }
19511 for (; i < tokens.length; i++) {
19513 if (token.type !== 'code') {
19514 return --pending || done();
19516 return highlight(token.text, token.lang, function(err, code) {
19517 if (err) { return done(err); }
19518 if (code == null || code === token.text) {
19519 return --pending || done();
19522 token.escaped = true;
19523 --pending || done();
19531 if (opt) { opt = merge({}, marked.defaults, opt); }
19532 return Parser.parse(Lexer.lex(src, opt), opt);
19534 e.message += '\nPlease report this to https://github.com/chjj/marked.';
19535 if ((opt || marked.defaults).silent) {
19536 return '<p>An error occured:</p><pre>'
19537 + escape(e.message + '', true)
19549 marked.setOptions = function(opt) {
19550 merge(marked.defaults, opt);
19554 marked.defaults = {
19565 langPrefix: 'lang-',
19566 smartypants: false,
19568 renderer: new Renderer,
19576 marked.Parser = Parser;
19577 marked.parser = Parser.parse;
19579 marked.Renderer = Renderer;
19581 marked.Lexer = Lexer;
19582 marked.lexer = Lexer.lex;
19584 marked.InlineLexer = InlineLexer;
19585 marked.inlineLexer = InlineLexer.output;
19587 marked.parse = marked;
19589 Roo.Markdown.marked = marked;
19593 * Ext JS Library 1.1.1
19594 * Copyright(c) 2006-2007, Ext JS, LLC.
19596 * Originally Released Under LGPL - original licence link has changed is not relivant.
19599 * <script type="text/javascript">
19605 * These classes are derivatives of the similarly named classes in the YUI Library.
19606 * The original license:
19607 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
19608 * Code licensed under the BSD License:
19609 * http://developer.yahoo.net/yui/license.txt
19614 var Event=Roo.EventManager;
19615 var Dom=Roo.lib.Dom;
19618 * @class Roo.dd.DragDrop
19619 * @extends Roo.util.Observable
19620 * Defines the interface and base operation of items that that can be
19621 * dragged or can be drop targets. It was designed to be extended, overriding
19622 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
19623 * Up to three html elements can be associated with a DragDrop instance:
19625 * <li>linked element: the element that is passed into the constructor.
19626 * This is the element which defines the boundaries for interaction with
19627 * other DragDrop objects.</li>
19628 * <li>handle element(s): The drag operation only occurs if the element that
19629 * was clicked matches a handle element. By default this is the linked
19630 * element, but there are times that you will want only a portion of the
19631 * linked element to initiate the drag operation, and the setHandleElId()
19632 * method provides a way to define this.</li>
19633 * <li>drag element: this represents the element that would be moved along
19634 * with the cursor during a drag operation. By default, this is the linked
19635 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
19636 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
19639 * This class should not be instantiated until the onload event to ensure that
19640 * the associated elements are available.
19641 * The following would define a DragDrop obj that would interact with any
19642 * other DragDrop obj in the "group1" group:
19644 * dd = new Roo.dd.DragDrop("div1", "group1");
19646 * Since none of the event handlers have been implemented, nothing would
19647 * actually happen if you were to run the code above. Normally you would
19648 * override this class or one of the default implementations, but you can
19649 * also override the methods you want on an instance of the class...
19651 * dd.onDragDrop = function(e, id) {
19652 * alert("dd was dropped on " + id);
19656 * @param {String} id of the element that is linked to this instance
19657 * @param {String} sGroup the group of related DragDrop objects
19658 * @param {object} config an object containing configurable attributes
19659 * Valid properties for DragDrop:
19660 * padding, isTarget, maintainOffset, primaryButtonOnly
19662 Roo.dd.DragDrop = function(id, sGroup, config) {
19664 this.init(id, sGroup, config);
19669 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
19672 * The id of the element associated with this object. This is what we
19673 * refer to as the "linked element" because the size and position of
19674 * this element is used to determine when the drag and drop objects have
19682 * Configuration attributes passed into the constructor
19689 * The id of the element that will be dragged. By default this is same
19690 * as the linked element , but could be changed to another element. Ex:
19692 * @property dragElId
19699 * the id of the element that initiates the drag operation. By default
19700 * this is the linked element, but could be changed to be a child of this
19701 * element. This lets us do things like only starting the drag when the
19702 * header element within the linked html element is clicked.
19703 * @property handleElId
19710 * An associative array of HTML tags that will be ignored if clicked.
19711 * @property invalidHandleTypes
19712 * @type {string: string}
19714 invalidHandleTypes: null,
19717 * An associative array of ids for elements that will be ignored if clicked
19718 * @property invalidHandleIds
19719 * @type {string: string}
19721 invalidHandleIds: null,
19724 * An indexted array of css class names for elements that will be ignored
19726 * @property invalidHandleClasses
19729 invalidHandleClasses: null,
19732 * The linked element's absolute X position at the time the drag was
19734 * @property startPageX
19741 * The linked element's absolute X position at the time the drag was
19743 * @property startPageY
19750 * The group defines a logical collection of DragDrop objects that are
19751 * related. Instances only get events when interacting with other
19752 * DragDrop object in the same group. This lets us define multiple
19753 * groups using a single DragDrop subclass if we want.
19755 * @type {string: string}
19760 * Individual drag/drop instances can be locked. This will prevent
19761 * onmousedown start drag.
19769 * Lock this instance
19772 lock: function() { this.locked = true; },
19775 * Unlock this instace
19778 unlock: function() { this.locked = false; },
19781 * By default, all insances can be a drop target. This can be disabled by
19782 * setting isTarget to false.
19789 * The padding configured for this drag and drop object for calculating
19790 * the drop zone intersection with this object.
19797 * Cached reference to the linked element
19798 * @property _domRef
19804 * Internal typeof flag
19805 * @property __ygDragDrop
19808 __ygDragDrop: true,
19811 * Set to true when horizontal contraints are applied
19812 * @property constrainX
19819 * Set to true when vertical contraints are applied
19820 * @property constrainY
19827 * The left constraint
19835 * The right constraint
19843 * The up constraint
19852 * The down constraint
19860 * Maintain offsets when we resetconstraints. Set to true when you want
19861 * the position of the element relative to its parent to stay the same
19862 * when the page changes
19864 * @property maintainOffset
19867 maintainOffset: false,
19870 * Array of pixel locations the element will snap to if we specified a
19871 * horizontal graduation/interval. This array is generated automatically
19872 * when you define a tick interval.
19879 * Array of pixel locations the element will snap to if we specified a
19880 * vertical graduation/interval. This array is generated automatically
19881 * when you define a tick interval.
19888 * By default the drag and drop instance will only respond to the primary
19889 * button click (left button for a right-handed mouse). Set to true to
19890 * allow drag and drop to start with any mouse click that is propogated
19892 * @property primaryButtonOnly
19895 primaryButtonOnly: true,
19898 * The availabe property is false until the linked dom element is accessible.
19899 * @property available
19905 * By default, drags can only be initiated if the mousedown occurs in the
19906 * region the linked element is. This is done in part to work around a
19907 * bug in some browsers that mis-report the mousedown if the previous
19908 * mouseup happened outside of the window. This property is set to true
19909 * if outer handles are defined.
19911 * @property hasOuterHandles
19915 hasOuterHandles: false,
19918 * Code that executes immediately before the startDrag event
19919 * @method b4StartDrag
19922 b4StartDrag: function(x, y) { },
19925 * Abstract method called after a drag/drop object is clicked
19926 * and the drag or mousedown time thresholds have beeen met.
19927 * @method startDrag
19928 * @param {int} X click location
19929 * @param {int} Y click location
19931 startDrag: function(x, y) { /* override this */ },
19934 * Code that executes immediately before the onDrag event
19938 b4Drag: function(e) { },
19941 * Abstract method called during the onMouseMove event while dragging an
19944 * @param {Event} e the mousemove event
19946 onDrag: function(e) { /* override this */ },
19949 * Abstract method called when this element fist begins hovering over
19950 * another DragDrop obj
19951 * @method onDragEnter
19952 * @param {Event} e the mousemove event
19953 * @param {String|DragDrop[]} id In POINT mode, the element
19954 * id this is hovering over. In INTERSECT mode, an array of one or more
19955 * dragdrop items being hovered over.
19957 onDragEnter: function(e, id) { /* override this */ },
19960 * Code that executes immediately before the onDragOver event
19961 * @method b4DragOver
19964 b4DragOver: function(e) { },
19967 * Abstract method called when this element is hovering over another
19969 * @method onDragOver
19970 * @param {Event} e the mousemove event
19971 * @param {String|DragDrop[]} id In POINT mode, the element
19972 * id this is hovering over. In INTERSECT mode, an array of dd items
19973 * being hovered over.
19975 onDragOver: function(e, id) { /* override this */ },
19978 * Code that executes immediately before the onDragOut event
19979 * @method b4DragOut
19982 b4DragOut: function(e) { },
19985 * Abstract method called when we are no longer hovering over an element
19986 * @method onDragOut
19987 * @param {Event} e the mousemove event
19988 * @param {String|DragDrop[]} id In POINT mode, the element
19989 * id this was hovering over. In INTERSECT mode, an array of dd items
19990 * that the mouse is no longer over.
19992 onDragOut: function(e, id) { /* override this */ },
19995 * Code that executes immediately before the onDragDrop event
19996 * @method b4DragDrop
19999 b4DragDrop: function(e) { },
20002 * Abstract method called when this item is dropped on another DragDrop
20004 * @method onDragDrop
20005 * @param {Event} e the mouseup event
20006 * @param {String|DragDrop[]} id In POINT mode, the element
20007 * id this was dropped on. In INTERSECT mode, an array of dd items this
20010 onDragDrop: function(e, id) { /* override this */ },
20013 * Abstract method called when this item is dropped on an area with no
20015 * @method onInvalidDrop
20016 * @param {Event} e the mouseup event
20018 onInvalidDrop: function(e) { /* override this */ },
20021 * Code that executes immediately before the endDrag event
20022 * @method b4EndDrag
20025 b4EndDrag: function(e) { },
20028 * Fired when we are done dragging the object
20030 * @param {Event} e the mouseup event
20032 endDrag: function(e) { /* override this */ },
20035 * Code executed immediately before the onMouseDown event
20036 * @method b4MouseDown
20037 * @param {Event} e the mousedown event
20040 b4MouseDown: function(e) { },
20043 * Event handler that fires when a drag/drop obj gets a mousedown
20044 * @method onMouseDown
20045 * @param {Event} e the mousedown event
20047 onMouseDown: function(e) { /* override this */ },
20050 * Event handler that fires when a drag/drop obj gets a mouseup
20051 * @method onMouseUp
20052 * @param {Event} e the mouseup event
20054 onMouseUp: function(e) { /* override this */ },
20057 * Override the onAvailable method to do what is needed after the initial
20058 * position was determined.
20059 * @method onAvailable
20061 onAvailable: function () {
20065 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
20068 defaultPadding : {left:0, right:0, top:0, bottom:0},
20071 * Initializes the drag drop object's constraints to restrict movement to a certain element.
20075 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
20076 { dragElId: "existingProxyDiv" });
20077 dd.startDrag = function(){
20078 this.constrainTo("parent-id");
20081 * Or you can initalize it using the {@link Roo.Element} object:
20083 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
20084 startDrag : function(){
20085 this.constrainTo("parent-id");
20089 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
20090 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
20091 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
20092 * an object containing the sides to pad. For example: {right:10, bottom:10}
20093 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
20095 constrainTo : function(constrainTo, pad, inContent){
20096 if(typeof pad == "number"){
20097 pad = {left: pad, right:pad, top:pad, bottom:pad};
20099 pad = pad || this.defaultPadding;
20100 var b = Roo.get(this.getEl()).getBox();
20101 var ce = Roo.get(constrainTo);
20102 var s = ce.getScroll();
20103 var c, cd = ce.dom;
20104 if(cd == document.body){
20105 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
20108 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
20112 var topSpace = b.y - c.y;
20113 var leftSpace = b.x - c.x;
20115 this.resetConstraints();
20116 this.setXConstraint(leftSpace - (pad.left||0), // left
20117 c.width - leftSpace - b.width - (pad.right||0) //right
20119 this.setYConstraint(topSpace - (pad.top||0), //top
20120 c.height - topSpace - b.height - (pad.bottom||0) //bottom
20125 * Returns a reference to the linked element
20127 * @return {HTMLElement} the html element
20129 getEl: function() {
20130 if (!this._domRef) {
20131 this._domRef = Roo.getDom(this.id);
20134 return this._domRef;
20138 * Returns a reference to the actual element to drag. By default this is
20139 * the same as the html element, but it can be assigned to another
20140 * element. An example of this can be found in Roo.dd.DDProxy
20141 * @method getDragEl
20142 * @return {HTMLElement} the html element
20144 getDragEl: function() {
20145 return Roo.getDom(this.dragElId);
20149 * Sets up the DragDrop object. Must be called in the constructor of any
20150 * Roo.dd.DragDrop subclass
20152 * @param id the id of the linked element
20153 * @param {String} sGroup the group of related items
20154 * @param {object} config configuration attributes
20156 init: function(id, sGroup, config) {
20157 this.initTarget(id, sGroup, config);
20158 if (!Roo.isTouch) {
20159 Event.on(this.id, "mousedown", this.handleMouseDown, this);
20161 Event.on(this.id, "touchstart", this.handleMouseDown, this);
20162 // Event.on(this.id, "selectstart", Event.preventDefault);
20166 * Initializes Targeting functionality only... the object does not
20167 * get a mousedown handler.
20168 * @method initTarget
20169 * @param id the id of the linked element
20170 * @param {String} sGroup the group of related items
20171 * @param {object} config configuration attributes
20173 initTarget: function(id, sGroup, config) {
20175 // configuration attributes
20176 this.config = config || {};
20178 // create a local reference to the drag and drop manager
20179 this.DDM = Roo.dd.DDM;
20180 // initialize the groups array
20183 // assume that we have an element reference instead of an id if the
20184 // parameter is not a string
20185 if (typeof id !== "string") {
20192 // add to an interaction group
20193 this.addToGroup((sGroup) ? sGroup : "default");
20195 // We don't want to register this as the handle with the manager
20196 // so we just set the id rather than calling the setter.
20197 this.handleElId = id;
20199 // the linked element is the element that gets dragged by default
20200 this.setDragElId(id);
20202 // by default, clicked anchors will not start drag operations.
20203 this.invalidHandleTypes = { A: "A" };
20204 this.invalidHandleIds = {};
20205 this.invalidHandleClasses = [];
20207 this.applyConfig();
20209 this.handleOnAvailable();
20213 * Applies the configuration parameters that were passed into the constructor.
20214 * This is supposed to happen at each level through the inheritance chain. So
20215 * a DDProxy implentation will execute apply config on DDProxy, DD, and
20216 * DragDrop in order to get all of the parameters that are available in
20218 * @method applyConfig
20220 applyConfig: function() {
20222 // configurable properties:
20223 // padding, isTarget, maintainOffset, primaryButtonOnly
20224 this.padding = this.config.padding || [0, 0, 0, 0];
20225 this.isTarget = (this.config.isTarget !== false);
20226 this.maintainOffset = (this.config.maintainOffset);
20227 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
20232 * Executed when the linked element is available
20233 * @method handleOnAvailable
20236 handleOnAvailable: function() {
20237 this.available = true;
20238 this.resetConstraints();
20239 this.onAvailable();
20243 * Configures the padding for the target zone in px. Effectively expands
20244 * (or reduces) the virtual object size for targeting calculations.
20245 * Supports css-style shorthand; if only one parameter is passed, all sides
20246 * will have that padding, and if only two are passed, the top and bottom
20247 * will have the first param, the left and right the second.
20248 * @method setPadding
20249 * @param {int} iTop Top pad
20250 * @param {int} iRight Right pad
20251 * @param {int} iBot Bot pad
20252 * @param {int} iLeft Left pad
20254 setPadding: function(iTop, iRight, iBot, iLeft) {
20255 // this.padding = [iLeft, iRight, iTop, iBot];
20256 if (!iRight && 0 !== iRight) {
20257 this.padding = [iTop, iTop, iTop, iTop];
20258 } else if (!iBot && 0 !== iBot) {
20259 this.padding = [iTop, iRight, iTop, iRight];
20261 this.padding = [iTop, iRight, iBot, iLeft];
20266 * Stores the initial placement of the linked element.
20267 * @method setInitialPosition
20268 * @param {int} diffX the X offset, default 0
20269 * @param {int} diffY the Y offset, default 0
20271 setInitPosition: function(diffX, diffY) {
20272 var el = this.getEl();
20274 if (!this.DDM.verifyEl(el)) {
20278 var dx = diffX || 0;
20279 var dy = diffY || 0;
20281 var p = Dom.getXY( el );
20283 this.initPageX = p[0] - dx;
20284 this.initPageY = p[1] - dy;
20286 this.lastPageX = p[0];
20287 this.lastPageY = p[1];
20290 this.setStartPosition(p);
20294 * Sets the start position of the element. This is set when the obj
20295 * is initialized, the reset when a drag is started.
20296 * @method setStartPosition
20297 * @param pos current position (from previous lookup)
20300 setStartPosition: function(pos) {
20301 var p = pos || Dom.getXY( this.getEl() );
20302 this.deltaSetXY = null;
20304 this.startPageX = p[0];
20305 this.startPageY = p[1];
20309 * Add this instance to a group of related drag/drop objects. All
20310 * instances belong to at least one group, and can belong to as many
20311 * groups as needed.
20312 * @method addToGroup
20313 * @param sGroup {string} the name of the group
20315 addToGroup: function(sGroup) {
20316 this.groups[sGroup] = true;
20317 this.DDM.regDragDrop(this, sGroup);
20321 * Remove's this instance from the supplied interaction group
20322 * @method removeFromGroup
20323 * @param {string} sGroup The group to drop
20325 removeFromGroup: function(sGroup) {
20326 if (this.groups[sGroup]) {
20327 delete this.groups[sGroup];
20330 this.DDM.removeDDFromGroup(this, sGroup);
20334 * Allows you to specify that an element other than the linked element
20335 * will be moved with the cursor during a drag
20336 * @method setDragElId
20337 * @param id {string} the id of the element that will be used to initiate the drag
20339 setDragElId: function(id) {
20340 this.dragElId = id;
20344 * Allows you to specify a child of the linked element that should be
20345 * used to initiate the drag operation. An example of this would be if
20346 * you have a content div with text and links. Clicking anywhere in the
20347 * content area would normally start the drag operation. Use this method
20348 * to specify that an element inside of the content div is the element
20349 * that starts the drag operation.
20350 * @method setHandleElId
20351 * @param id {string} the id of the element that will be used to
20352 * initiate the drag.
20354 setHandleElId: function(id) {
20355 if (typeof id !== "string") {
20358 this.handleElId = id;
20359 this.DDM.regHandle(this.id, id);
20363 * Allows you to set an element outside of the linked element as a drag
20365 * @method setOuterHandleElId
20366 * @param id the id of the element that will be used to initiate the drag
20368 setOuterHandleElId: function(id) {
20369 if (typeof id !== "string") {
20372 Event.on(id, "mousedown",
20373 this.handleMouseDown, this);
20374 this.setHandleElId(id);
20376 this.hasOuterHandles = true;
20380 * Remove all drag and drop hooks for this element
20383 unreg: function() {
20384 Event.un(this.id, "mousedown",
20385 this.handleMouseDown);
20386 Event.un(this.id, "touchstart",
20387 this.handleMouseDown);
20388 this._domRef = null;
20389 this.DDM._remove(this);
20392 destroy : function(){
20397 * Returns true if this instance is locked, or the drag drop mgr is locked
20398 * (meaning that all drag/drop is disabled on the page.)
20400 * @return {boolean} true if this obj or all drag/drop is locked, else
20403 isLocked: function() {
20404 return (this.DDM.isLocked() || this.locked);
20408 * Fired when this object is clicked
20409 * @method handleMouseDown
20411 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
20414 handleMouseDown: function(e, oDD){
20416 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
20417 //Roo.log('not touch/ button !=0');
20420 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
20421 return; // double touch..
20425 if (this.isLocked()) {
20426 //Roo.log('locked');
20430 this.DDM.refreshCache(this.groups);
20431 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
20432 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
20433 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
20434 //Roo.log('no outer handes or not over target');
20437 // Roo.log('check validator');
20438 if (this.clickValidator(e)) {
20439 // Roo.log('validate success');
20440 // set the initial element position
20441 this.setStartPosition();
20444 this.b4MouseDown(e);
20445 this.onMouseDown(e);
20447 this.DDM.handleMouseDown(e, this);
20449 this.DDM.stopEvent(e);
20457 clickValidator: function(e) {
20458 var target = e.getTarget();
20459 return ( this.isValidHandleChild(target) &&
20460 (this.id == this.handleElId ||
20461 this.DDM.handleWasClicked(target, this.id)) );
20465 * Allows you to specify a tag name that should not start a drag operation
20466 * when clicked. This is designed to facilitate embedding links within a
20467 * drag handle that do something other than start the drag.
20468 * @method addInvalidHandleType
20469 * @param {string} tagName the type of element to exclude
20471 addInvalidHandleType: function(tagName) {
20472 var type = tagName.toUpperCase();
20473 this.invalidHandleTypes[type] = type;
20477 * Lets you to specify an element id for a child of a drag handle
20478 * that should not initiate a drag
20479 * @method addInvalidHandleId
20480 * @param {string} id the element id of the element you wish to ignore
20482 addInvalidHandleId: function(id) {
20483 if (typeof id !== "string") {
20486 this.invalidHandleIds[id] = id;
20490 * Lets you specify a css class of elements that will not initiate a drag
20491 * @method addInvalidHandleClass
20492 * @param {string} cssClass the class of the elements you wish to ignore
20494 addInvalidHandleClass: function(cssClass) {
20495 this.invalidHandleClasses.push(cssClass);
20499 * Unsets an excluded tag name set by addInvalidHandleType
20500 * @method removeInvalidHandleType
20501 * @param {string} tagName the type of element to unexclude
20503 removeInvalidHandleType: function(tagName) {
20504 var type = tagName.toUpperCase();
20505 // this.invalidHandleTypes[type] = null;
20506 delete this.invalidHandleTypes[type];
20510 * Unsets an invalid handle id
20511 * @method removeInvalidHandleId
20512 * @param {string} id the id of the element to re-enable
20514 removeInvalidHandleId: function(id) {
20515 if (typeof id !== "string") {
20518 delete this.invalidHandleIds[id];
20522 * Unsets an invalid css class
20523 * @method removeInvalidHandleClass
20524 * @param {string} cssClass the class of the element(s) you wish to
20527 removeInvalidHandleClass: function(cssClass) {
20528 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
20529 if (this.invalidHandleClasses[i] == cssClass) {
20530 delete this.invalidHandleClasses[i];
20536 * Checks the tag exclusion list to see if this click should be ignored
20537 * @method isValidHandleChild
20538 * @param {HTMLElement} node the HTMLElement to evaluate
20539 * @return {boolean} true if this is a valid tag type, false if not
20541 isValidHandleChild: function(node) {
20544 // var n = (node.nodeName == "#text") ? node.parentNode : node;
20547 nodeName = node.nodeName.toUpperCase();
20549 nodeName = node.nodeName;
20551 valid = valid && !this.invalidHandleTypes[nodeName];
20552 valid = valid && !this.invalidHandleIds[node.id];
20554 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
20555 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
20564 * Create the array of horizontal tick marks if an interval was specified
20565 * in setXConstraint().
20566 * @method setXTicks
20569 setXTicks: function(iStartX, iTickSize) {
20571 this.xTickSize = iTickSize;
20575 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
20577 this.xTicks[this.xTicks.length] = i;
20582 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
20584 this.xTicks[this.xTicks.length] = i;
20589 this.xTicks.sort(this.DDM.numericSort) ;
20593 * Create the array of vertical tick marks if an interval was specified in
20594 * setYConstraint().
20595 * @method setYTicks
20598 setYTicks: function(iStartY, iTickSize) {
20600 this.yTickSize = iTickSize;
20604 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
20606 this.yTicks[this.yTicks.length] = i;
20611 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
20613 this.yTicks[this.yTicks.length] = i;
20618 this.yTicks.sort(this.DDM.numericSort) ;
20622 * By default, the element can be dragged any place on the screen. Use
20623 * this method to limit the horizontal travel of the element. Pass in
20624 * 0,0 for the parameters if you want to lock the drag to the y axis.
20625 * @method setXConstraint
20626 * @param {int} iLeft the number of pixels the element can move to the left
20627 * @param {int} iRight the number of pixels the element can move to the
20629 * @param {int} iTickSize optional parameter for specifying that the
20631 * should move iTickSize pixels at a time.
20633 setXConstraint: function(iLeft, iRight, iTickSize) {
20634 this.leftConstraint = iLeft;
20635 this.rightConstraint = iRight;
20637 this.minX = this.initPageX - iLeft;
20638 this.maxX = this.initPageX + iRight;
20639 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
20641 this.constrainX = true;
20645 * Clears any constraints applied to this instance. Also clears ticks
20646 * since they can't exist independent of a constraint at this time.
20647 * @method clearConstraints
20649 clearConstraints: function() {
20650 this.constrainX = false;
20651 this.constrainY = false;
20656 * Clears any tick interval defined for this instance
20657 * @method clearTicks
20659 clearTicks: function() {
20660 this.xTicks = null;
20661 this.yTicks = null;
20662 this.xTickSize = 0;
20663 this.yTickSize = 0;
20667 * By default, the element can be dragged any place on the screen. Set
20668 * this to limit the vertical travel of the element. Pass in 0,0 for the
20669 * parameters if you want to lock the drag to the x axis.
20670 * @method setYConstraint
20671 * @param {int} iUp the number of pixels the element can move up
20672 * @param {int} iDown the number of pixels the element can move down
20673 * @param {int} iTickSize optional parameter for specifying that the
20674 * element should move iTickSize pixels at a time.
20676 setYConstraint: function(iUp, iDown, iTickSize) {
20677 this.topConstraint = iUp;
20678 this.bottomConstraint = iDown;
20680 this.minY = this.initPageY - iUp;
20681 this.maxY = this.initPageY + iDown;
20682 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
20684 this.constrainY = true;
20689 * resetConstraints must be called if you manually reposition a dd element.
20690 * @method resetConstraints
20691 * @param {boolean} maintainOffset
20693 resetConstraints: function() {
20696 // Maintain offsets if necessary
20697 if (this.initPageX || this.initPageX === 0) {
20698 // figure out how much this thing has moved
20699 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
20700 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
20702 this.setInitPosition(dx, dy);
20704 // This is the first time we have detected the element's position
20706 this.setInitPosition();
20709 if (this.constrainX) {
20710 this.setXConstraint( this.leftConstraint,
20711 this.rightConstraint,
20715 if (this.constrainY) {
20716 this.setYConstraint( this.topConstraint,
20717 this.bottomConstraint,
20723 * Normally the drag element is moved pixel by pixel, but we can specify
20724 * that it move a number of pixels at a time. This method resolves the
20725 * location when we have it set up like this.
20727 * @param {int} val where we want to place the object
20728 * @param {int[]} tickArray sorted array of valid points
20729 * @return {int} the closest tick
20732 getTick: function(val, tickArray) {
20735 // If tick interval is not defined, it is effectively 1 pixel,
20736 // so we return the value passed to us.
20738 } else if (tickArray[0] >= val) {
20739 // The value is lower than the first tick, so we return the first
20741 return tickArray[0];
20743 for (var i=0, len=tickArray.length; i<len; ++i) {
20745 if (tickArray[next] && tickArray[next] >= val) {
20746 var diff1 = val - tickArray[i];
20747 var diff2 = tickArray[next] - val;
20748 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
20752 // The value is larger than the last tick, so we return the last
20754 return tickArray[tickArray.length - 1];
20761 * @return {string} string representation of the dd obj
20763 toString: function() {
20764 return ("DragDrop " + this.id);
20772 * Ext JS Library 1.1.1
20773 * Copyright(c) 2006-2007, Ext JS, LLC.
20775 * Originally Released Under LGPL - original licence link has changed is not relivant.
20778 * <script type="text/javascript">
20783 * The drag and drop utility provides a framework for building drag and drop
20784 * applications. In addition to enabling drag and drop for specific elements,
20785 * the drag and drop elements are tracked by the manager class, and the
20786 * interactions between the various elements are tracked during the drag and
20787 * the implementing code is notified about these important moments.
20790 // Only load the library once. Rewriting the manager class would orphan
20791 // existing drag and drop instances.
20792 if (!Roo.dd.DragDropMgr) {
20795 * @class Roo.dd.DragDropMgr
20796 * DragDropMgr is a singleton that tracks the element interaction for
20797 * all DragDrop items in the window. Generally, you will not call
20798 * this class directly, but it does have helper methods that could
20799 * be useful in your DragDrop implementations.
20802 Roo.dd.DragDropMgr = function() {
20804 var Event = Roo.EventManager;
20809 * Two dimensional Array of registered DragDrop objects. The first
20810 * dimension is the DragDrop item group, the second the DragDrop
20813 * @type {string: string}
20820 * Array of element ids defined as drag handles. Used to determine
20821 * if the element that generated the mousedown event is actually the
20822 * handle and not the html element itself.
20823 * @property handleIds
20824 * @type {string: string}
20831 * the DragDrop object that is currently being dragged
20832 * @property dragCurrent
20840 * the DragDrop object(s) that are being hovered over
20841 * @property dragOvers
20849 * the X distance between the cursor and the object being dragged
20858 * the Y distance between the cursor and the object being dragged
20867 * Flag to determine if we should prevent the default behavior of the
20868 * events we define. By default this is true, but this can be set to
20869 * false if you need the default behavior (not recommended)
20870 * @property preventDefault
20874 preventDefault: true,
20877 * Flag to determine if we should stop the propagation of the events
20878 * we generate. This is true by default but you may want to set it to
20879 * false if the html element contains other features that require the
20881 * @property stopPropagation
20885 stopPropagation: true,
20888 * Internal flag that is set to true when drag and drop has been
20890 * @property initialized
20897 * All drag and drop can be disabled.
20905 * Called the first time an element is registered.
20911 this.initialized = true;
20915 * In point mode, drag and drop interaction is defined by the
20916 * location of the cursor during the drag/drop
20924 * In intersect mode, drag and drop interactio nis defined by the
20925 * overlap of two or more drag and drop objects.
20926 * @property INTERSECT
20933 * The current drag and drop mode. Default: POINT
20941 * Runs method on all drag and drop objects
20942 * @method _execOnAll
20946 _execOnAll: function(sMethod, args) {
20947 for (var i in this.ids) {
20948 for (var j in this.ids[i]) {
20949 var oDD = this.ids[i][j];
20950 if (! this.isTypeOfDD(oDD)) {
20953 oDD[sMethod].apply(oDD, args);
20959 * Drag and drop initialization. Sets up the global event handlers
20964 _onLoad: function() {
20968 if (!Roo.isTouch) {
20969 Event.on(document, "mouseup", this.handleMouseUp, this, true);
20970 Event.on(document, "mousemove", this.handleMouseMove, this, true);
20972 Event.on(document, "touchend", this.handleMouseUp, this, true);
20973 Event.on(document, "touchmove", this.handleMouseMove, this, true);
20975 Event.on(window, "unload", this._onUnload, this, true);
20976 Event.on(window, "resize", this._onResize, this, true);
20977 // Event.on(window, "mouseout", this._test);
20982 * Reset constraints on all drag and drop objs
20983 * @method _onResize
20987 _onResize: function(e) {
20988 this._execOnAll("resetConstraints", []);
20992 * Lock all drag and drop functionality
20996 lock: function() { this.locked = true; },
20999 * Unlock all drag and drop functionality
21003 unlock: function() { this.locked = false; },
21006 * Is drag and drop locked?
21008 * @return {boolean} True if drag and drop is locked, false otherwise.
21011 isLocked: function() { return this.locked; },
21014 * Location cache that is set for all drag drop objects when a drag is
21015 * initiated, cleared when the drag is finished.
21016 * @property locationCache
21023 * Set useCache to false if you want to force object the lookup of each
21024 * drag and drop linked element constantly during a drag.
21025 * @property useCache
21032 * The number of pixels that the mouse needs to move after the
21033 * mousedown before the drag is initiated. Default=3;
21034 * @property clickPixelThresh
21038 clickPixelThresh: 3,
21041 * The number of milliseconds after the mousedown event to initiate the
21042 * drag if we don't get a mouseup event. Default=1000
21043 * @property clickTimeThresh
21047 clickTimeThresh: 350,
21050 * Flag that indicates that either the drag pixel threshold or the
21051 * mousdown time threshold has been met
21052 * @property dragThreshMet
21057 dragThreshMet: false,
21060 * Timeout used for the click time threshold
21061 * @property clickTimeout
21066 clickTimeout: null,
21069 * The X position of the mousedown event stored for later use when a
21070 * drag threshold is met.
21079 * The Y position of the mousedown event stored for later use when a
21080 * drag threshold is met.
21089 * Each DragDrop instance must be registered with the DragDropMgr.
21090 * This is executed in DragDrop.init()
21091 * @method regDragDrop
21092 * @param {DragDrop} oDD the DragDrop object to register
21093 * @param {String} sGroup the name of the group this element belongs to
21096 regDragDrop: function(oDD, sGroup) {
21097 if (!this.initialized) { this.init(); }
21099 if (!this.ids[sGroup]) {
21100 this.ids[sGroup] = {};
21102 this.ids[sGroup][oDD.id] = oDD;
21106 * Removes the supplied dd instance from the supplied group. Executed
21107 * by DragDrop.removeFromGroup, so don't call this function directly.
21108 * @method removeDDFromGroup
21112 removeDDFromGroup: function(oDD, sGroup) {
21113 if (!this.ids[sGroup]) {
21114 this.ids[sGroup] = {};
21117 var obj = this.ids[sGroup];
21118 if (obj && obj[oDD.id]) {
21119 delete obj[oDD.id];
21124 * Unregisters a drag and drop item. This is executed in
21125 * DragDrop.unreg, use that method instead of calling this directly.
21130 _remove: function(oDD) {
21131 for (var g in oDD.groups) {
21132 if (g && this.ids[g][oDD.id]) {
21133 delete this.ids[g][oDD.id];
21136 delete this.handleIds[oDD.id];
21140 * Each DragDrop handle element must be registered. This is done
21141 * automatically when executing DragDrop.setHandleElId()
21142 * @method regHandle
21143 * @param {String} sDDId the DragDrop id this element is a handle for
21144 * @param {String} sHandleId the id of the element that is the drag
21148 regHandle: function(sDDId, sHandleId) {
21149 if (!this.handleIds[sDDId]) {
21150 this.handleIds[sDDId] = {};
21152 this.handleIds[sDDId][sHandleId] = sHandleId;
21156 * Utility function to determine if a given element has been
21157 * registered as a drag drop item.
21158 * @method isDragDrop
21159 * @param {String} id the element id to check
21160 * @return {boolean} true if this element is a DragDrop item,
21164 isDragDrop: function(id) {
21165 return ( this.getDDById(id) ) ? true : false;
21169 * Returns the drag and drop instances that are in all groups the
21170 * passed in instance belongs to.
21171 * @method getRelated
21172 * @param {DragDrop} p_oDD the obj to get related data for
21173 * @param {boolean} bTargetsOnly if true, only return targetable objs
21174 * @return {DragDrop[]} the related instances
21177 getRelated: function(p_oDD, bTargetsOnly) {
21179 for (var i in p_oDD.groups) {
21180 for (j in this.ids[i]) {
21181 var dd = this.ids[i][j];
21182 if (! this.isTypeOfDD(dd)) {
21185 if (!bTargetsOnly || dd.isTarget) {
21186 oDDs[oDDs.length] = dd;
21195 * Returns true if the specified dd target is a legal target for
21196 * the specifice drag obj
21197 * @method isLegalTarget
21198 * @param {DragDrop} the drag obj
21199 * @param {DragDrop} the target
21200 * @return {boolean} true if the target is a legal target for the
21204 isLegalTarget: function (oDD, oTargetDD) {
21205 var targets = this.getRelated(oDD, true);
21206 for (var i=0, len=targets.length;i<len;++i) {
21207 if (targets[i].id == oTargetDD.id) {
21216 * My goal is to be able to transparently determine if an object is
21217 * typeof DragDrop, and the exact subclass of DragDrop. typeof
21218 * returns "object", oDD.constructor.toString() always returns
21219 * "DragDrop" and not the name of the subclass. So for now it just
21220 * evaluates a well-known variable in DragDrop.
21221 * @method isTypeOfDD
21222 * @param {Object} the object to evaluate
21223 * @return {boolean} true if typeof oDD = DragDrop
21226 isTypeOfDD: function (oDD) {
21227 return (oDD && oDD.__ygDragDrop);
21231 * Utility function to determine if a given element has been
21232 * registered as a drag drop handle for the given Drag Drop object.
21234 * @param {String} id the element id to check
21235 * @return {boolean} true if this element is a DragDrop handle, false
21239 isHandle: function(sDDId, sHandleId) {
21240 return ( this.handleIds[sDDId] &&
21241 this.handleIds[sDDId][sHandleId] );
21245 * Returns the DragDrop instance for a given id
21246 * @method getDDById
21247 * @param {String} id the id of the DragDrop object
21248 * @return {DragDrop} the drag drop object, null if it is not found
21251 getDDById: function(id) {
21252 for (var i in this.ids) {
21253 if (this.ids[i][id]) {
21254 return this.ids[i][id];
21261 * Fired after a registered DragDrop object gets the mousedown event.
21262 * Sets up the events required to track the object being dragged
21263 * @method handleMouseDown
21264 * @param {Event} e the event
21265 * @param oDD the DragDrop object being dragged
21269 handleMouseDown: function(e, oDD) {
21271 Roo.QuickTips.disable();
21273 this.currentTarget = e.getTarget();
21275 this.dragCurrent = oDD;
21277 var el = oDD.getEl();
21279 // track start position
21280 this.startX = e.getPageX();
21281 this.startY = e.getPageY();
21283 this.deltaX = this.startX - el.offsetLeft;
21284 this.deltaY = this.startY - el.offsetTop;
21286 this.dragThreshMet = false;
21288 this.clickTimeout = setTimeout(
21290 var DDM = Roo.dd.DDM;
21291 DDM.startDrag(DDM.startX, DDM.startY);
21293 this.clickTimeThresh );
21297 * Fired when either the drag pixel threshol or the mousedown hold
21298 * time threshold has been met.
21299 * @method startDrag
21300 * @param x {int} the X position of the original mousedown
21301 * @param y {int} the Y position of the original mousedown
21304 startDrag: function(x, y) {
21305 clearTimeout(this.clickTimeout);
21306 if (this.dragCurrent) {
21307 this.dragCurrent.b4StartDrag(x, y);
21308 this.dragCurrent.startDrag(x, y);
21310 this.dragThreshMet = true;
21314 * Internal function to handle the mouseup event. Will be invoked
21315 * from the context of the document.
21316 * @method handleMouseUp
21317 * @param {Event} e the event
21321 handleMouseUp: function(e) {
21324 Roo.QuickTips.enable();
21326 if (! this.dragCurrent) {
21330 clearTimeout(this.clickTimeout);
21332 if (this.dragThreshMet) {
21333 this.fireEvents(e, true);
21343 * Utility to stop event propagation and event default, if these
21344 * features are turned on.
21345 * @method stopEvent
21346 * @param {Event} e the event as returned by this.getEvent()
21349 stopEvent: function(e){
21350 if(this.stopPropagation) {
21351 e.stopPropagation();
21354 if (this.preventDefault) {
21355 e.preventDefault();
21360 * Internal function to clean up event handlers after the drag
21361 * operation is complete
21363 * @param {Event} e the event
21367 stopDrag: function(e) {
21368 // Fire the drag end event for the item that was dragged
21369 if (this.dragCurrent) {
21370 if (this.dragThreshMet) {
21371 this.dragCurrent.b4EndDrag(e);
21372 this.dragCurrent.endDrag(e);
21375 this.dragCurrent.onMouseUp(e);
21378 this.dragCurrent = null;
21379 this.dragOvers = {};
21383 * Internal function to handle the mousemove event. Will be invoked
21384 * from the context of the html element.
21386 * @TODO figure out what we can do about mouse events lost when the
21387 * user drags objects beyond the window boundary. Currently we can
21388 * detect this in internet explorer by verifying that the mouse is
21389 * down during the mousemove event. Firefox doesn't give us the
21390 * button state on the mousemove event.
21391 * @method handleMouseMove
21392 * @param {Event} e the event
21396 handleMouseMove: function(e) {
21397 if (! this.dragCurrent) {
21401 // var button = e.which || e.button;
21403 // check for IE mouseup outside of page boundary
21404 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
21406 return this.handleMouseUp(e);
21409 if (!this.dragThreshMet) {
21410 var diffX = Math.abs(this.startX - e.getPageX());
21411 var diffY = Math.abs(this.startY - e.getPageY());
21412 if (diffX > this.clickPixelThresh ||
21413 diffY > this.clickPixelThresh) {
21414 this.startDrag(this.startX, this.startY);
21418 if (this.dragThreshMet) {
21419 this.dragCurrent.b4Drag(e);
21420 this.dragCurrent.onDrag(e);
21421 if(!this.dragCurrent.moveOnly){
21422 this.fireEvents(e, false);
21432 * Iterates over all of the DragDrop elements to find ones we are
21433 * hovering over or dropping on
21434 * @method fireEvents
21435 * @param {Event} e the event
21436 * @param {boolean} isDrop is this a drop op or a mouseover op?
21440 fireEvents: function(e, isDrop) {
21441 var dc = this.dragCurrent;
21443 // If the user did the mouse up outside of the window, we could
21444 // get here even though we have ended the drag.
21445 if (!dc || dc.isLocked()) {
21449 var pt = e.getPoint();
21451 // cache the previous dragOver array
21457 var enterEvts = [];
21459 // Check to see if the object(s) we were hovering over is no longer
21460 // being hovered over so we can fire the onDragOut event
21461 for (var i in this.dragOvers) {
21463 var ddo = this.dragOvers[i];
21465 if (! this.isTypeOfDD(ddo)) {
21469 if (! this.isOverTarget(pt, ddo, this.mode)) {
21470 outEvts.push( ddo );
21473 oldOvers[i] = true;
21474 delete this.dragOvers[i];
21477 for (var sGroup in dc.groups) {
21479 if ("string" != typeof sGroup) {
21483 for (i in this.ids[sGroup]) {
21484 var oDD = this.ids[sGroup][i];
21485 if (! this.isTypeOfDD(oDD)) {
21489 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
21490 if (this.isOverTarget(pt, oDD, this.mode)) {
21491 // look for drop interactions
21493 dropEvts.push( oDD );
21494 // look for drag enter and drag over interactions
21497 // initial drag over: dragEnter fires
21498 if (!oldOvers[oDD.id]) {
21499 enterEvts.push( oDD );
21500 // subsequent drag overs: dragOver fires
21502 overEvts.push( oDD );
21505 this.dragOvers[oDD.id] = oDD;
21513 if (outEvts.length) {
21514 dc.b4DragOut(e, outEvts);
21515 dc.onDragOut(e, outEvts);
21518 if (enterEvts.length) {
21519 dc.onDragEnter(e, enterEvts);
21522 if (overEvts.length) {
21523 dc.b4DragOver(e, overEvts);
21524 dc.onDragOver(e, overEvts);
21527 if (dropEvts.length) {
21528 dc.b4DragDrop(e, dropEvts);
21529 dc.onDragDrop(e, dropEvts);
21533 // fire dragout events
21535 for (i=0, len=outEvts.length; i<len; ++i) {
21536 dc.b4DragOut(e, outEvts[i].id);
21537 dc.onDragOut(e, outEvts[i].id);
21540 // fire enter events
21541 for (i=0,len=enterEvts.length; i<len; ++i) {
21542 // dc.b4DragEnter(e, oDD.id);
21543 dc.onDragEnter(e, enterEvts[i].id);
21546 // fire over events
21547 for (i=0,len=overEvts.length; i<len; ++i) {
21548 dc.b4DragOver(e, overEvts[i].id);
21549 dc.onDragOver(e, overEvts[i].id);
21552 // fire drop events
21553 for (i=0, len=dropEvts.length; i<len; ++i) {
21554 dc.b4DragDrop(e, dropEvts[i].id);
21555 dc.onDragDrop(e, dropEvts[i].id);
21560 // notify about a drop that did not find a target
21561 if (isDrop && !dropEvts.length) {
21562 dc.onInvalidDrop(e);
21568 * Helper function for getting the best match from the list of drag
21569 * and drop objects returned by the drag and drop events when we are
21570 * in INTERSECT mode. It returns either the first object that the
21571 * cursor is over, or the object that has the greatest overlap with
21572 * the dragged element.
21573 * @method getBestMatch
21574 * @param {DragDrop[]} dds The array of drag and drop objects
21576 * @return {DragDrop} The best single match
21579 getBestMatch: function(dds) {
21581 // Return null if the input is not what we expect
21582 //if (!dds || !dds.length || dds.length == 0) {
21584 // If there is only one item, it wins
21585 //} else if (dds.length == 1) {
21587 var len = dds.length;
21592 // Loop through the targeted items
21593 for (var i=0; i<len; ++i) {
21595 // If the cursor is over the object, it wins. If the
21596 // cursor is over multiple matches, the first one we come
21598 if (dd.cursorIsOver) {
21601 // Otherwise the object with the most overlap wins
21604 winner.overlap.getArea() < dd.overlap.getArea()) {
21615 * Refreshes the cache of the top-left and bottom-right points of the
21616 * drag and drop objects in the specified group(s). This is in the
21617 * format that is stored in the drag and drop instance, so typical
21620 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
21624 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
21626 * @TODO this really should be an indexed array. Alternatively this
21627 * method could accept both.
21628 * @method refreshCache
21629 * @param {Object} groups an associative array of groups to refresh
21632 refreshCache: function(groups) {
21633 for (var sGroup in groups) {
21634 if ("string" != typeof sGroup) {
21637 for (var i in this.ids[sGroup]) {
21638 var oDD = this.ids[sGroup][i];
21640 if (this.isTypeOfDD(oDD)) {
21641 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
21642 var loc = this.getLocation(oDD);
21644 this.locationCache[oDD.id] = loc;
21646 delete this.locationCache[oDD.id];
21647 // this will unregister the drag and drop object if
21648 // the element is not in a usable state
21657 * This checks to make sure an element exists and is in the DOM. The
21658 * main purpose is to handle cases where innerHTML is used to remove
21659 * drag and drop objects from the DOM. IE provides an 'unspecified
21660 * error' when trying to access the offsetParent of such an element
21662 * @param {HTMLElement} el the element to check
21663 * @return {boolean} true if the element looks usable
21666 verifyEl: function(el) {
21671 parent = el.offsetParent;
21674 parent = el.offsetParent;
21685 * Returns a Region object containing the drag and drop element's position
21686 * and size, including the padding configured for it
21687 * @method getLocation
21688 * @param {DragDrop} oDD the drag and drop object to get the
21690 * @return {Roo.lib.Region} a Region object representing the total area
21691 * the element occupies, including any padding
21692 * the instance is configured for.
21695 getLocation: function(oDD) {
21696 if (! this.isTypeOfDD(oDD)) {
21700 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
21703 pos= Roo.lib.Dom.getXY(el);
21711 x2 = x1 + el.offsetWidth;
21713 y2 = y1 + el.offsetHeight;
21715 t = y1 - oDD.padding[0];
21716 r = x2 + oDD.padding[1];
21717 b = y2 + oDD.padding[2];
21718 l = x1 - oDD.padding[3];
21720 return new Roo.lib.Region( t, r, b, l );
21724 * Checks the cursor location to see if it over the target
21725 * @method isOverTarget
21726 * @param {Roo.lib.Point} pt The point to evaluate
21727 * @param {DragDrop} oTarget the DragDrop object we are inspecting
21728 * @return {boolean} true if the mouse is over the target
21732 isOverTarget: function(pt, oTarget, intersect) {
21733 // use cache if available
21734 var loc = this.locationCache[oTarget.id];
21735 if (!loc || !this.useCache) {
21736 loc = this.getLocation(oTarget);
21737 this.locationCache[oTarget.id] = loc;
21745 oTarget.cursorIsOver = loc.contains( pt );
21747 // DragDrop is using this as a sanity check for the initial mousedown
21748 // in this case we are done. In POINT mode, if the drag obj has no
21749 // contraints, we are also done. Otherwise we need to evaluate the
21750 // location of the target as related to the actual location of the
21751 // dragged element.
21752 var dc = this.dragCurrent;
21753 if (!dc || !dc.getTargetCoord ||
21754 (!intersect && !dc.constrainX && !dc.constrainY)) {
21755 return oTarget.cursorIsOver;
21758 oTarget.overlap = null;
21760 // Get the current location of the drag element, this is the
21761 // location of the mouse event less the delta that represents
21762 // where the original mousedown happened on the element. We
21763 // need to consider constraints and ticks as well.
21764 var pos = dc.getTargetCoord(pt.x, pt.y);
21766 var el = dc.getDragEl();
21767 var curRegion = new Roo.lib.Region( pos.y,
21768 pos.x + el.offsetWidth,
21769 pos.y + el.offsetHeight,
21772 var overlap = curRegion.intersect(loc);
21775 oTarget.overlap = overlap;
21776 return (intersect) ? true : oTarget.cursorIsOver;
21783 * unload event handler
21784 * @method _onUnload
21788 _onUnload: function(e, me) {
21789 Roo.dd.DragDropMgr.unregAll();
21793 * Cleans up the drag and drop events and objects.
21798 unregAll: function() {
21800 if (this.dragCurrent) {
21802 this.dragCurrent = null;
21805 this._execOnAll("unreg", []);
21807 for (i in this.elementCache) {
21808 delete this.elementCache[i];
21811 this.elementCache = {};
21816 * A cache of DOM elements
21817 * @property elementCache
21824 * Get the wrapper for the DOM element specified
21825 * @method getElWrapper
21826 * @param {String} id the id of the element to get
21827 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
21829 * @deprecated This wrapper isn't that useful
21832 getElWrapper: function(id) {
21833 var oWrapper = this.elementCache[id];
21834 if (!oWrapper || !oWrapper.el) {
21835 oWrapper = this.elementCache[id] =
21836 new this.ElementWrapper(Roo.getDom(id));
21842 * Returns the actual DOM element
21843 * @method getElement
21844 * @param {String} id the id of the elment to get
21845 * @return {Object} The element
21846 * @deprecated use Roo.getDom instead
21849 getElement: function(id) {
21850 return Roo.getDom(id);
21854 * Returns the style property for the DOM element (i.e.,
21855 * document.getElById(id).style)
21857 * @param {String} id the id of the elment to get
21858 * @return {Object} The style property of the element
21859 * @deprecated use Roo.getDom instead
21862 getCss: function(id) {
21863 var el = Roo.getDom(id);
21864 return (el) ? el.style : null;
21868 * Inner class for cached elements
21869 * @class DragDropMgr.ElementWrapper
21874 ElementWrapper: function(el) {
21879 this.el = el || null;
21884 this.id = this.el && el.id;
21886 * A reference to the style property
21889 this.css = this.el && el.style;
21893 * Returns the X position of an html element
21895 * @param el the element for which to get the position
21896 * @return {int} the X coordinate
21898 * @deprecated use Roo.lib.Dom.getX instead
21901 getPosX: function(el) {
21902 return Roo.lib.Dom.getX(el);
21906 * Returns the Y position of an html element
21908 * @param el the element for which to get the position
21909 * @return {int} the Y coordinate
21910 * @deprecated use Roo.lib.Dom.getY instead
21913 getPosY: function(el) {
21914 return Roo.lib.Dom.getY(el);
21918 * Swap two nodes. In IE, we use the native method, for others we
21919 * emulate the IE behavior
21921 * @param n1 the first node to swap
21922 * @param n2 the other node to swap
21925 swapNode: function(n1, n2) {
21929 var p = n2.parentNode;
21930 var s = n2.nextSibling;
21933 p.insertBefore(n1, n2);
21934 } else if (n2 == n1.nextSibling) {
21935 p.insertBefore(n2, n1);
21937 n1.parentNode.replaceChild(n2, n1);
21938 p.insertBefore(n1, s);
21944 * Returns the current scroll position
21945 * @method getScroll
21949 getScroll: function () {
21950 var t, l, dde=document.documentElement, db=document.body;
21951 if (dde && (dde.scrollTop || dde.scrollLeft)) {
21953 l = dde.scrollLeft;
21960 return { top: t, left: l };
21964 * Returns the specified element style property
21966 * @param {HTMLElement} el the element
21967 * @param {string} styleProp the style property
21968 * @return {string} The value of the style property
21969 * @deprecated use Roo.lib.Dom.getStyle
21972 getStyle: function(el, styleProp) {
21973 return Roo.fly(el).getStyle(styleProp);
21977 * Gets the scrollTop
21978 * @method getScrollTop
21979 * @return {int} the document's scrollTop
21982 getScrollTop: function () { return this.getScroll().top; },
21985 * Gets the scrollLeft
21986 * @method getScrollLeft
21987 * @return {int} the document's scrollTop
21990 getScrollLeft: function () { return this.getScroll().left; },
21993 * Sets the x/y position of an element to the location of the
21996 * @param {HTMLElement} moveEl The element to move
21997 * @param {HTMLElement} targetEl The position reference element
22000 moveToEl: function (moveEl, targetEl) {
22001 var aCoord = Roo.lib.Dom.getXY(targetEl);
22002 Roo.lib.Dom.setXY(moveEl, aCoord);
22006 * Numeric array sort function
22007 * @method numericSort
22010 numericSort: function(a, b) { return (a - b); },
22014 * @property _timeoutCount
22021 * Trying to make the load order less important. Without this we get
22022 * an error if this file is loaded before the Event Utility.
22023 * @method _addListeners
22027 _addListeners: function() {
22028 var DDM = Roo.dd.DDM;
22029 if ( Roo.lib.Event && document ) {
22032 if (DDM._timeoutCount > 2000) {
22034 setTimeout(DDM._addListeners, 10);
22035 if (document && document.body) {
22036 DDM._timeoutCount += 1;
22043 * Recursively searches the immediate parent and all child nodes for
22044 * the handle element in order to determine wheter or not it was
22046 * @method handleWasClicked
22047 * @param node the html element to inspect
22050 handleWasClicked: function(node, id) {
22051 if (this.isHandle(id, node.id)) {
22054 // check to see if this is a text node child of the one we want
22055 var p = node.parentNode;
22058 if (this.isHandle(id, p.id)) {
22073 // shorter alias, save a few bytes
22074 Roo.dd.DDM = Roo.dd.DragDropMgr;
22075 Roo.dd.DDM._addListeners();
22079 * Ext JS Library 1.1.1
22080 * Copyright(c) 2006-2007, Ext JS, LLC.
22082 * Originally Released Under LGPL - original licence link has changed is not relivant.
22085 * <script type="text/javascript">
22090 * A DragDrop implementation where the linked element follows the
22091 * mouse cursor during a drag.
22092 * @extends Roo.dd.DragDrop
22094 * @param {String} id the id of the linked element
22095 * @param {String} sGroup the group of related DragDrop items
22096 * @param {object} config an object containing configurable attributes
22097 * Valid properties for DD:
22100 Roo.dd.DD = function(id, sGroup, config) {
22102 this.init(id, sGroup, config);
22106 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
22109 * When set to true, the utility automatically tries to scroll the browser
22110 * window wehn a drag and drop element is dragged near the viewport boundary.
22111 * Defaults to true.
22118 * Sets the pointer offset to the distance between the linked element's top
22119 * left corner and the location the element was clicked
22120 * @method autoOffset
22121 * @param {int} iPageX the X coordinate of the click
22122 * @param {int} iPageY the Y coordinate of the click
22124 autoOffset: function(iPageX, iPageY) {
22125 var x = iPageX - this.startPageX;
22126 var y = iPageY - this.startPageY;
22127 this.setDelta(x, y);
22131 * Sets the pointer offset. You can call this directly to force the
22132 * offset to be in a particular location (e.g., pass in 0,0 to set it
22133 * to the center of the object)
22135 * @param {int} iDeltaX the distance from the left
22136 * @param {int} iDeltaY the distance from the top
22138 setDelta: function(iDeltaX, iDeltaY) {
22139 this.deltaX = iDeltaX;
22140 this.deltaY = iDeltaY;
22144 * Sets the drag element to the location of the mousedown or click event,
22145 * maintaining the cursor location relative to the location on the element
22146 * that was clicked. Override this if you want to place the element in a
22147 * location other than where the cursor is.
22148 * @method setDragElPos
22149 * @param {int} iPageX the X coordinate of the mousedown or drag event
22150 * @param {int} iPageY the Y coordinate of the mousedown or drag event
22152 setDragElPos: function(iPageX, iPageY) {
22153 // the first time we do this, we are going to check to make sure
22154 // the element has css positioning
22156 var el = this.getDragEl();
22157 this.alignElWithMouse(el, iPageX, iPageY);
22161 * Sets the element to the location of the mousedown or click event,
22162 * maintaining the cursor location relative to the location on the element
22163 * that was clicked. Override this if you want to place the element in a
22164 * location other than where the cursor is.
22165 * @method alignElWithMouse
22166 * @param {HTMLElement} el the element to move
22167 * @param {int} iPageX the X coordinate of the mousedown or drag event
22168 * @param {int} iPageY the Y coordinate of the mousedown or drag event
22170 alignElWithMouse: function(el, iPageX, iPageY) {
22171 var oCoord = this.getTargetCoord(iPageX, iPageY);
22172 var fly = el.dom ? el : Roo.fly(el);
22173 if (!this.deltaSetXY) {
22174 var aCoord = [oCoord.x, oCoord.y];
22176 var newLeft = fly.getLeft(true);
22177 var newTop = fly.getTop(true);
22178 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
22180 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
22183 this.cachePosition(oCoord.x, oCoord.y);
22184 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
22189 * Saves the most recent position so that we can reset the constraints and
22190 * tick marks on-demand. We need to know this so that we can calculate the
22191 * number of pixels the element is offset from its original position.
22192 * @method cachePosition
22193 * @param iPageX the current x position (optional, this just makes it so we
22194 * don't have to look it up again)
22195 * @param iPageY the current y position (optional, this just makes it so we
22196 * don't have to look it up again)
22198 cachePosition: function(iPageX, iPageY) {
22200 this.lastPageX = iPageX;
22201 this.lastPageY = iPageY;
22203 var aCoord = Roo.lib.Dom.getXY(this.getEl());
22204 this.lastPageX = aCoord[0];
22205 this.lastPageY = aCoord[1];
22210 * Auto-scroll the window if the dragged object has been moved beyond the
22211 * visible window boundary.
22212 * @method autoScroll
22213 * @param {int} x the drag element's x position
22214 * @param {int} y the drag element's y position
22215 * @param {int} h the height of the drag element
22216 * @param {int} w the width of the drag element
22219 autoScroll: function(x, y, h, w) {
22222 // The client height
22223 var clientH = Roo.lib.Dom.getViewWidth();
22225 // The client width
22226 var clientW = Roo.lib.Dom.getViewHeight();
22228 // The amt scrolled down
22229 var st = this.DDM.getScrollTop();
22231 // The amt scrolled right
22232 var sl = this.DDM.getScrollLeft();
22234 // Location of the bottom of the element
22237 // Location of the right of the element
22240 // The distance from the cursor to the bottom of the visible area,
22241 // adjusted so that we don't scroll if the cursor is beyond the
22242 // element drag constraints
22243 var toBot = (clientH + st - y - this.deltaY);
22245 // The distance from the cursor to the right of the visible area
22246 var toRight = (clientW + sl - x - this.deltaX);
22249 // How close to the edge the cursor must be before we scroll
22250 // var thresh = (document.all) ? 100 : 40;
22253 // How many pixels to scroll per autoscroll op. This helps to reduce
22254 // clunky scrolling. IE is more sensitive about this ... it needs this
22255 // value to be higher.
22256 var scrAmt = (document.all) ? 80 : 30;
22258 // Scroll down if we are near the bottom of the visible page and the
22259 // obj extends below the crease
22260 if ( bot > clientH && toBot < thresh ) {
22261 window.scrollTo(sl, st + scrAmt);
22264 // Scroll up if the window is scrolled down and the top of the object
22265 // goes above the top border
22266 if ( y < st && st > 0 && y - st < thresh ) {
22267 window.scrollTo(sl, st - scrAmt);
22270 // Scroll right if the obj is beyond the right border and the cursor is
22271 // near the border.
22272 if ( right > clientW && toRight < thresh ) {
22273 window.scrollTo(sl + scrAmt, st);
22276 // Scroll left if the window has been scrolled to the right and the obj
22277 // extends past the left border
22278 if ( x < sl && sl > 0 && x - sl < thresh ) {
22279 window.scrollTo(sl - scrAmt, st);
22285 * Finds the location the element should be placed if we want to move
22286 * it to where the mouse location less the click offset would place us.
22287 * @method getTargetCoord
22288 * @param {int} iPageX the X coordinate of the click
22289 * @param {int} iPageY the Y coordinate of the click
22290 * @return an object that contains the coordinates (Object.x and Object.y)
22293 getTargetCoord: function(iPageX, iPageY) {
22296 var x = iPageX - this.deltaX;
22297 var y = iPageY - this.deltaY;
22299 if (this.constrainX) {
22300 if (x < this.minX) { x = this.minX; }
22301 if (x > this.maxX) { x = this.maxX; }
22304 if (this.constrainY) {
22305 if (y < this.minY) { y = this.minY; }
22306 if (y > this.maxY) { y = this.maxY; }
22309 x = this.getTick(x, this.xTicks);
22310 y = this.getTick(y, this.yTicks);
22317 * Sets up config options specific to this class. Overrides
22318 * Roo.dd.DragDrop, but all versions of this method through the
22319 * inheritance chain are called
22321 applyConfig: function() {
22322 Roo.dd.DD.superclass.applyConfig.call(this);
22323 this.scroll = (this.config.scroll !== false);
22327 * Event that fires prior to the onMouseDown event. Overrides
22330 b4MouseDown: function(e) {
22331 // this.resetConstraints();
22332 this.autoOffset(e.getPageX(),
22337 * Event that fires prior to the onDrag event. Overrides
22340 b4Drag: function(e) {
22341 this.setDragElPos(e.getPageX(),
22345 toString: function() {
22346 return ("DD " + this.id);
22349 //////////////////////////////////////////////////////////////////////////
22350 // Debugging ygDragDrop events that can be overridden
22351 //////////////////////////////////////////////////////////////////////////
22353 startDrag: function(x, y) {
22356 onDrag: function(e) {
22359 onDragEnter: function(e, id) {
22362 onDragOver: function(e, id) {
22365 onDragOut: function(e, id) {
22368 onDragDrop: function(e, id) {
22371 endDrag: function(e) {
22378 * Ext JS Library 1.1.1
22379 * Copyright(c) 2006-2007, Ext JS, LLC.
22381 * Originally Released Under LGPL - original licence link has changed is not relivant.
22384 * <script type="text/javascript">
22388 * @class Roo.dd.DDProxy
22389 * A DragDrop implementation that inserts an empty, bordered div into
22390 * the document that follows the cursor during drag operations. At the time of
22391 * the click, the frame div is resized to the dimensions of the linked html
22392 * element, and moved to the exact location of the linked element.
22394 * References to the "frame" element refer to the single proxy element that
22395 * was created to be dragged in place of all DDProxy elements on the
22398 * @extends Roo.dd.DD
22400 * @param {String} id the id of the linked html element
22401 * @param {String} sGroup the group of related DragDrop objects
22402 * @param {object} config an object containing configurable attributes
22403 * Valid properties for DDProxy in addition to those in DragDrop:
22404 * resizeFrame, centerFrame, dragElId
22406 Roo.dd.DDProxy = function(id, sGroup, config) {
22408 this.init(id, sGroup, config);
22414 * The default drag frame div id
22415 * @property Roo.dd.DDProxy.dragElId
22419 Roo.dd.DDProxy.dragElId = "ygddfdiv";
22421 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
22424 * By default we resize the drag frame to be the same size as the element
22425 * we want to drag (this is to get the frame effect). We can turn it off
22426 * if we want a different behavior.
22427 * @property resizeFrame
22433 * By default the frame is positioned exactly where the drag element is, so
22434 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
22435 * you do not have constraints on the obj is to have the drag frame centered
22436 * around the cursor. Set centerFrame to true for this effect.
22437 * @property centerFrame
22440 centerFrame: false,
22443 * Creates the proxy element if it does not yet exist
22444 * @method createFrame
22446 createFrame: function() {
22448 var body = document.body;
22450 if (!body || !body.firstChild) {
22451 setTimeout( function() { self.createFrame(); }, 50 );
22455 var div = this.getDragEl();
22458 div = document.createElement("div");
22459 div.id = this.dragElId;
22462 s.position = "absolute";
22463 s.visibility = "hidden";
22465 s.border = "2px solid #aaa";
22468 // appendChild can blow up IE if invoked prior to the window load event
22469 // while rendering a table. It is possible there are other scenarios
22470 // that would cause this to happen as well.
22471 body.insertBefore(div, body.firstChild);
22476 * Initialization for the drag frame element. Must be called in the
22477 * constructor of all subclasses
22478 * @method initFrame
22480 initFrame: function() {
22481 this.createFrame();
22484 applyConfig: function() {
22485 Roo.dd.DDProxy.superclass.applyConfig.call(this);
22487 this.resizeFrame = (this.config.resizeFrame !== false);
22488 this.centerFrame = (this.config.centerFrame);
22489 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
22493 * Resizes the drag frame to the dimensions of the clicked object, positions
22494 * it over the object, and finally displays it
22495 * @method showFrame
22496 * @param {int} iPageX X click position
22497 * @param {int} iPageY Y click position
22500 showFrame: function(iPageX, iPageY) {
22501 var el = this.getEl();
22502 var dragEl = this.getDragEl();
22503 var s = dragEl.style;
22505 this._resizeProxy();
22507 if (this.centerFrame) {
22508 this.setDelta( Math.round(parseInt(s.width, 10)/2),
22509 Math.round(parseInt(s.height, 10)/2) );
22512 this.setDragElPos(iPageX, iPageY);
22514 Roo.fly(dragEl).show();
22518 * The proxy is automatically resized to the dimensions of the linked
22519 * element when a drag is initiated, unless resizeFrame is set to false
22520 * @method _resizeProxy
22523 _resizeProxy: function() {
22524 if (this.resizeFrame) {
22525 var el = this.getEl();
22526 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
22530 // overrides Roo.dd.DragDrop
22531 b4MouseDown: function(e) {
22532 var x = e.getPageX();
22533 var y = e.getPageY();
22534 this.autoOffset(x, y);
22535 this.setDragElPos(x, y);
22538 // overrides Roo.dd.DragDrop
22539 b4StartDrag: function(x, y) {
22540 // show the drag frame
22541 this.showFrame(x, y);
22544 // overrides Roo.dd.DragDrop
22545 b4EndDrag: function(e) {
22546 Roo.fly(this.getDragEl()).hide();
22549 // overrides Roo.dd.DragDrop
22550 // By default we try to move the element to the last location of the frame.
22551 // This is so that the default behavior mirrors that of Roo.dd.DD.
22552 endDrag: function(e) {
22554 var lel = this.getEl();
22555 var del = this.getDragEl();
22557 // Show the drag frame briefly so we can get its position
22558 del.style.visibility = "";
22561 // Hide the linked element before the move to get around a Safari
22563 lel.style.visibility = "hidden";
22564 Roo.dd.DDM.moveToEl(lel, del);
22565 del.style.visibility = "hidden";
22566 lel.style.visibility = "";
22571 beforeMove : function(){
22575 afterDrag : function(){
22579 toString: function() {
22580 return ("DDProxy " + this.id);
22586 * Ext JS Library 1.1.1
22587 * Copyright(c) 2006-2007, Ext JS, LLC.
22589 * Originally Released Under LGPL - original licence link has changed is not relivant.
22592 * <script type="text/javascript">
22596 * @class Roo.dd.DDTarget
22597 * A DragDrop implementation that does not move, but can be a drop
22598 * target. You would get the same result by simply omitting implementation
22599 * for the event callbacks, but this way we reduce the processing cost of the
22600 * event listener and the callbacks.
22601 * @extends Roo.dd.DragDrop
22603 * @param {String} id the id of the element that is a drop target
22604 * @param {String} sGroup the group of related DragDrop objects
22605 * @param {object} config an object containing configurable attributes
22606 * Valid properties for DDTarget in addition to those in
22610 Roo.dd.DDTarget = function(id, sGroup, config) {
22612 this.initTarget(id, sGroup, config);
22614 if (config && (config.listeners || config.events)) {
22615 Roo.dd.DragDrop.superclass.constructor.call(this, {
22616 listeners : config.listeners || {},
22617 events : config.events || {}
22622 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
22623 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
22624 toString: function() {
22625 return ("DDTarget " + this.id);
22630 * Ext JS Library 1.1.1
22631 * Copyright(c) 2006-2007, Ext JS, LLC.
22633 * Originally Released Under LGPL - original licence link has changed is not relivant.
22636 * <script type="text/javascript">
22641 * @class Roo.dd.ScrollManager
22642 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
22643 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
22646 Roo.dd.ScrollManager = function(){
22647 var ddm = Roo.dd.DragDropMgr;
22654 var onStop = function(e){
22659 var triggerRefresh = function(){
22660 if(ddm.dragCurrent){
22661 ddm.refreshCache(ddm.dragCurrent.groups);
22665 var doScroll = function(){
22666 if(ddm.dragCurrent){
22667 var dds = Roo.dd.ScrollManager;
22669 if(proc.el.scroll(proc.dir, dds.increment)){
22673 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
22678 var clearProc = function(){
22680 clearInterval(proc.id);
22687 var startProc = function(el, dir){
22688 Roo.log('scroll startproc');
22692 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
22695 var onFire = function(e, isDrop){
22697 if(isDrop || !ddm.dragCurrent){ return; }
22698 var dds = Roo.dd.ScrollManager;
22699 if(!dragEl || dragEl != ddm.dragCurrent){
22700 dragEl = ddm.dragCurrent;
22701 // refresh regions on drag start
22702 dds.refreshCache();
22705 var xy = Roo.lib.Event.getXY(e);
22706 var pt = new Roo.lib.Point(xy[0], xy[1]);
22707 for(var id in els){
22708 var el = els[id], r = el._region;
22709 if(r && r.contains(pt) && el.isScrollable()){
22710 if(r.bottom - pt.y <= dds.thresh){
22712 startProc(el, "down");
22715 }else if(r.right - pt.x <= dds.thresh){
22717 startProc(el, "left");
22720 }else if(pt.y - r.top <= dds.thresh){
22722 startProc(el, "up");
22725 }else if(pt.x - r.left <= dds.thresh){
22727 startProc(el, "right");
22736 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
22737 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
22741 * Registers new overflow element(s) to auto scroll
22742 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
22744 register : function(el){
22745 if(el instanceof Array){
22746 for(var i = 0, len = el.length; i < len; i++) {
22747 this.register(el[i]);
22753 Roo.dd.ScrollManager.els = els;
22757 * Unregisters overflow element(s) so they are no longer scrolled
22758 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
22760 unregister : function(el){
22761 if(el instanceof Array){
22762 for(var i = 0, len = el.length; i < len; i++) {
22763 this.unregister(el[i]);
22772 * The number of pixels from the edge of a container the pointer needs to be to
22773 * trigger scrolling (defaults to 25)
22779 * The number of pixels to scroll in each scroll increment (defaults to 50)
22785 * The frequency of scrolls in milliseconds (defaults to 500)
22791 * True to animate the scroll (defaults to true)
22797 * The animation duration in seconds -
22798 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
22804 * Manually trigger a cache refresh.
22806 refreshCache : function(){
22807 for(var id in els){
22808 if(typeof els[id] == 'object'){ // for people extending the object prototype
22809 els[id]._region = els[id].getRegion();
22816 * Ext JS Library 1.1.1
22817 * Copyright(c) 2006-2007, Ext JS, LLC.
22819 * Originally Released Under LGPL - original licence link has changed is not relivant.
22822 * <script type="text/javascript">
22827 * @class Roo.dd.Registry
22828 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
22829 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
22832 Roo.dd.Registry = function(){
22835 var autoIdSeed = 0;
22837 var getId = function(el, autogen){
22838 if(typeof el == "string"){
22842 if(!id && autogen !== false){
22843 id = "roodd-" + (++autoIdSeed);
22851 * Register a drag drop element
22852 * @param {String|HTMLElement} element The id or DOM node to register
22853 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
22854 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
22855 * knows how to interpret, plus there are some specific properties known to the Registry that should be
22856 * populated in the data object (if applicable):
22858 Value Description<br />
22859 --------- ------------------------------------------<br />
22860 handles Array of DOM nodes that trigger dragging<br />
22861 for the element being registered<br />
22862 isHandle True if the element passed in triggers<br />
22863 dragging itself, else false
22866 register : function(el, data){
22868 if(typeof el == "string"){
22869 el = document.getElementById(el);
22872 elements[getId(el)] = data;
22873 if(data.isHandle !== false){
22874 handles[data.ddel.id] = data;
22877 var hs = data.handles;
22878 for(var i = 0, len = hs.length; i < len; i++){
22879 handles[getId(hs[i])] = data;
22885 * Unregister a drag drop element
22886 * @param {String|HTMLElement} element The id or DOM node to unregister
22888 unregister : function(el){
22889 var id = getId(el, false);
22890 var data = elements[id];
22892 delete elements[id];
22894 var hs = data.handles;
22895 for(var i = 0, len = hs.length; i < len; i++){
22896 delete handles[getId(hs[i], false)];
22903 * Returns the handle registered for a DOM Node by id
22904 * @param {String|HTMLElement} id The DOM node or id to look up
22905 * @return {Object} handle The custom handle data
22907 getHandle : function(id){
22908 if(typeof id != "string"){ // must be element?
22911 return handles[id];
22915 * Returns the handle that is registered for the DOM node that is the target of the event
22916 * @param {Event} e The event
22917 * @return {Object} handle The custom handle data
22919 getHandleFromEvent : function(e){
22920 var t = Roo.lib.Event.getTarget(e);
22921 return t ? handles[t.id] : null;
22925 * Returns a custom data object that is registered for a DOM node by id
22926 * @param {String|HTMLElement} id The DOM node or id to look up
22927 * @return {Object} data The custom data
22929 getTarget : function(id){
22930 if(typeof id != "string"){ // must be element?
22933 return elements[id];
22937 * Returns a custom data object that is registered for the DOM node that is the target of the event
22938 * @param {Event} e The event
22939 * @return {Object} data The custom data
22941 getTargetFromEvent : function(e){
22942 var t = Roo.lib.Event.getTarget(e);
22943 return t ? elements[t.id] || handles[t.id] : null;
22948 * Ext JS Library 1.1.1
22949 * Copyright(c) 2006-2007, Ext JS, LLC.
22951 * Originally Released Under LGPL - original licence link has changed is not relivant.
22954 * <script type="text/javascript">
22959 * @class Roo.dd.StatusProxy
22960 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
22961 * default drag proxy used by all Roo.dd components.
22963 * @param {Object} config
22965 Roo.dd.StatusProxy = function(config){
22966 Roo.apply(this, config);
22967 this.id = this.id || Roo.id();
22968 this.el = new Roo.Layer({
22970 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
22971 {tag: "div", cls: "x-dd-drop-icon"},
22972 {tag: "div", cls: "x-dd-drag-ghost"}
22975 shadow: !config || config.shadow !== false
22977 this.ghost = Roo.get(this.el.dom.childNodes[1]);
22978 this.dropStatus = this.dropNotAllowed;
22981 Roo.dd.StatusProxy.prototype = {
22983 * @cfg {String} dropAllowed
22984 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
22986 dropAllowed : "x-dd-drop-ok",
22988 * @cfg {String} dropNotAllowed
22989 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
22991 dropNotAllowed : "x-dd-drop-nodrop",
22994 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
22995 * over the current target element.
22996 * @param {String} cssClass The css class for the new drop status indicator image
22998 setStatus : function(cssClass){
22999 cssClass = cssClass || this.dropNotAllowed;
23000 if(this.dropStatus != cssClass){
23001 this.el.replaceClass(this.dropStatus, cssClass);
23002 this.dropStatus = cssClass;
23007 * Resets the status indicator to the default dropNotAllowed value
23008 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
23010 reset : function(clearGhost){
23011 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
23012 this.dropStatus = this.dropNotAllowed;
23014 this.ghost.update("");
23019 * Updates the contents of the ghost element
23020 * @param {String} html The html that will replace the current innerHTML of the ghost element
23022 update : function(html){
23023 if(typeof html == "string"){
23024 this.ghost.update(html);
23026 this.ghost.update("");
23027 html.style.margin = "0";
23028 this.ghost.dom.appendChild(html);
23030 // ensure float = none set?? cant remember why though.
23031 var el = this.ghost.dom.firstChild;
23033 Roo.fly(el).setStyle('float', 'none');
23038 * Returns the underlying proxy {@link Roo.Layer}
23039 * @return {Roo.Layer} el
23041 getEl : function(){
23046 * Returns the ghost element
23047 * @return {Roo.Element} el
23049 getGhost : function(){
23055 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
23057 hide : function(clear){
23065 * Stops the repair animation if it's currently running
23068 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
23074 * Displays this proxy
23081 * Force the Layer to sync its shadow and shim positions to the element
23088 * Causes the proxy to return to its position of origin via an animation. Should be called after an
23089 * invalid drop operation by the item being dragged.
23090 * @param {Array} xy The XY position of the element ([x, y])
23091 * @param {Function} callback The function to call after the repair is complete
23092 * @param {Object} scope The scope in which to execute the callback
23094 repair : function(xy, callback, scope){
23095 this.callback = callback;
23096 this.scope = scope;
23097 if(xy && this.animRepair !== false){
23098 this.el.addClass("x-dd-drag-repair");
23099 this.el.hideUnders(true);
23100 this.anim = this.el.shift({
23101 duration: this.repairDuration || .5,
23105 callback: this.afterRepair,
23109 this.afterRepair();
23114 afterRepair : function(){
23116 if(typeof this.callback == "function"){
23117 this.callback.call(this.scope || this);
23119 this.callback = null;
23124 * Ext JS Library 1.1.1
23125 * Copyright(c) 2006-2007, Ext JS, LLC.
23127 * Originally Released Under LGPL - original licence link has changed is not relivant.
23130 * <script type="text/javascript">
23134 * @class Roo.dd.DragSource
23135 * @extends Roo.dd.DDProxy
23136 * A simple class that provides the basic implementation needed to make any element draggable.
23138 * @param {String/HTMLElement/Element} el The container element
23139 * @param {Object} config
23141 Roo.dd.DragSource = function(el, config){
23142 this.el = Roo.get(el);
23143 this.dragData = {};
23145 Roo.apply(this, config);
23148 this.proxy = new Roo.dd.StatusProxy();
23151 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
23152 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
23154 this.dragging = false;
23157 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
23159 * @cfg {String} dropAllowed
23160 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23162 dropAllowed : "x-dd-drop-ok",
23164 * @cfg {String} dropNotAllowed
23165 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23167 dropNotAllowed : "x-dd-drop-nodrop",
23170 * Returns the data object associated with this drag source
23171 * @return {Object} data An object containing arbitrary data
23173 getDragData : function(e){
23174 return this.dragData;
23178 onDragEnter : function(e, id){
23179 var target = Roo.dd.DragDropMgr.getDDById(id);
23180 this.cachedTarget = target;
23181 if(this.beforeDragEnter(target, e, id) !== false){
23182 if(target.isNotifyTarget){
23183 var status = target.notifyEnter(this, e, this.dragData);
23184 this.proxy.setStatus(status);
23186 this.proxy.setStatus(this.dropAllowed);
23189 if(this.afterDragEnter){
23191 * An empty function by default, but provided so that you can perform a custom action
23192 * when the dragged item enters the drop target by providing an implementation.
23193 * @param {Roo.dd.DragDrop} target The drop target
23194 * @param {Event} e The event object
23195 * @param {String} id The id of the dragged element
23196 * @method afterDragEnter
23198 this.afterDragEnter(target, e, id);
23204 * An empty function by default, but provided so that you can perform a custom action
23205 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
23206 * @param {Roo.dd.DragDrop} target The drop target
23207 * @param {Event} e The event object
23208 * @param {String} id The id of the dragged element
23209 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23211 beforeDragEnter : function(target, e, id){
23216 alignElWithMouse: function() {
23217 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
23222 onDragOver : function(e, id){
23223 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23224 if(this.beforeDragOver(target, e, id) !== false){
23225 if(target.isNotifyTarget){
23226 var status = target.notifyOver(this, e, this.dragData);
23227 this.proxy.setStatus(status);
23230 if(this.afterDragOver){
23232 * An empty function by default, but provided so that you can perform a custom action
23233 * while the dragged item is over the drop target by providing an implementation.
23234 * @param {Roo.dd.DragDrop} target The drop target
23235 * @param {Event} e The event object
23236 * @param {String} id The id of the dragged element
23237 * @method afterDragOver
23239 this.afterDragOver(target, e, id);
23245 * An empty function by default, but provided so that you can perform a custom action
23246 * while the dragged item is over the drop target and optionally cancel the onDragOver.
23247 * @param {Roo.dd.DragDrop} target The drop target
23248 * @param {Event} e The event object
23249 * @param {String} id The id of the dragged element
23250 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23252 beforeDragOver : function(target, e, id){
23257 onDragOut : function(e, id){
23258 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23259 if(this.beforeDragOut(target, e, id) !== false){
23260 if(target.isNotifyTarget){
23261 target.notifyOut(this, e, this.dragData);
23263 this.proxy.reset();
23264 if(this.afterDragOut){
23266 * An empty function by default, but provided so that you can perform a custom action
23267 * after the dragged item is dragged out of the target without dropping.
23268 * @param {Roo.dd.DragDrop} target The drop target
23269 * @param {Event} e The event object
23270 * @param {String} id The id of the dragged element
23271 * @method afterDragOut
23273 this.afterDragOut(target, e, id);
23276 this.cachedTarget = null;
23280 * An empty function by default, but provided so that you can perform a custom action before the dragged
23281 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
23282 * @param {Roo.dd.DragDrop} target The drop target
23283 * @param {Event} e The event object
23284 * @param {String} id The id of the dragged element
23285 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23287 beforeDragOut : function(target, e, id){
23292 onDragDrop : function(e, id){
23293 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23294 if(this.beforeDragDrop(target, e, id) !== false){
23295 if(target.isNotifyTarget){
23296 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
23297 this.onValidDrop(target, e, id);
23299 this.onInvalidDrop(target, e, id);
23302 this.onValidDrop(target, e, id);
23305 if(this.afterDragDrop){
23307 * An empty function by default, but provided so that you can perform a custom action
23308 * after a valid drag drop has occurred by providing an implementation.
23309 * @param {Roo.dd.DragDrop} target The drop target
23310 * @param {Event} e The event object
23311 * @param {String} id The id of the dropped element
23312 * @method afterDragDrop
23314 this.afterDragDrop(target, e, id);
23317 delete this.cachedTarget;
23321 * An empty function by default, but provided so that you can perform a custom action before the dragged
23322 * item is dropped onto the target and optionally cancel the onDragDrop.
23323 * @param {Roo.dd.DragDrop} target The drop target
23324 * @param {Event} e The event object
23325 * @param {String} id The id of the dragged element
23326 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
23328 beforeDragDrop : function(target, e, id){
23333 onValidDrop : function(target, e, id){
23335 if(this.afterValidDrop){
23337 * An empty function by default, but provided so that you can perform a custom action
23338 * after a valid drop has occurred by providing an implementation.
23339 * @param {Object} target The target DD
23340 * @param {Event} e The event object
23341 * @param {String} id The id of the dropped element
23342 * @method afterInvalidDrop
23344 this.afterValidDrop(target, e, id);
23349 getRepairXY : function(e, data){
23350 return this.el.getXY();
23354 onInvalidDrop : function(target, e, id){
23355 this.beforeInvalidDrop(target, e, id);
23356 if(this.cachedTarget){
23357 if(this.cachedTarget.isNotifyTarget){
23358 this.cachedTarget.notifyOut(this, e, this.dragData);
23360 this.cacheTarget = null;
23362 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
23364 if(this.afterInvalidDrop){
23366 * An empty function by default, but provided so that you can perform a custom action
23367 * after an invalid drop has occurred by providing an implementation.
23368 * @param {Event} e The event object
23369 * @param {String} id The id of the dropped element
23370 * @method afterInvalidDrop
23372 this.afterInvalidDrop(e, id);
23377 afterRepair : function(){
23379 this.el.highlight(this.hlColor || "c3daf9");
23381 this.dragging = false;
23385 * An empty function by default, but provided so that you can perform a custom action after an invalid
23386 * drop has occurred.
23387 * @param {Roo.dd.DragDrop} target The drop target
23388 * @param {Event} e The event object
23389 * @param {String} id The id of the dragged element
23390 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
23392 beforeInvalidDrop : function(target, e, id){
23397 handleMouseDown : function(e){
23398 if(this.dragging) {
23401 var data = this.getDragData(e);
23402 if(data && this.onBeforeDrag(data, e) !== false){
23403 this.dragData = data;
23405 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
23410 * An empty function by default, but provided so that you can perform a custom action before the initial
23411 * drag event begins and optionally cancel it.
23412 * @param {Object} data An object containing arbitrary data to be shared with drop targets
23413 * @param {Event} e The event object
23414 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23416 onBeforeDrag : function(data, e){
23421 * An empty function by default, but provided so that you can perform a custom action once the initial
23422 * drag event has begun. The drag cannot be canceled from this function.
23423 * @param {Number} x The x position of the click on the dragged object
23424 * @param {Number} y The y position of the click on the dragged object
23426 onStartDrag : Roo.emptyFn,
23428 // private - YUI override
23429 startDrag : function(x, y){
23430 this.proxy.reset();
23431 this.dragging = true;
23432 this.proxy.update("");
23433 this.onInitDrag(x, y);
23438 onInitDrag : function(x, y){
23439 var clone = this.el.dom.cloneNode(true);
23440 clone.id = Roo.id(); // prevent duplicate ids
23441 this.proxy.update(clone);
23442 this.onStartDrag(x, y);
23447 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
23448 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
23450 getProxy : function(){
23455 * Hides the drag source's {@link Roo.dd.StatusProxy}
23457 hideProxy : function(){
23459 this.proxy.reset(true);
23460 this.dragging = false;
23464 triggerCacheRefresh : function(){
23465 Roo.dd.DDM.refreshCache(this.groups);
23468 // private - override to prevent hiding
23469 b4EndDrag: function(e) {
23472 // private - override to prevent moving
23473 endDrag : function(e){
23474 this.onEndDrag(this.dragData, e);
23478 onEndDrag : function(data, e){
23481 // private - pin to cursor
23482 autoOffset : function(x, y) {
23483 this.setDelta(-12, -20);
23487 * Ext JS Library 1.1.1
23488 * Copyright(c) 2006-2007, Ext JS, LLC.
23490 * Originally Released Under LGPL - original licence link has changed is not relivant.
23493 * <script type="text/javascript">
23498 * @class Roo.dd.DropTarget
23499 * @extends Roo.dd.DDTarget
23500 * A simple class that provides the basic implementation needed to make any element a drop target that can have
23501 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
23503 * @param {String/HTMLElement/Element} el The container element
23504 * @param {Object} config
23506 Roo.dd.DropTarget = function(el, config){
23507 this.el = Roo.get(el);
23509 var listeners = false; ;
23510 if (config && config.listeners) {
23511 listeners= config.listeners;
23512 delete config.listeners;
23514 Roo.apply(this, config);
23516 if(this.containerScroll){
23517 Roo.dd.ScrollManager.register(this.el);
23521 * @scope Roo.dd.DropTarget
23526 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
23527 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
23528 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
23530 * IMPORTANT : it should set this.valid to true|false
23532 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23533 * @param {Event} e The event
23534 * @param {Object} data An object containing arbitrary data supplied by the drag source
23540 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
23541 * This method will be called on every mouse movement while the drag source is over the drop target.
23542 * This default implementation simply returns the dropAllowed config value.
23544 * IMPORTANT : it should set this.valid to true|false
23546 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23547 * @param {Event} e The event
23548 * @param {Object} data An object containing arbitrary data supplied by the drag source
23554 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
23555 * out of the target without dropping. This default implementation simply removes the CSS class specified by
23556 * overClass (if any) from the drop element.
23559 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23560 * @param {Event} e The event
23561 * @param {Object} data An object containing arbitrary data supplied by the drag source
23567 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
23568 * been dropped on it. This method has no default implementation and returns false, so you must provide an
23569 * implementation that does something to process the drop event and returns true so that the drag source's
23570 * repair action does not run.
23572 * IMPORTANT : it should set this.success
23574 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23575 * @param {Event} e The event
23576 * @param {Object} data An object containing arbitrary data supplied by the drag source
23582 Roo.dd.DropTarget.superclass.constructor.call( this,
23584 this.ddGroup || this.group,
23587 listeners : listeners || {}
23595 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
23597 * @cfg {String} overClass
23598 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
23601 * @cfg {String} ddGroup
23602 * The drag drop group to handle drop events for
23606 * @cfg {String} dropAllowed
23607 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23609 dropAllowed : "x-dd-drop-ok",
23611 * @cfg {String} dropNotAllowed
23612 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23614 dropNotAllowed : "x-dd-drop-nodrop",
23616 * @cfg {boolean} success
23617 * set this after drop listener..
23621 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
23622 * if the drop point is valid for over/enter..
23629 isNotifyTarget : true,
23634 notifyEnter : function(dd, e, data)
23637 this.fireEvent('enter', dd, e, data);
23638 if(this.overClass){
23639 this.el.addClass(this.overClass);
23641 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23642 this.valid ? this.dropAllowed : this.dropNotAllowed
23649 notifyOver : function(dd, e, data)
23652 this.fireEvent('over', dd, e, data);
23653 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23654 this.valid ? this.dropAllowed : this.dropNotAllowed
23661 notifyOut : function(dd, e, data)
23663 this.fireEvent('out', dd, e, data);
23664 if(this.overClass){
23665 this.el.removeClass(this.overClass);
23672 notifyDrop : function(dd, e, data)
23674 this.success = false;
23675 this.fireEvent('drop', dd, e, data);
23676 return this.success;
23680 * Ext JS Library 1.1.1
23681 * Copyright(c) 2006-2007, Ext JS, LLC.
23683 * Originally Released Under LGPL - original licence link has changed is not relivant.
23686 * <script type="text/javascript">
23691 * @class Roo.dd.DragZone
23692 * @extends Roo.dd.DragSource
23693 * This class provides a container DD instance that proxies for multiple child node sources.<br />
23694 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
23696 * @param {String/HTMLElement/Element} el The container element
23697 * @param {Object} config
23699 Roo.dd.DragZone = function(el, config){
23700 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
23701 if(this.containerScroll){
23702 Roo.dd.ScrollManager.register(this.el);
23706 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
23708 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
23709 * for auto scrolling during drag operations.
23712 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
23713 * method after a failed drop (defaults to "c3daf9" - light blue)
23717 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
23718 * for a valid target to drag based on the mouse down. Override this method
23719 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
23720 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
23721 * @param {EventObject} e The mouse down event
23722 * @return {Object} The dragData
23724 getDragData : function(e){
23725 return Roo.dd.Registry.getHandleFromEvent(e);
23729 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
23730 * this.dragData.ddel
23731 * @param {Number} x The x position of the click on the dragged object
23732 * @param {Number} y The y position of the click on the dragged object
23733 * @return {Boolean} true to continue the drag, false to cancel
23735 onInitDrag : function(x, y){
23736 this.proxy.update(this.dragData.ddel.cloneNode(true));
23737 this.onStartDrag(x, y);
23742 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
23744 afterRepair : function(){
23746 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
23748 this.dragging = false;
23752 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
23753 * the XY of this.dragData.ddel
23754 * @param {EventObject} e The mouse up event
23755 * @return {Array} The xy location (e.g. [100, 200])
23757 getRepairXY : function(e){
23758 return Roo.Element.fly(this.dragData.ddel).getXY();
23762 * Ext JS Library 1.1.1
23763 * Copyright(c) 2006-2007, Ext JS, LLC.
23765 * Originally Released Under LGPL - original licence link has changed is not relivant.
23768 * <script type="text/javascript">
23771 * @class Roo.dd.DropZone
23772 * @extends Roo.dd.DropTarget
23773 * This class provides a container DD instance that proxies for multiple child node targets.<br />
23774 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
23776 * @param {String/HTMLElement/Element} el The container element
23777 * @param {Object} config
23779 Roo.dd.DropZone = function(el, config){
23780 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
23783 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
23785 * Returns a custom data object associated with the DOM node that is the target of the event. By default
23786 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
23787 * provide your own custom lookup.
23788 * @param {Event} e The event
23789 * @return {Object} data The custom data
23791 getTargetFromEvent : function(e){
23792 return Roo.dd.Registry.getTargetFromEvent(e);
23796 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
23797 * that it has registered. This method has no default implementation and should be overridden to provide
23798 * node-specific processing if necessary.
23799 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23800 * {@link #getTargetFromEvent} for this node)
23801 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23802 * @param {Event} e The event
23803 * @param {Object} data An object containing arbitrary data supplied by the drag source
23805 onNodeEnter : function(n, dd, e, data){
23810 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
23811 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
23812 * overridden to provide the proper feedback.
23813 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23814 * {@link #getTargetFromEvent} for this node)
23815 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23816 * @param {Event} e The event
23817 * @param {Object} data An object containing arbitrary data supplied by the drag source
23818 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23819 * underlying {@link Roo.dd.StatusProxy} can be updated
23821 onNodeOver : function(n, dd, e, data){
23822 return this.dropAllowed;
23826 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
23827 * the drop node without dropping. This method has no default implementation and should be overridden to provide
23828 * node-specific processing if necessary.
23829 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23830 * {@link #getTargetFromEvent} for this node)
23831 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23832 * @param {Event} e The event
23833 * @param {Object} data An object containing arbitrary data supplied by the drag source
23835 onNodeOut : function(n, dd, e, data){
23840 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
23841 * the drop node. The default implementation returns false, so it should be overridden to provide the
23842 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
23843 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23844 * {@link #getTargetFromEvent} for this node)
23845 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23846 * @param {Event} e The event
23847 * @param {Object} data An object containing arbitrary data supplied by the drag source
23848 * @return {Boolean} True if the drop was valid, else false
23850 onNodeDrop : function(n, dd, e, data){
23855 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
23856 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
23857 * it should be overridden to provide the proper feedback if necessary.
23858 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23859 * @param {Event} e The event
23860 * @param {Object} data An object containing arbitrary data supplied by the drag source
23861 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23862 * underlying {@link Roo.dd.StatusProxy} can be updated
23864 onContainerOver : function(dd, e, data){
23865 return this.dropNotAllowed;
23869 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
23870 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
23871 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
23872 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
23873 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23874 * @param {Event} e The event
23875 * @param {Object} data An object containing arbitrary data supplied by the drag source
23876 * @return {Boolean} True if the drop was valid, else false
23878 onContainerDrop : function(dd, e, data){
23883 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
23884 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
23885 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
23886 * you should override this method and provide a custom implementation.
23887 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23888 * @param {Event} e The event
23889 * @param {Object} data An object containing arbitrary data supplied by the drag source
23890 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23891 * underlying {@link Roo.dd.StatusProxy} can be updated
23893 notifyEnter : function(dd, e, data){
23894 return this.dropNotAllowed;
23898 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
23899 * This method will be called on every mouse movement while the drag source is over the drop zone.
23900 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
23901 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
23902 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
23903 * registered node, it will call {@link #onContainerOver}.
23904 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23905 * @param {Event} e The event
23906 * @param {Object} data An object containing arbitrary data supplied by the drag source
23907 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23908 * underlying {@link Roo.dd.StatusProxy} can be updated
23910 notifyOver : function(dd, e, data){
23911 var n = this.getTargetFromEvent(e);
23912 if(!n){ // not over valid drop target
23913 if(this.lastOverNode){
23914 this.onNodeOut(this.lastOverNode, dd, e, data);
23915 this.lastOverNode = null;
23917 return this.onContainerOver(dd, e, data);
23919 if(this.lastOverNode != n){
23920 if(this.lastOverNode){
23921 this.onNodeOut(this.lastOverNode, dd, e, data);
23923 this.onNodeEnter(n, dd, e, data);
23924 this.lastOverNode = n;
23926 return this.onNodeOver(n, dd, e, data);
23930 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
23931 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
23932 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
23933 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23934 * @param {Event} e The event
23935 * @param {Object} data An object containing arbitrary data supplied by the drag zone
23937 notifyOut : function(dd, e, data){
23938 if(this.lastOverNode){
23939 this.onNodeOut(this.lastOverNode, dd, e, data);
23940 this.lastOverNode = null;
23945 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
23946 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
23947 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
23948 * otherwise it will call {@link #onContainerDrop}.
23949 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23950 * @param {Event} e The event
23951 * @param {Object} data An object containing arbitrary data supplied by the drag source
23952 * @return {Boolean} True if the drop was valid, else false
23954 notifyDrop : function(dd, e, data){
23955 if(this.lastOverNode){
23956 this.onNodeOut(this.lastOverNode, dd, e, data);
23957 this.lastOverNode = null;
23959 var n = this.getTargetFromEvent(e);
23961 this.onNodeDrop(n, dd, e, data) :
23962 this.onContainerDrop(dd, e, data);
23966 triggerCacheRefresh : function(){
23967 Roo.dd.DDM.refreshCache(this.groups);