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",
707 * Ext JS Library 1.1.1
708 * Copyright(c) 2006-2007, Ext JS, LLC.
710 * Originally Released Under LGPL - original licence link has changed is not relivant.
713 * <script type="text/javascript">
717 // wrappedn so fnCleanup is not in global scope...
719 function fnCleanUp() {
720 var p = Function.prototype;
721 delete p.createSequence;
723 delete p.createDelegate;
724 delete p.createCallback;
725 delete p.createInterceptor;
727 window.detachEvent("onunload", fnCleanUp);
729 window.attachEvent("onunload", fnCleanUp);
736 * These functions are available on every Function object (any JavaScript function).
738 Roo.apply(Function.prototype, {
740 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
741 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
742 * Will create a function that is bound to those 2 args.
743 * @return {Function} The new function
745 createCallback : function(/*args...*/){
746 // make args available, in function below
747 var args = arguments;
750 return method.apply(window, args);
755 * Creates a delegate (callback) that sets the scope to obj.
756 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
757 * Will create a function that is automatically scoped to this.
758 * @param {Object} obj (optional) The object for which the scope is set
759 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
760 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
761 * if a number the args are inserted at the specified position
762 * @return {Function} The new function
764 createDelegate : function(obj, args, appendArgs){
767 var callArgs = args || arguments;
768 if(appendArgs === true){
769 callArgs = Array.prototype.slice.call(arguments, 0);
770 callArgs = callArgs.concat(args);
771 }else if(typeof appendArgs == "number"){
772 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
773 var applyArgs = [appendArgs, 0].concat(args); // create method call params
774 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
776 return method.apply(obj || window, callArgs);
781 * Calls this function after the number of millseconds specified.
782 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
783 * @param {Object} obj (optional) The object for which the scope is set
784 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
785 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
786 * if a number the args are inserted at the specified position
787 * @return {Number} The timeout id that can be used with clearTimeout
789 defer : function(millis, obj, args, appendArgs){
790 var fn = this.createDelegate(obj, args, appendArgs);
792 return setTimeout(fn, millis);
798 * Create a combined function call sequence of the original function + the passed function.
799 * The resulting function returns the results of the original function.
800 * The passed fcn is called with the parameters of the original function
801 * @param {Function} fcn The function to sequence
802 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
803 * @return {Function} The new function
805 createSequence : function(fcn, scope){
806 if(typeof fcn != "function"){
811 var retval = method.apply(this || window, arguments);
812 fcn.apply(scope || this || window, arguments);
818 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
819 * The resulting function returns the results of the original function.
820 * The passed fcn is called with the parameters of the original function.
822 * @param {Function} fcn The function to call before the original
823 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
824 * @return {Function} The new function
826 createInterceptor : function(fcn, scope){
827 if(typeof fcn != "function"){
834 if(fcn.apply(scope || this || window, arguments) === false){
837 return method.apply(this || window, arguments);
843 * Ext JS Library 1.1.1
844 * Copyright(c) 2006-2007, Ext JS, LLC.
846 * Originally Released Under LGPL - original licence link has changed is not relivant.
849 * <script type="text/javascript">
852 Roo.applyIf(String, {
857 * Escapes the passed string for ' and \
858 * @param {String} string The string to escape
859 * @return {String} The escaped string
862 escape : function(string) {
863 return string.replace(/('|\\)/g, "\\$1");
867 * Pads the left side of a string with a specified character. This is especially useful
868 * for normalizing number and date strings. Example usage:
870 var s = String.leftPad('123', 5, '0');
871 // s now contains the string: '00123'
873 * @param {String} string The original string
874 * @param {Number} size The total length of the output string
875 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
876 * @return {String} The padded string
879 leftPad : function (val, size, ch) {
880 var result = new String(val);
881 if(ch === null || ch === undefined || ch === '') {
884 while (result.length < size) {
885 result = ch + result;
891 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
892 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
894 var cls = 'my-class', text = 'Some text';
895 var s = String.format('<div class="{0}">{1}</div>', cls, text);
896 // s now contains the string: '<div class="my-class">Some text</div>'
898 * @param {String} string The tokenized string to be formatted
899 * @param {String} value1 The value to replace token {0}
900 * @param {String} value2 Etc...
901 * @return {String} The formatted string
904 format : function(format){
905 var args = Array.prototype.slice.call(arguments, 1);
906 return format.replace(/\{(\d+)\}/g, function(m, i){
907 return Roo.util.Format.htmlEncode(args[i]);
915 * Utility function that allows you to easily switch a string between two alternating values. The passed value
916 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
917 * they are already different, the first value passed in is returned. Note that this method returns the new value
918 * but does not change the current string.
920 // alternate sort directions
921 sort = sort.toggle('ASC', 'DESC');
923 // instead of conditional logic:
924 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
926 * @param {String} value The value to compare to the current string
927 * @param {String} other The new value to use if the string already equals the first value passed in
928 * @return {String} The new value
931 String.prototype.toggle = function(value, other){
932 return this == value ? other : value;
937 * Remove invalid unicode characters from a string
939 * @return {String} The clean string
941 String.prototype.unicodeClean = function () {
942 return this.replace(/[\s\S]/g,
943 function(character) {
944 if (character.charCodeAt()< 256) {
948 encodeURIComponent(character);
959 * Ext JS Library 1.1.1
960 * Copyright(c) 2006-2007, Ext JS, LLC.
962 * Originally Released Under LGPL - original licence link has changed is not relivant.
965 * <script type="text/javascript">
971 Roo.applyIf(Number.prototype, {
973 * Checks whether or not the current number is within a desired range. If the number is already within the
974 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
975 * exceeded. Note that this method returns the constrained value but does not change the current number.
976 * @param {Number} min The minimum number in the range
977 * @param {Number} max The maximum number in the range
978 * @return {Number} The constrained value if outside the range, otherwise the current value
980 constrain : function(min, max){
981 return Math.min(Math.max(this, min), max);
985 * Ext JS Library 1.1.1
986 * Copyright(c) 2006-2007, Ext JS, LLC.
988 * Originally Released Under LGPL - original licence link has changed is not relivant.
991 * <script type="text/javascript">
996 Roo.applyIf(Array.prototype, {
999 * Checks whether or not the specified object exists in the array.
1000 * @param {Object} o The object to check for
1001 * @return {Number} The index of o in the array (or -1 if it is not found)
1003 indexOf : function(o){
1004 for (var i = 0, len = this.length; i < len; i++){
1005 if(this[i] == o) { return i; }
1011 * Removes the specified object from the array. If the object is not found nothing happens.
1012 * @param {Object} o The object to remove
1014 remove : function(o){
1015 var index = this.indexOf(o);
1017 this.splice(index, 1);
1021 * Map (JS 1.6 compatibility)
1022 * @param {Function} function to call
1024 map : function(fun )
1026 var len = this.length >>> 0;
1027 if (typeof fun != "function") {
1028 throw new TypeError();
1030 var res = new Array(len);
1031 var thisp = arguments[1];
1032 for (var i = 0; i < len; i++)
1035 res[i] = fun.call(thisp, this[i], i, this);
1043 * @param {Array} o The array to compare to
1044 * @returns {Boolean} true if the same
1046 equals : function(b)
1048 // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
1055 if (this.length !== b.length) {
1059 // sort?? a.sort().equals(b.sort());
1061 for (var i = 0; i < this.length; ++i) {
1062 if (this[i] !== b[i]) {
1074 Roo.applyIf(Array, {
1078 * @param {Array} o Or Array like object (eg. nodelist)
1085 for (var i =0; i < o.length; i++) {
1094 * Ext JS Library 1.1.1
1095 * Copyright(c) 2006-2007, Ext JS, LLC.
1097 * Originally Released Under LGPL - original licence link has changed is not relivant.
1100 * <script type="text/javascript">
1106 * The date parsing and format syntax is a subset of
1107 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1108 * supported will provide results equivalent to their PHP versions.
1110 * Following is the list of all currently supported formats:
1113 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1115 Format Output Description
1116 ------ ---------- --------------------------------------------------------------
1117 d 10 Day of the month, 2 digits with leading zeros
1118 D Wed A textual representation of a day, three letters
1119 j 10 Day of the month without leading zeros
1120 l Wednesday A full textual representation of the day of the week
1121 S th English ordinal day of month suffix, 2 chars (use with j)
1122 w 3 Numeric representation of the day of the week
1123 z 9 The julian date, or day of the year (0-365)
1124 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1125 F January A full textual representation of the month
1126 m 01 Numeric representation of a month, with leading zeros
1127 M Jan Month name abbreviation, three letters
1128 n 1 Numeric representation of a month, without leading zeros
1129 t 31 Number of days in the given month
1130 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1131 Y 2007 A full numeric representation of a year, 4 digits
1132 y 07 A two digit representation of a year
1133 a pm Lowercase Ante meridiem and Post meridiem
1134 A PM Uppercase Ante meridiem and Post meridiem
1135 g 3 12-hour format of an hour without leading zeros
1136 G 15 24-hour format of an hour without leading zeros
1137 h 03 12-hour format of an hour with leading zeros
1138 H 15 24-hour format of an hour with leading zeros
1139 i 05 Minutes with leading zeros
1140 s 01 Seconds, with leading zeros
1141 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1142 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1143 T CST Timezone setting of the machine running the code
1144 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1147 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1149 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1150 document.write(dt.format('Y-m-d')); //2007-01-10
1151 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1152 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
1155 * Here are some standard date/time patterns that you might find helpful. They
1156 * are not part of the source of Date.js, but to use them you can simply copy this
1157 * block of code into any script that is included after Date.js and they will also become
1158 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1161 ISO8601Long:"Y-m-d H:i:s",
1162 ISO8601Short:"Y-m-d",
1164 LongDate: "l, F d, Y",
1165 FullDateTime: "l, F d, Y g:i:s A",
1168 LongTime: "g:i:s A",
1169 SortableDateTime: "Y-m-d\\TH:i:s",
1170 UniversalSortableDateTime: "Y-m-d H:i:sO",
1177 var dt = new Date();
1178 document.write(dt.format(Date.patterns.ShortDate));
1183 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1184 * They generate precompiled functions from date formats instead of parsing and
1185 * processing the pattern every time you format a date. These functions are available
1186 * on every Date object (any javascript function).
1188 * The original article and download are here:
1189 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1196 Returns the number of milliseconds between this date and date
1197 @param {Date} date (optional) Defaults to now
1198 @return {Number} The diff in milliseconds
1199 @member Date getElapsed
1201 Date.prototype.getElapsed = function(date) {
1202 return Math.abs((date || new Date()).getTime()-this.getTime());
1204 // was in date file..
1208 Date.parseFunctions = {count:0};
1210 Date.parseRegexes = [];
1212 Date.formatFunctions = {count:0};
1215 Date.prototype.dateFormat = function(format) {
1216 if (Date.formatFunctions[format] == null) {
1217 Date.createNewFormat(format);
1219 var func = Date.formatFunctions[format];
1220 return this[func]();
1225 * Formats a date given the supplied format string
1226 * @param {String} format The format string
1227 * @return {String} The formatted date
1230 Date.prototype.format = Date.prototype.dateFormat;
1233 Date.createNewFormat = function(format) {
1234 var funcName = "format" + Date.formatFunctions.count++;
1235 Date.formatFunctions[format] = funcName;
1236 var code = "Date.prototype." + funcName + " = function(){return ";
1237 var special = false;
1239 for (var i = 0; i < format.length; ++i) {
1240 ch = format.charAt(i);
1241 if (!special && ch == "\\") {
1246 code += "'" + String.escape(ch) + "' + ";
1249 code += Date.getFormatCode(ch);
1252 /** eval:var:zzzzzzzzzzzzz */
1253 eval(code.substring(0, code.length - 3) + ";}");
1257 Date.getFormatCode = function(character) {
1258 switch (character) {
1260 return "String.leftPad(this.getDate(), 2, '0') + ";
1262 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1264 return "this.getDate() + ";
1266 return "Date.dayNames[this.getDay()] + ";
1268 return "this.getSuffix() + ";
1270 return "this.getDay() + ";
1272 return "this.getDayOfYear() + ";
1274 return "this.getWeekOfYear() + ";
1276 return "Date.monthNames[this.getMonth()] + ";
1278 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1280 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1282 return "(this.getMonth() + 1) + ";
1284 return "this.getDaysInMonth() + ";
1286 return "(this.isLeapYear() ? 1 : 0) + ";
1288 return "this.getFullYear() + ";
1290 return "('' + this.getFullYear()).substring(2, 4) + ";
1292 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1294 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1296 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1298 return "this.getHours() + ";
1300 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1302 return "String.leftPad(this.getHours(), 2, '0') + ";
1304 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1306 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1308 return "this.getGMTOffset() + ";
1310 return "this.getGMTColonOffset() + ";
1312 return "this.getTimezone() + ";
1314 return "(this.getTimezoneOffset() * -60) + ";
1316 return "'" + String.escape(character) + "' + ";
1321 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1322 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1323 * the date format that is not specified will default to the current date value for that part. Time parts can also
1324 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1325 * string or the parse operation will fail.
1328 //dt = Fri May 25 2007 (current date)
1329 var dt = new Date();
1331 //dt = Thu May 25 2006 (today's month/day in 2006)
1332 dt = Date.parseDate("2006", "Y");
1334 //dt = Sun Jan 15 2006 (all date parts specified)
1335 dt = Date.parseDate("2006-1-15", "Y-m-d");
1337 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1338 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1340 * @param {String} input The unparsed date as a string
1341 * @param {String} format The format the date is in
1342 * @return {Date} The parsed date
1345 Date.parseDate = function(input, format) {
1346 if (Date.parseFunctions[format] == null) {
1347 Date.createParser(format);
1349 var func = Date.parseFunctions[format];
1350 return Date[func](input);
1356 Date.createParser = function(format) {
1357 var funcName = "parse" + Date.parseFunctions.count++;
1358 var regexNum = Date.parseRegexes.length;
1359 var currentGroup = 1;
1360 Date.parseFunctions[format] = funcName;
1362 var code = "Date." + funcName + " = function(input){\n"
1363 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1364 + "var d = new Date();\n"
1365 + "y = d.getFullYear();\n"
1366 + "m = d.getMonth();\n"
1367 + "d = d.getDate();\n"
1368 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1369 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1370 + "if (results && results.length > 0) {";
1373 var special = false;
1375 for (var i = 0; i < format.length; ++i) {
1376 ch = format.charAt(i);
1377 if (!special && ch == "\\") {
1382 regex += String.escape(ch);
1385 var obj = Date.formatCodeToRegex(ch, currentGroup);
1386 currentGroup += obj.g;
1388 if (obj.g && obj.c) {
1394 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1395 + "{v = new Date(y, m, d, h, i, s); v.setFullYear(y);}\n"
1396 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1397 + "{v = new Date(y, m, d, h, i); v.setFullYear(y);}\n"
1398 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1399 + "{v = new Date(y, m, d, h); v.setFullYear(y);}\n"
1400 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1401 + "{v = new Date(y, m, d); v.setFullYear(y);}\n"
1402 + "else if (y >= 0 && m >= 0)\n"
1403 + "{v = new Date(y, m); v.setFullYear(y);}\n"
1404 + "else if (y >= 0)\n"
1405 + "{v = new Date(y); v.setFullYear(y);}\n"
1406 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1407 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1408 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1411 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1412 /** eval:var:zzzzzzzzzzzzz */
1417 Date.formatCodeToRegex = function(character, currentGroup) {
1418 switch (character) {
1422 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1425 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1426 s:"(\\d{1,2})"}; // day of month without leading zeroes
1429 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1430 s:"(\\d{2})"}; // day of month with leading zeroes
1434 s:"(?:" + Date.dayNames.join("|") + ")"};
1438 s:"(?:st|nd|rd|th)"};
1453 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1454 s:"(" + Date.monthNames.join("|") + ")"};
1457 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1458 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1461 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1462 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1465 c:"m = Math.max(0,parseInt(results[" + currentGroup + "], 10) - 1);\n",
1466 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1477 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1481 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1482 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1486 c:"if (results[" + currentGroup + "] == 'am') {\n"
1487 + "if (h == 12) { h = 0; }\n"
1488 + "} else { if (h < 12) { h += 12; }}",
1492 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1493 + "if (h == 12) { h = 0; }\n"
1494 + "} else { if (h < 12) { h += 12; }}",
1499 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1500 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1504 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1505 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1508 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1512 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1517 "o = results[", currentGroup, "];\n",
1518 "var sn = o.substring(0,1);\n", // get + / - sign
1519 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1520 "var mn = o.substring(3,5) % 60;\n", // get minutes
1521 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1522 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1524 s:"([+\-]\\d{2,4})"};
1530 "o = results[", currentGroup, "];\n",
1531 "var sn = o.substring(0,1);\n",
1532 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1533 "var mn = o.substring(4,6) % 60;\n",
1534 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1535 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1541 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1544 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1545 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1546 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1550 s:String.escape(character)};
1555 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1556 * @return {String} The abbreviated timezone name (e.g. 'CST')
1558 Date.prototype.getTimezone = function() {
1559 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1563 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1564 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1566 Date.prototype.getGMTOffset = function() {
1567 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1568 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1569 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1573 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1574 * @return {String} 2-characters representing hours and 2-characters representing minutes
1575 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1577 Date.prototype.getGMTColonOffset = function() {
1578 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1579 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1581 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1585 * Get the numeric day number of the year, adjusted for leap year.
1586 * @return {Number} 0 through 364 (365 in leap years)
1588 Date.prototype.getDayOfYear = function() {
1590 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1591 for (var i = 0; i < this.getMonth(); ++i) {
1592 num += Date.daysInMonth[i];
1594 return num + this.getDate() - 1;
1598 * Get the string representation of the numeric week number of the year
1599 * (equivalent to the format specifier 'W').
1600 * @return {String} '00' through '52'
1602 Date.prototype.getWeekOfYear = function() {
1603 // Skip to Thursday of this week
1604 var now = this.getDayOfYear() + (4 - this.getDay());
1605 // Find the first Thursday of the year
1606 var jan1 = new Date(this.getFullYear(), 0, 1);
1607 var then = (7 - jan1.getDay() + 4);
1608 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1612 * Whether or not the current date is in a leap year.
1613 * @return {Boolean} True if the current date is in a leap year, else false
1615 Date.prototype.isLeapYear = function() {
1616 var year = this.getFullYear();
1617 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1621 * Get the first day of the current month, adjusted for leap year. The returned value
1622 * is the numeric day index within the week (0-6) which can be used in conjunction with
1623 * the {@link #monthNames} array to retrieve the textual day name.
1626 var dt = new Date('1/10/2007');
1627 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1629 * @return {Number} The day number (0-6)
1631 Date.prototype.getFirstDayOfMonth = function() {
1632 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1633 return (day < 0) ? (day + 7) : day;
1637 * Get the last day of the current month, adjusted for leap year. The returned value
1638 * is the numeric day index within the week (0-6) which can be used in conjunction with
1639 * the {@link #monthNames} array to retrieve the textual day name.
1642 var dt = new Date('1/10/2007');
1643 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1645 * @return {Number} The day number (0-6)
1647 Date.prototype.getLastDayOfMonth = function() {
1648 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1649 return (day < 0) ? (day + 7) : day;
1654 * Get the first date of this date's month
1657 Date.prototype.getFirstDateOfMonth = function() {
1658 return new Date(this.getFullYear(), this.getMonth(), 1);
1662 * Get the last date of this date's month
1665 Date.prototype.getLastDateOfMonth = function() {
1666 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1669 * Get the number of days in the current month, adjusted for leap year.
1670 * @return {Number} The number of days in the month
1672 Date.prototype.getDaysInMonth = function() {
1673 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1674 return Date.daysInMonth[this.getMonth()];
1678 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1679 * @return {String} 'st, 'nd', 'rd' or 'th'
1681 Date.prototype.getSuffix = function() {
1682 switch (this.getDate()) {
1699 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1702 * An array of textual month names.
1703 * Override these values for international dates, for example...
1704 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1723 * An array of textual day names.
1724 * Override these values for international dates, for example...
1725 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1741 Date.monthNumbers = {
1756 * Creates and returns a new Date instance with the exact same date value as the called instance.
1757 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1758 * variable will also be changed. When the intention is to create a new variable that will not
1759 * modify the original instance, you should create a clone.
1761 * Example of correctly cloning a date:
1764 var orig = new Date('10/1/2006');
1767 document.write(orig); //returns 'Thu Oct 05 2006'!
1770 var orig = new Date('10/1/2006');
1771 var copy = orig.clone();
1773 document.write(orig); //returns 'Thu Oct 01 2006'
1775 * @return {Date} The new Date instance
1777 Date.prototype.clone = function() {
1778 return new Date(this.getTime());
1782 * Clears any time information from this date
1783 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1784 @return {Date} this or the clone
1786 Date.prototype.clearTime = function(clone){
1788 return this.clone().clearTime();
1793 this.setMilliseconds(0);
1798 // safari setMonth is broken -- check that this is only donw once...
1799 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1800 Date.brokenSetMonth = Date.prototype.setMonth;
1801 Date.prototype.setMonth = function(num){
1803 var n = Math.ceil(-num);
1804 var back_year = Math.ceil(n/12);
1805 var month = (n % 12) ? 12 - n % 12 : 0 ;
1806 this.setFullYear(this.getFullYear() - back_year);
1807 return Date.brokenSetMonth.call(this, month);
1809 return Date.brokenSetMonth.apply(this, arguments);
1814 /** Date interval constant
1818 /** Date interval constant
1822 /** Date interval constant
1826 /** Date interval constant
1830 /** Date interval constant
1834 /** Date interval constant
1838 /** Date interval constant
1844 * Provides a convenient method of performing basic date arithmetic. This method
1845 * does not modify the Date instance being called - it creates and returns
1846 * a new Date instance containing the resulting date value.
1851 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1852 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1854 //Negative values will subtract correctly:
1855 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1856 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1858 //You can even chain several calls together in one line!
1859 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1860 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1863 * @param {String} interval A valid date interval enum value
1864 * @param {Number} value The amount to add to the current date
1865 * @return {Date} The new Date instance
1867 Date.prototype.add = function(interval, value){
1868 var d = this.clone();
1869 if (!interval || value === 0) { return d; }
1870 switch(interval.toLowerCase()){
1872 d.setMilliseconds(this.getMilliseconds() + value);
1875 d.setSeconds(this.getSeconds() + value);
1878 d.setMinutes(this.getMinutes() + value);
1881 d.setHours(this.getHours() + value);
1884 d.setDate(this.getDate() + value);
1887 var day = this.getDate();
1889 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1892 d.setMonth(this.getMonth() + value);
1895 d.setFullYear(this.getFullYear() + value);
1901 * @class Roo.lib.Dom
1905 * Dom utils (from YIU afaik)
1911 * Get the view width
1912 * @param {Boolean} full True will get the full document, otherwise it's the view width
1913 * @return {Number} The width
1916 getViewWidth : function(full) {
1917 return full ? this.getDocumentWidth() : this.getViewportWidth();
1920 * Get the view height
1921 * @param {Boolean} full True will get the full document, otherwise it's the view height
1922 * @return {Number} The height
1924 getViewHeight : function(full) {
1925 return full ? this.getDocumentHeight() : this.getViewportHeight();
1928 * Get the Full Document height
1929 * @return {Number} The height
1931 getDocumentHeight: function() {
1932 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1933 return Math.max(scrollHeight, this.getViewportHeight());
1936 * Get the Full Document width
1937 * @return {Number} The width
1939 getDocumentWidth: function() {
1940 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1941 return Math.max(scrollWidth, this.getViewportWidth());
1944 * Get the Window Viewport height
1945 * @return {Number} The height
1947 getViewportHeight: function() {
1948 var height = self.innerHeight;
1949 var mode = document.compatMode;
1951 if ((mode || Roo.isIE) && !Roo.isOpera) {
1952 height = (mode == "CSS1Compat") ?
1953 document.documentElement.clientHeight :
1954 document.body.clientHeight;
1960 * Get the Window Viewport width
1961 * @return {Number} The width
1963 getViewportWidth: function() {
1964 var width = self.innerWidth;
1965 var mode = document.compatMode;
1967 if (mode || Roo.isIE) {
1968 width = (mode == "CSS1Compat") ?
1969 document.documentElement.clientWidth :
1970 document.body.clientWidth;
1975 isAncestor : function(p, c) {
1982 if (p.contains && !Roo.isSafari) {
1983 return p.contains(c);
1984 } else if (p.compareDocumentPosition) {
1985 return !!(p.compareDocumentPosition(c) & 16);
1987 var parent = c.parentNode;
1992 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1995 parent = parent.parentNode;
2001 getRegion : function(el) {
2002 return Roo.lib.Region.getRegion(el);
2005 getY : function(el) {
2006 return this.getXY(el)[1];
2009 getX : function(el) {
2010 return this.getXY(el)[0];
2013 getXY : function(el) {
2014 var p, pe, b, scroll, bd = document.body;
2015 el = Roo.getDom(el);
2016 var fly = Roo.lib.AnimBase.fly;
2017 if (el.getBoundingClientRect) {
2018 b = el.getBoundingClientRect();
2019 scroll = fly(document).getScroll();
2020 return [b.left + scroll.left, b.top + scroll.top];
2026 var hasAbsolute = fly(el).getStyle("position") == "absolute";
2033 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
2040 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
2041 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2048 if (p != el && pe.getStyle('overflow') != 'visible') {
2056 if (Roo.isSafari && hasAbsolute) {
2061 if (Roo.isGecko && !hasAbsolute) {
2063 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2064 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2068 while (p && p != bd) {
2069 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2081 setXY : function(el, xy) {
2082 el = Roo.fly(el, '_setXY');
2084 var pts = el.translatePoints(xy);
2085 if (xy[0] !== false) {
2086 el.dom.style.left = pts.left + "px";
2088 if (xy[1] !== false) {
2089 el.dom.style.top = pts.top + "px";
2093 setX : function(el, x) {
2094 this.setXY(el, [x, false]);
2097 setY : function(el, y) {
2098 this.setXY(el, [false, y]);
2102 * Portions of this file are based on pieces of Yahoo User Interface Library
2103 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2104 * YUI licensed under the BSD License:
2105 * http://developer.yahoo.net/yui/license.txt
2106 * <script type="text/javascript">
2110 Roo.lib.Event = function() {
2111 var loadComplete = false;
2113 var unloadListeners = [];
2115 var onAvailStack = [];
2117 var lastError = null;
2130 startInterval: function() {
2131 if (!this._interval) {
2133 var callback = function() {
2134 self._tryPreloadAttach();
2136 this._interval = setInterval(callback, this.POLL_INTERVAL);
2141 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2142 onAvailStack.push({ id: p_id,
2145 override: p_override,
2146 checkReady: false });
2148 retryCount = this.POLL_RETRYS;
2149 this.startInterval();
2153 addListener: function(el, eventName, fn) {
2154 el = Roo.getDom(el);
2159 if ("unload" == eventName) {
2160 unloadListeners[unloadListeners.length] =
2161 [el, eventName, fn];
2165 var wrappedFn = function(e) {
2166 return fn(Roo.lib.Event.getEvent(e));
2169 var li = [el, eventName, fn, wrappedFn];
2171 var index = listeners.length;
2172 listeners[index] = li;
2174 this.doAdd(el, eventName, wrappedFn, false);
2180 removeListener: function(el, eventName, fn) {
2183 el = Roo.getDom(el);
2186 return this.purgeElement(el, false, eventName);
2190 if ("unload" == eventName) {
2192 for (i = 0,len = unloadListeners.length; i < len; i++) {
2193 var li = unloadListeners[i];
2196 li[1] == eventName &&
2198 unloadListeners.splice(i, 1);
2206 var cacheItem = null;
2209 var index = arguments[3];
2211 if ("undefined" == typeof index) {
2212 index = this._getCacheIndex(el, eventName, fn);
2216 cacheItem = listeners[index];
2219 if (!el || !cacheItem) {
2223 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2225 delete listeners[index][this.WFN];
2226 delete listeners[index][this.FN];
2227 listeners.splice(index, 1);
2234 getTarget: function(ev, resolveTextNode) {
2235 ev = ev.browserEvent || ev;
2236 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2237 var t = ev.target || ev.srcElement;
2238 return this.resolveTextNode(t);
2242 resolveTextNode: function(node) {
2243 if (Roo.isSafari && node && 3 == node.nodeType) {
2244 return node.parentNode;
2251 getPageX: function(ev) {
2252 ev = ev.browserEvent || ev;
2253 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2255 if (!x && 0 !== x) {
2256 x = ev.clientX || 0;
2259 x += this.getScroll()[1];
2267 getPageY: function(ev) {
2268 ev = ev.browserEvent || ev;
2269 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2271 if (!y && 0 !== y) {
2272 y = ev.clientY || 0;
2275 y += this.getScroll()[0];
2284 getXY: function(ev) {
2285 ev = ev.browserEvent || ev;
2286 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2287 return [this.getPageX(ev), this.getPageY(ev)];
2291 getRelatedTarget: function(ev) {
2292 ev = ev.browserEvent || ev;
2293 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2294 var t = ev.relatedTarget;
2296 if (ev.type == "mouseout") {
2298 } else if (ev.type == "mouseover") {
2303 return this.resolveTextNode(t);
2307 getTime: function(ev) {
2308 ev = ev.browserEvent || ev;
2309 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2311 var t = new Date().getTime();
2315 this.lastError = ex;
2324 stopEvent: function(ev) {
2325 this.stopPropagation(ev);
2326 this.preventDefault(ev);
2330 stopPropagation: function(ev) {
2331 ev = ev.browserEvent || ev;
2332 if (ev.stopPropagation) {
2333 ev.stopPropagation();
2335 ev.cancelBubble = true;
2340 preventDefault: function(ev) {
2341 ev = ev.browserEvent || ev;
2342 if(ev.preventDefault) {
2343 ev.preventDefault();
2345 ev.returnValue = false;
2350 getEvent: function(e) {
2351 var ev = e || window.event;
2353 var c = this.getEvent.caller;
2355 ev = c.arguments[0];
2356 if (ev && Event == ev.constructor) {
2366 getCharCode: function(ev) {
2367 ev = ev.browserEvent || ev;
2368 return ev.charCode || ev.keyCode || 0;
2372 _getCacheIndex: function(el, eventName, fn) {
2373 for (var i = 0,len = listeners.length; i < len; ++i) {
2374 var li = listeners[i];
2376 li[this.FN] == fn &&
2377 li[this.EL] == el &&
2378 li[this.TYPE] == eventName) {
2390 getEl: function(id) {
2391 return document.getElementById(id);
2395 clearCache: function() {
2399 _load: function(e) {
2400 loadComplete = true;
2401 var EU = Roo.lib.Event;
2405 EU.doRemove(window, "load", EU._load);
2410 _tryPreloadAttach: function() {
2419 var tryAgain = !loadComplete;
2421 tryAgain = (retryCount > 0);
2426 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2427 var item = onAvailStack[i];
2429 var el = this.getEl(item.id);
2432 if (!item.checkReady ||
2435 (document && document.body)) {
2438 if (item.override) {
2439 if (item.override === true) {
2442 scope = item.override;
2445 item.fn.call(scope, item.obj);
2446 onAvailStack[i] = null;
2449 notAvail.push(item);
2454 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2458 this.startInterval();
2460 clearInterval(this._interval);
2461 this._interval = null;
2464 this.locked = false;
2471 purgeElement: function(el, recurse, eventName) {
2472 var elListeners = this.getListeners(el, eventName);
2474 for (var i = 0,len = elListeners.length; i < len; ++i) {
2475 var l = elListeners[i];
2476 this.removeListener(el, l.type, l.fn);
2480 if (recurse && el && el.childNodes) {
2481 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2482 this.purgeElement(el.childNodes[i], recurse, eventName);
2488 getListeners: function(el, eventName) {
2489 var results = [], searchLists;
2491 searchLists = [listeners, unloadListeners];
2492 } else if (eventName == "unload") {
2493 searchLists = [unloadListeners];
2495 searchLists = [listeners];
2498 for (var j = 0; j < searchLists.length; ++j) {
2499 var searchList = searchLists[j];
2500 if (searchList && searchList.length > 0) {
2501 for (var i = 0,len = searchList.length; i < len; ++i) {
2502 var l = searchList[i];
2503 if (l && l[this.EL] === el &&
2504 (!eventName || eventName === l[this.TYPE])) {
2509 adjust: l[this.ADJ_SCOPE],
2517 return (results.length) ? results : null;
2521 _unload: function(e) {
2523 var EU = Roo.lib.Event, i, j, l, len, index;
2525 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2526 l = unloadListeners[i];
2529 if (l[EU.ADJ_SCOPE]) {
2530 if (l[EU.ADJ_SCOPE] === true) {
2533 scope = l[EU.ADJ_SCOPE];
2536 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2537 unloadListeners[i] = null;
2543 unloadListeners = null;
2545 if (listeners && listeners.length > 0) {
2546 j = listeners.length;
2549 l = listeners[index];
2551 EU.removeListener(l[EU.EL], l[EU.TYPE],
2561 EU.doRemove(window, "unload", EU._unload);
2566 getScroll: function() {
2567 var dd = document.documentElement, db = document.body;
2568 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2569 return [dd.scrollTop, dd.scrollLeft];
2571 return [db.scrollTop, db.scrollLeft];
2578 doAdd: function () {
2579 if (window.addEventListener) {
2580 return function(el, eventName, fn, capture) {
2581 el.addEventListener(eventName, fn, (capture));
2583 } else if (window.attachEvent) {
2584 return function(el, eventName, fn, capture) {
2585 el.attachEvent("on" + eventName, fn);
2594 doRemove: function() {
2595 if (window.removeEventListener) {
2596 return function (el, eventName, fn, capture) {
2597 el.removeEventListener(eventName, fn, (capture));
2599 } else if (window.detachEvent) {
2600 return function (el, eventName, fn) {
2601 el.detachEvent("on" + eventName, fn);
2613 var E = Roo.lib.Event;
2614 E.on = E.addListener;
2615 E.un = E.removeListener;
2617 if (document && document.body) {
2620 E.doAdd(window, "load", E._load);
2622 E.doAdd(window, "unload", E._unload);
2623 E._tryPreloadAttach();
2630 * @class Roo.lib.Ajax
2632 * provide a simple Ajax request utility functions
2634 * Portions of this file are based on pieces of Yahoo User Interface Library
2635 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2636 * YUI licensed under the BSD License:
2637 * http://developer.yahoo.net/yui/license.txt
2638 * <script type="text/javascript">
2646 request : function(method, uri, cb, data, options) {
2648 var hs = options.headers;
2651 if(hs.hasOwnProperty(h)){
2652 this.initHeader(h, hs[h], false);
2656 if(options.xmlData){
2657 this.initHeader('Content-Type', 'text/xml', false);
2659 data = options.xmlData;
2663 return this.asyncRequest(method, uri, cb, data);
2669 * @param {DomForm} form element
2670 * @return {String} urlencode form output.
2672 serializeForm : function(form) {
2673 if(typeof form == 'string') {
2674 form = (document.getElementById(form) || document.forms[form]);
2677 var el, name, val, disabled, data = '', hasSubmit = false;
2678 for (var i = 0; i < form.elements.length; i++) {
2679 el = form.elements[i];
2680 disabled = form.elements[i].disabled;
2681 name = form.elements[i].name;
2682 val = form.elements[i].value;
2684 if (!disabled && name){
2688 case 'select-multiple':
2689 for (var j = 0; j < el.options.length; j++) {
2690 if (el.options[j].selected) {
2692 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2695 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2703 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2716 if(hasSubmit == false) {
2717 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2722 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2727 data = data.substr(0, data.length - 1);
2735 useDefaultHeader:true,
2737 defaultPostHeader:'application/x-www-form-urlencoded',
2739 useDefaultXhrHeader:true,
2741 defaultXhrHeader:'XMLHttpRequest',
2743 hasDefaultHeaders:true,
2755 setProgId:function(id)
2757 this.activeX.unshift(id);
2760 setDefaultPostHeader:function(b)
2762 this.useDefaultHeader = b;
2765 setDefaultXhrHeader:function(b)
2767 this.useDefaultXhrHeader = b;
2770 setPollingInterval:function(i)
2772 if (typeof i == 'number' && isFinite(i)) {
2773 this.pollInterval = i;
2777 createXhrObject:function(transactionId)
2783 http = new XMLHttpRequest();
2785 obj = { conn:http, tId:transactionId };
2789 for (var i = 0; i < this.activeX.length; ++i) {
2793 http = new ActiveXObject(this.activeX[i]);
2795 obj = { conn:http, tId:transactionId };
2808 getConnectionObject:function()
2811 var tId = this.transactionId;
2815 o = this.createXhrObject(tId);
2817 this.transactionId++;
2828 asyncRequest:function(method, uri, callback, postData)
2830 var o = this.getConnectionObject();
2836 o.conn.open(method, uri, true);
2838 if (this.useDefaultXhrHeader) {
2839 if (!this.defaultHeaders['X-Requested-With']) {
2840 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2844 if(postData && this.useDefaultHeader){
2845 this.initHeader('Content-Type', this.defaultPostHeader);
2848 if (this.hasDefaultHeaders || this.hasHeaders) {
2852 this.handleReadyState(o, callback);
2853 o.conn.send(postData || null);
2859 handleReadyState:function(o, callback)
2863 if (callback && callback.timeout) {
2865 this.timeout[o.tId] = window.setTimeout(function() {
2866 oConn.abort(o, callback, true);
2867 }, callback.timeout);
2870 this.poll[o.tId] = window.setInterval(
2872 if (o.conn && o.conn.readyState == 4) {
2873 window.clearInterval(oConn.poll[o.tId]);
2874 delete oConn.poll[o.tId];
2876 if(callback && callback.timeout) {
2877 window.clearTimeout(oConn.timeout[o.tId]);
2878 delete oConn.timeout[o.tId];
2881 oConn.handleTransactionResponse(o, callback);
2884 , this.pollInterval);
2887 handleTransactionResponse:function(o, callback, isAbort)
2891 this.releaseObject(o);
2895 var httpStatus, responseObject;
2899 if (o.conn.status !== undefined && o.conn.status != 0) {
2900 httpStatus = o.conn.status;
2912 if (httpStatus >= 200 && httpStatus < 300) {
2913 responseObject = this.createResponseObject(o, callback.argument);
2914 if (callback.success) {
2915 if (!callback.scope) {
2916 callback.success(responseObject);
2921 callback.success.apply(callback.scope, [responseObject]);
2926 switch (httpStatus) {
2934 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2935 if (callback.failure) {
2936 if (!callback.scope) {
2937 callback.failure(responseObject);
2940 callback.failure.apply(callback.scope, [responseObject]);
2945 responseObject = this.createResponseObject(o, callback.argument);
2946 if (callback.failure) {
2947 if (!callback.scope) {
2948 callback.failure(responseObject);
2951 callback.failure.apply(callback.scope, [responseObject]);
2957 this.releaseObject(o);
2958 responseObject = null;
2961 createResponseObject:function(o, callbackArg)
2968 var headerStr = o.conn.getAllResponseHeaders();
2969 var header = headerStr.split('\n');
2970 for (var i = 0; i < header.length; i++) {
2971 var delimitPos = header[i].indexOf(':');
2972 if (delimitPos != -1) {
2973 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2981 obj.status = o.conn.status;
2982 obj.statusText = o.conn.statusText;
2983 obj.getResponseHeader = headerObj;
2984 obj.getAllResponseHeaders = headerStr;
2985 obj.responseText = o.conn.responseText;
2986 obj.responseXML = o.conn.responseXML;
2988 if (typeof callbackArg !== undefined) {
2989 obj.argument = callbackArg;
2995 createExceptionObject:function(tId, callbackArg, isAbort)
2998 var COMM_ERROR = 'communication failure';
2999 var ABORT_CODE = -1;
3000 var ABORT_ERROR = 'transaction aborted';
3006 obj.status = ABORT_CODE;
3007 obj.statusText = ABORT_ERROR;
3010 obj.status = COMM_CODE;
3011 obj.statusText = COMM_ERROR;
3015 obj.argument = callbackArg;
3021 initHeader:function(label, value, isDefault)
3023 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
3025 if (headerObj[label] === undefined) {
3026 headerObj[label] = value;
3031 headerObj[label] = value + "," + headerObj[label];
3035 this.hasDefaultHeaders = true;
3038 this.hasHeaders = true;
3043 setHeader:function(o)
3045 if (this.hasDefaultHeaders) {
3046 for (var prop in this.defaultHeaders) {
3047 if (this.defaultHeaders.hasOwnProperty(prop)) {
3048 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3053 if (this.hasHeaders) {
3054 for (var prop in this.headers) {
3055 if (this.headers.hasOwnProperty(prop)) {
3056 o.conn.setRequestHeader(prop, this.headers[prop]);
3060 this.hasHeaders = false;
3064 resetDefaultHeaders:function() {
3065 delete this.defaultHeaders;
3066 this.defaultHeaders = {};
3067 this.hasDefaultHeaders = false;
3070 abort:function(o, callback, isTimeout)
3072 if(this.isCallInProgress(o)) {
3074 window.clearInterval(this.poll[o.tId]);
3075 delete this.poll[o.tId];
3077 delete this.timeout[o.tId];
3080 this.handleTransactionResponse(o, callback, true);
3090 isCallInProgress:function(o)
3093 return o.conn.readyState != 4 && o.conn.readyState != 0;
3102 releaseObject:function(o)
3111 'MSXML2.XMLHTTP.3.0',
3119 * Portions of this file are based on pieces of Yahoo User Interface Library
3120 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3121 * YUI licensed under the BSD License:
3122 * http://developer.yahoo.net/yui/license.txt
3123 * <script type="text/javascript">
3127 Roo.lib.Region = function(t, r, b, l) {
3137 Roo.lib.Region.prototype = {
3138 contains : function(region) {
3139 return ( region.left >= this.left &&
3140 region.right <= this.right &&
3141 region.top >= this.top &&
3142 region.bottom <= this.bottom );
3146 getArea : function() {
3147 return ( (this.bottom - this.top) * (this.right - this.left) );
3150 intersect : function(region) {
3151 var t = Math.max(this.top, region.top);
3152 var r = Math.min(this.right, region.right);
3153 var b = Math.min(this.bottom, region.bottom);
3154 var l = Math.max(this.left, region.left);
3156 if (b >= t && r >= l) {
3157 return new Roo.lib.Region(t, r, b, l);
3162 union : function(region) {
3163 var t = Math.min(this.top, region.top);
3164 var r = Math.max(this.right, region.right);
3165 var b = Math.max(this.bottom, region.bottom);
3166 var l = Math.min(this.left, region.left);
3168 return new Roo.lib.Region(t, r, b, l);
3171 adjust : function(t, l, b, r) {
3180 Roo.lib.Region.getRegion = function(el) {
3181 var p = Roo.lib.Dom.getXY(el);
3184 var r = p[0] + el.offsetWidth;
3185 var b = p[1] + el.offsetHeight;
3188 return new Roo.lib.Region(t, r, b, l);
3191 * Portions of this file are based on pieces of Yahoo User Interface Library
3192 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3193 * YUI licensed under the BSD License:
3194 * http://developer.yahoo.net/yui/license.txt
3195 * <script type="text/javascript">
3198 //@@dep Roo.lib.Region
3201 Roo.lib.Point = function(x, y) {
3202 if (x instanceof Array) {
3206 this.x = this.right = this.left = this[0] = x;
3207 this.y = this.top = this.bottom = this[1] = y;
3210 Roo.lib.Point.prototype = new Roo.lib.Region();
3212 * Portions of this file are based on pieces of Yahoo User Interface Library
3213 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3214 * YUI licensed under the BSD License:
3215 * http://developer.yahoo.net/yui/license.txt
3216 * <script type="text/javascript">
3223 scroll : function(el, args, duration, easing, cb, scope) {
3224 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3227 motion : function(el, args, duration, easing, cb, scope) {
3228 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3231 color : function(el, args, duration, easing, cb, scope) {
3232 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3235 run : function(el, args, duration, easing, cb, scope, type) {
3236 type = type || Roo.lib.AnimBase;
3237 if (typeof easing == "string") {
3238 easing = Roo.lib.Easing[easing];
3240 var anim = new type(el, args, duration, easing);
3241 anim.animateX(function() {
3242 Roo.callback(cb, scope);
3248 * Portions of this file are based on pieces of Yahoo User Interface Library
3249 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3250 * YUI licensed under the BSD License:
3251 * http://developer.yahoo.net/yui/license.txt
3252 * <script type="text/javascript">
3260 if (!libFlyweight) {
3261 libFlyweight = new Roo.Element.Flyweight();
3263 libFlyweight.dom = el;
3264 return libFlyweight;
3267 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3271 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3273 this.init(el, attributes, duration, method);
3277 Roo.lib.AnimBase.fly = fly;
3281 Roo.lib.AnimBase.prototype = {
3283 toString: function() {
3284 var el = this.getEl();
3285 var id = el.id || el.tagName;
3286 return ("Anim " + id);
3290 noNegatives: /width|height|opacity|padding/i,
3291 offsetAttribute: /^((width|height)|(top|left))$/,
3292 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3293 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3297 doMethod: function(attr, start, end) {
3298 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3302 setAttribute: function(attr, val, unit) {
3303 if (this.patterns.noNegatives.test(attr)) {
3304 val = (val > 0) ? val : 0;
3307 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3311 getAttribute: function(attr) {
3312 var el = this.getEl();
3313 var val = fly(el).getStyle(attr);
3315 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3316 return parseFloat(val);
3319 var a = this.patterns.offsetAttribute.exec(attr) || [];
3320 var pos = !!( a[3] );
3321 var box = !!( a[2] );
3324 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3325 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3334 getDefaultUnit: function(attr) {
3335 if (this.patterns.defaultUnit.test(attr)) {
3342 animateX : function(callback, scope) {
3343 var f = function() {
3344 this.onComplete.removeListener(f);
3345 if (typeof callback == "function") {
3346 callback.call(scope || this, this);
3349 this.onComplete.addListener(f, this);
3354 setRuntimeAttribute: function(attr) {
3357 var attributes = this.attributes;
3359 this.runtimeAttributes[attr] = {};
3361 var isset = function(prop) {
3362 return (typeof prop !== 'undefined');
3365 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3369 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3372 if (isset(attributes[attr]['to'])) {
3373 end = attributes[attr]['to'];
3374 } else if (isset(attributes[attr]['by'])) {
3375 if (start.constructor == Array) {
3377 for (var i = 0, len = start.length; i < len; ++i) {
3378 end[i] = start[i] + attributes[attr]['by'][i];
3381 end = start + attributes[attr]['by'];
3385 this.runtimeAttributes[attr].start = start;
3386 this.runtimeAttributes[attr].end = end;
3389 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3393 init: function(el, attributes, duration, method) {
3395 var isAnimated = false;
3398 var startTime = null;
3401 var actualFrames = 0;
3404 el = Roo.getDom(el);
3407 this.attributes = attributes || {};
3410 this.duration = duration || 1;
3413 this.method = method || Roo.lib.Easing.easeNone;
3416 this.useSeconds = true;
3419 this.currentFrame = 0;
3422 this.totalFrames = Roo.lib.AnimMgr.fps;
3425 this.getEl = function() {
3430 this.isAnimated = function() {
3435 this.getStartTime = function() {
3439 this.runtimeAttributes = {};
3442 this.animate = function() {
3443 if (this.isAnimated()) {
3447 this.currentFrame = 0;
3449 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3451 Roo.lib.AnimMgr.registerElement(this);
3455 this.stop = function(finish) {
3457 this.currentFrame = this.totalFrames;
3458 this._onTween.fire();
3460 Roo.lib.AnimMgr.stop(this);
3463 var onStart = function() {
3464 this.onStart.fire();
3466 this.runtimeAttributes = {};
3467 for (var attr in this.attributes) {
3468 this.setRuntimeAttribute(attr);
3473 startTime = new Date();
3477 var onTween = function() {
3479 duration: new Date() - this.getStartTime(),
3480 currentFrame: this.currentFrame
3483 data.toString = function() {
3485 'duration: ' + data.duration +
3486 ', currentFrame: ' + data.currentFrame
3490 this.onTween.fire(data);
3492 var runtimeAttributes = this.runtimeAttributes;
3494 for (var attr in runtimeAttributes) {
3495 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3501 var onComplete = function() {
3502 var actual_duration = (new Date() - startTime) / 1000 ;
3505 duration: actual_duration,
3506 frames: actualFrames,
3507 fps: actualFrames / actual_duration
3510 data.toString = function() {
3512 'duration: ' + data.duration +
3513 ', frames: ' + data.frames +
3514 ', fps: ' + data.fps
3520 this.onComplete.fire(data);
3524 this._onStart = new Roo.util.Event(this);
3525 this.onStart = new Roo.util.Event(this);
3526 this.onTween = new Roo.util.Event(this);
3527 this._onTween = new Roo.util.Event(this);
3528 this.onComplete = new Roo.util.Event(this);
3529 this._onComplete = new Roo.util.Event(this);
3530 this._onStart.addListener(onStart);
3531 this._onTween.addListener(onTween);
3532 this._onComplete.addListener(onComplete);
3537 * Portions of this file are based on pieces of Yahoo User Interface Library
3538 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3539 * YUI licensed under the BSD License:
3540 * http://developer.yahoo.net/yui/license.txt
3541 * <script type="text/javascript">
3545 Roo.lib.AnimMgr = new function() {
3562 this.registerElement = function(tween) {
3563 queue[queue.length] = tween;
3565 tween._onStart.fire();
3570 this.unRegister = function(tween, index) {
3571 tween._onComplete.fire();
3572 index = index || getIndex(tween);
3574 queue.splice(index, 1);
3578 if (tweenCount <= 0) {
3584 this.start = function() {
3585 if (thread === null) {
3586 thread = setInterval(this.run, this.delay);
3591 this.stop = function(tween) {
3593 clearInterval(thread);
3595 for (var i = 0, len = queue.length; i < len; ++i) {
3596 if (queue[0].isAnimated()) {
3597 this.unRegister(queue[0], 0);
3606 this.unRegister(tween);
3611 this.run = function() {
3612 for (var i = 0, len = queue.length; i < len; ++i) {
3613 var tween = queue[i];
3614 if (!tween || !tween.isAnimated()) {
3618 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3620 tween.currentFrame += 1;
3622 if (tween.useSeconds) {
3623 correctFrame(tween);
3625 tween._onTween.fire();
3628 Roo.lib.AnimMgr.stop(tween, i);
3633 var getIndex = function(anim) {
3634 for (var i = 0, len = queue.length; i < len; ++i) {
3635 if (queue[i] == anim) {
3643 var correctFrame = function(tween) {
3644 var frames = tween.totalFrames;
3645 var frame = tween.currentFrame;
3646 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3647 var elapsed = (new Date() - tween.getStartTime());
3650 if (elapsed < tween.duration * 1000) {
3651 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3653 tweak = frames - (frame + 1);
3655 if (tweak > 0 && isFinite(tweak)) {
3656 if (tween.currentFrame + tweak >= frames) {
3657 tweak = frames - (frame + 1);
3660 tween.currentFrame += tweak;
3666 * Portions of this file are based on pieces of Yahoo User Interface Library
3667 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3668 * YUI licensed under the BSD License:
3669 * http://developer.yahoo.net/yui/license.txt
3670 * <script type="text/javascript">
3673 Roo.lib.Bezier = new function() {
3675 this.getPosition = function(points, t) {
3676 var n = points.length;
3679 for (var i = 0; i < n; ++i) {
3680 tmp[i] = [points[i][0], points[i][1]];
3683 for (var j = 1; j < n; ++j) {
3684 for (i = 0; i < n - j; ++i) {
3685 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3686 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3690 return [ tmp[0][0], tmp[0][1] ];
3696 * @class Roo.lib.Color
3698 * An abstract Color implementation. Concrete Color implementations should use
3699 * an instance of this function as their prototype, and implement the getRGB and
3700 * getHSL functions. getRGB should return an object representing the RGB
3701 * components of this Color, with the red, green, and blue components in the
3702 * range [0,255] and the alpha component in the range [0,100]. getHSL should
3703 * return an object representing the HSL components of this Color, with the hue
3704 * component in the range [0,360), the saturation and lightness components in
3705 * the range [0,100], and the alpha component in the range [0,1].
3710 * Functions for Color handling and processing.
3712 * http://www.safalra.com/web-design/javascript/Color-handling-and-processing/
3714 * The author of this program, Safalra (Stephen Morley), irrevocably releases all
3715 * rights to this program, with the intention of it becoming part of the public
3716 * domain. Because this program is released into the public domain, it comes with
3717 * no warranty either expressed or implied, to the extent permitted by law.
3719 * For more free and public domain JavaScript code by the same author, visit:
3720 * http://www.safalra.com/web-design/javascript/
3723 Roo.lib.Color = function() { }
3726 Roo.apply(Roo.lib.Color.prototype, {
3734 * @return {Object} an object representing the RGBA components of this Color. The red,
3735 * green, and blue components are converted to integers in the range [0,255].
3736 * The alpha is a value in the range [0,1].
3738 getIntegerRGB : function(){
3740 // get the RGB components of this Color
3741 var rgb = this.getRGB();
3743 // return the integer components
3745 'r' : Math.round(rgb.r),
3746 'g' : Math.round(rgb.g),
3747 'b' : Math.round(rgb.b),
3755 * @return {Object} an object representing the RGBA components of this Color. The red,
3756 * green, and blue components are converted to numbers in the range [0,100].
3757 * The alpha is a value in the range [0,1].
3759 getPercentageRGB : function(){
3761 // get the RGB components of this Color
3762 var rgb = this.getRGB();
3764 // return the percentage components
3766 'r' : 100 * rgb.r / 255,
3767 'g' : 100 * rgb.g / 255,
3768 'b' : 100 * rgb.b / 255,
3775 * getCSSHexadecimalRGB
3776 * @return {String} a string representing this Color as a CSS hexadecimal RGB Color
3777 * value - that is, a string of the form #RRGGBB where each of RR, GG, and BB
3778 * are two-digit hexadecimal numbers.
3780 getCSSHexadecimalRGB : function()
3783 // get the integer RGB components
3784 var rgb = this.getIntegerRGB();
3786 // determine the hexadecimal equivalents
3787 var r16 = rgb.r.toString(16);
3788 var g16 = rgb.g.toString(16);
3789 var b16 = rgb.b.toString(16);
3791 // return the CSS RGB Color value
3793 + (r16.length == 2 ? r16 : '0' + r16)
3794 + (g16.length == 2 ? g16 : '0' + g16)
3795 + (b16.length == 2 ? b16 : '0' + b16);
3801 * @return {String} a string representing this Color as a CSS integer RGB Color
3802 * value - that is, a string of the form rgb(r,g,b) where each of r, g, and b
3803 * are integers in the range [0,255].
3805 getCSSIntegerRGB : function(){
3807 // get the integer RGB components
3808 var rgb = this.getIntegerRGB();
3810 // return the CSS RGB Color value
3811 return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')';
3817 * @return {String} Returns a string representing this Color as a CSS integer RGBA Color
3818 * value - that is, a string of the form rgba(r,g,b,a) where each of r, g, and
3819 * b are integers in the range [0,255] and a is in the range [0,1].
3821 getCSSIntegerRGBA : function(){
3823 // get the integer RGB components
3824 var rgb = this.getIntegerRGB();
3826 // return the CSS integer RGBA Color value
3827 return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + rgb.a + ')';
3832 * getCSSPercentageRGB
3833 * @return {String} a string representing this Color as a CSS percentage RGB Color
3834 * value - that is, a string of the form rgb(r%,g%,b%) where each of r, g, and
3835 * b are in the range [0,100].
3837 getCSSPercentageRGB : function(){
3839 // get the percentage RGB components
3840 var rgb = this.getPercentageRGB();
3842 // return the CSS RGB Color value
3843 return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%)';
3848 * getCSSPercentageRGBA
3849 * @return {String} a string representing this Color as a CSS percentage RGBA Color
3850 * value - that is, a string of the form rgba(r%,g%,b%,a) where each of r, g,
3851 * and b are in the range [0,100] and a is in the range [0,1].
3853 getCSSPercentageRGBA : function(){
3855 // get the percentage RGB components
3856 var rgb = this.getPercentageRGB();
3858 // return the CSS percentage RGBA Color value
3859 return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%,' + rgb.a + ')';
3865 * @return {String} a string representing this Color as a CSS HSL Color value - that
3866 * is, a string of the form hsl(h,s%,l%) where h is in the range [0,100] and
3867 * s and l are in the range [0,100].
3869 getCSSHSL : function(){
3871 // get the HSL components
3872 var hsl = this.getHSL();
3874 // return the CSS HSL Color value
3875 return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%)';
3881 * @return {String} a string representing this Color as a CSS HSLA Color value - that
3882 * is, a string of the form hsla(h,s%,l%,a) where h is in the range [0,100],
3883 * s and l are in the range [0,100], and a is in the range [0,1].
3885 getCSSHSLA : function(){
3887 // get the HSL components
3888 var hsl = this.getHSL();
3890 // return the CSS HSL Color value
3891 return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%,' + hsl.a + ')';
3896 * Sets the Color of the specified node to this Color. This functions sets
3897 * the CSS 'color' property for the node. The parameter is:
3899 * @param {DomElement} node - the node whose Color should be set
3901 setNodeColor : function(node){
3903 // set the Color of the node
3904 node.style.color = this.getCSSHexadecimalRGB();
3909 * Sets the background Color of the specified node to this Color. This
3910 * functions sets the CSS 'background-color' property for the node. The
3913 * @param {DomElement} node - the node whose background Color should be set
3915 setNodeBackgroundColor : function(node){
3917 // set the background Color of the node
3918 node.style.backgroundColor = this.getCSSHexadecimalRGB();
3921 // convert between formats..
3924 var r = this.getIntegerRGB();
3925 return new Roo.lib.RGBColor(r.r,r.g,r.b,r.a);
3930 var hsl = this.getHSL();
3931 // return the CSS HSL Color value
3932 return new Roo.lib.HSLColor(hsl.h, hsl.s, hsl.l , hsl.a );
3938 var rgb = this.toRGB();
3939 var hsv = rgb.getHSV();
3940 // return the CSS HSL Color value
3941 return new Roo.lib.HSVColor(hsv.h, hsv.s, hsv.v , hsv.a );
3945 // modify v = 0 ... 1 (eg. 0.5)
3946 saturate : function(v)
3948 var rgb = this.toRGB();
3949 var hsv = rgb.getHSV();
3950 return new Roo.lib.HSVColor(hsv.h, hsv.s * v, hsv.v , hsv.a );
3958 * @return {Object} the RGB and alpha components of this Color as an object with r,
3959 * g, b, and a properties. r, g, and b are in the range [0,255] and a is in
3964 // return the RGB components
3976 * @return {Object} the HSV and alpha components of this Color as an object with h,
3977 * s, v, and a properties. h is in the range [0,360), s and v are in the range
3978 * [0,100], and a is in the range [0,1].
3983 // calculate the HSV components if necessary
3984 if (this.hsv == null) {
3985 this.calculateHSV();
3988 // return the HSV components
4000 * @return {Object} the HSL and alpha components of this Color as an object with h,
4001 * s, l, and a properties. h is in the range [0,360), s and l are in the range
4002 * [0,100], and a is in the range [0,1].
4004 getHSL : function(){
4007 // calculate the HSV components if necessary
4008 if (this.hsl == null) { this.calculateHSL(); }
4010 // return the HSL components
4025 * @class Roo.lib.RGBColor
4026 * @extends Roo.lib.Color
4027 * Creates a Color specified in the RGB Color space, with an optional alpha
4028 * component. The parameters are:
4032 * @param {Number} r - the red component, clipped to the range [0,255]
4033 * @param {Number} g - the green component, clipped to the range [0,255]
4034 * @param {Number} b - the blue component, clipped to the range [0,255]
4035 * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4036 * optional and defaults to 1
4038 Roo.lib.RGBColor = function (r, g, b, a){
4040 // store the alpha component after clipping it if necessary
4041 this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4043 // store the RGB components after clipping them if necessary
4046 'r' : Math.max(0, Math.min(255, r)),
4047 'g' : Math.max(0, Math.min(255, g)),
4048 'b' : Math.max(0, Math.min(255, b))
4051 // initialise the HSV and HSL components to null
4055 * //private returns the HSV or HSL hue component of this RGBColor. The hue is in the
4056 * range [0,360). The parameters are:
4058 * maximum - the maximum of the RGB component values
4059 * range - the range of the RGB component values
4064 // this does an 'exteds'
4065 Roo.extend(Roo.lib.RGBColor, Roo.lib.Color, {
4068 getHue : function(maximum, range)
4072 // check whether the range is zero
4075 // set the hue to zero (any hue is acceptable as the Color is grey)
4080 // determine which of the components has the highest value and set the hue
4083 // red has the highest value
4085 var hue = (rgb.g - rgb.b) / range * 60;
4086 if (hue < 0) { hue += 360; }
4089 // green has the highest value
4091 var hue = (rgb.b - rgb.r) / range * 60 + 120;
4094 // blue has the highest value
4096 var hue = (rgb.r - rgb.g) / range * 60 + 240;
4108 /* //private Calculates and stores the HSV components of this RGBColor so that they can
4109 * be returned be the getHSV function.
4111 calculateHSV : function(){
4113 // get the maximum and range of the RGB component values
4114 var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4115 var range = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4117 // store the HSV components
4120 'h' : this.getHue(maximum, range),
4121 's' : (maximum == 0 ? 0 : 100 * range / maximum),
4122 'v' : maximum / 2.55
4127 /* //private Calculates and stores the HSL components of this RGBColor so that they can
4128 * be returned be the getHSL function.
4130 calculateHSL : function(){
4132 // get the maximum and range of the RGB component values
4133 var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4134 var range = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4136 // determine the lightness in the range [0,1]
4137 var l = maximum / 255 - range / 510;
4139 // store the HSL components
4142 'h' : this.getHue(maximum, range),
4143 's' : (range == 0 ? 0 : range / 2.55 / (l < 0.5 ? l * 2 : 2 - l * 2)),
4152 * @class Roo.lib.HSVColor
4153 * @extends Roo.lib.Color
4154 * Creates a Color specified in the HSV Color space, with an optional alpha
4155 * component. The parameters are:
4158 * @param {Number} h - the hue component, wrapped to the range [0,360)
4159 * @param {Number} s - the saturation component, clipped to the range [0,100]
4160 * @param {Number} v - the value component, clipped to the range [0,100]
4161 * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4162 * optional and defaults to 1
4164 Roo.lib.HSVColor = function (h, s, v, a){
4166 // store the alpha component after clipping it if necessary
4167 this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4169 // store the HSV components after clipping or wrapping them if necessary
4172 'h' : (h % 360 + 360) % 360,
4173 's' : Math.max(0, Math.min(100, s)),
4174 'v' : Math.max(0, Math.min(100, v))
4177 // initialise the RGB and HSL components to null
4182 Roo.extend(Roo.lib.HSVColor, Roo.lib.Color, {
4183 /* Calculates and stores the RGB components of this HSVColor so that they can
4184 * be returned be the getRGB function.
4186 calculateRGB: function ()
4189 // check whether the saturation is zero
4192 // set the Color to the appropriate shade of grey
4199 // set some temporary values
4200 var f = hsv.h / 60 - Math.floor(hsv.h / 60);
4201 var p = hsv.v * (1 - hsv.s / 100);
4202 var q = hsv.v * (1 - hsv.s / 100 * f);
4203 var t = hsv.v * (1 - hsv.s / 100 * (1 - f));
4205 // set the RGB Color components to their temporary values
4206 switch (Math.floor(hsv.h / 60)){
4207 case 0: var r = hsv.v; var g = t; var b = p; break;
4208 case 1: var r = q; var g = hsv.v; var b = p; break;
4209 case 2: var r = p; var g = hsv.v; var b = t; break;
4210 case 3: var r = p; var g = q; var b = hsv.v; break;
4211 case 4: var r = t; var g = p; var b = hsv.v; break;
4212 case 5: var r = hsv.v; var g = p; var b = q; break;
4217 // store the RGB components
4227 /* Calculates and stores the HSL components of this HSVColor so that they can
4228 * be returned be the getHSL function.
4230 calculateHSL : function (){
4233 // determine the lightness in the range [0,100]
4234 var l = (2 - hsv.s / 100) * hsv.v / 2;
4236 // store the HSL components
4240 's' : hsv.s * hsv.v / (l < 50 ? l * 2 : 200 - l * 2),
4244 // correct a division-by-zero error
4245 if (isNaN(hsl.s)) { hsl.s = 0; }
4254 * @class Roo.lib.HSLColor
4255 * @extends Roo.lib.Color
4258 * Creates a Color specified in the HSL Color space, with an optional alpha
4259 * component. The parameters are:
4261 * @param {Number} h - the hue component, wrapped to the range [0,360)
4262 * @param {Number} s - the saturation component, clipped to the range [0,100]
4263 * @param {Number} l - the lightness component, clipped to the range [0,100]
4264 * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4265 * optional and defaults to 1
4268 Roo.lib.HSLColor = function(h, s, l, a){
4270 // store the alpha component after clipping it if necessary
4271 this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4273 // store the HSL components after clipping or wrapping them if necessary
4276 'h' : (h % 360 + 360) % 360,
4277 's' : Math.max(0, Math.min(100, s)),
4278 'l' : Math.max(0, Math.min(100, l))
4281 // initialise the RGB and HSV components to null
4284 Roo.extend(Roo.lib.HSLColor, Roo.lib.Color, {
4286 /* Calculates and stores the RGB components of this HSLColor so that they can
4287 * be returned be the getRGB function.
4289 calculateRGB: function (){
4291 // check whether the saturation is zero
4292 if (this.hsl.s == 0){
4294 // store the RGB components representing the appropriate shade of grey
4297 'r' : this.hsl.l * 2.55,
4298 'g' : this.hsl.l * 2.55,
4299 'b' : this.hsl.l * 2.55
4304 // set some temporary values
4305 var p = this.hsl.l < 50
4306 ? this.hsl.l * (1 + hsl.s / 100)
4307 : this.hsl.l + hsl.s - hsl.l * hsl.s / 100;
4308 var q = 2 * hsl.l - p;
4310 // initialise the RGB components
4313 'r' : (h + 120) / 60 % 6,
4315 'b' : (h + 240) / 60 % 6
4318 // loop over the RGB components
4319 for (var key in this.rgb){
4321 // ensure that the property is not inherited from the root object
4322 if (this.rgb.hasOwnProperty(key)){
4324 // set the component to its value in the range [0,100]
4325 if (this.rgb[key] < 1){
4326 this.rgb[key] = q + (p - q) * this.rgb[key];
4327 }else if (this.rgb[key] < 3){
4329 }else if (this.rgb[key] < 4){
4330 this.rgb[key] = q + (p - q) * (4 - this.rgb[key]);
4335 // set the component to its value in the range [0,255]
4336 this.rgb[key] *= 2.55;
4346 /* Calculates and stores the HSV components of this HSLColor so that they can
4347 * be returned be the getHSL function.
4349 calculateHSV : function(){
4351 // set a temporary value
4352 var t = this.hsl.s * (this.hsl.l < 50 ? this.hsl.l : 100 - this.hsl.l) / 100;
4354 // store the HSV components
4358 's' : 200 * t / (this.hsl.l + t),
4359 'v' : t + this.hsl.l
4362 // correct a division-by-zero error
4363 if (isNaN(this.hsv.s)) { this.hsv.s = 0; }
4370 * Portions of this file are based on pieces of Yahoo User Interface Library
4371 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4372 * YUI licensed under the BSD License:
4373 * http://developer.yahoo.net/yui/license.txt
4374 * <script type="text/javascript">
4379 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
4380 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
4383 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
4385 var fly = Roo.lib.AnimBase.fly;
4387 var superclass = Y.ColorAnim.superclass;
4388 var proto = Y.ColorAnim.prototype;
4390 proto.toString = function() {
4391 var el = this.getEl();
4392 var id = el.id || el.tagName;
4393 return ("ColorAnim " + id);
4396 proto.patterns.color = /color$/i;
4397 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
4398 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
4399 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
4400 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
4403 proto.parseColor = function(s) {
4404 if (s.length == 3) {
4408 var c = this.patterns.hex.exec(s);
4409 if (c && c.length == 4) {
4410 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
4413 c = this.patterns.rgb.exec(s);
4414 if (c && c.length == 4) {
4415 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
4418 c = this.patterns.hex3.exec(s);
4419 if (c && c.length == 4) {
4420 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
4425 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
4426 proto.getAttribute = function(attr) {
4427 var el = this.getEl();
4428 if (this.patterns.color.test(attr)) {
4429 var val = fly(el).getStyle(attr);
4431 if (this.patterns.transparent.test(val)) {
4432 var parent = el.parentNode;
4433 val = fly(parent).getStyle(attr);
4435 while (parent && this.patterns.transparent.test(val)) {
4436 parent = parent.parentNode;
4437 val = fly(parent).getStyle(attr);
4438 if (parent.tagName.toUpperCase() == 'HTML') {
4444 val = superclass.getAttribute.call(this, attr);
4449 proto.getAttribute = function(attr) {
4450 var el = this.getEl();
4451 if (this.patterns.color.test(attr)) {
4452 var val = fly(el).getStyle(attr);
4454 if (this.patterns.transparent.test(val)) {
4455 var parent = el.parentNode;
4456 val = fly(parent).getStyle(attr);
4458 while (parent && this.patterns.transparent.test(val)) {
4459 parent = parent.parentNode;
4460 val = fly(parent).getStyle(attr);
4461 if (parent.tagName.toUpperCase() == 'HTML') {
4467 val = superclass.getAttribute.call(this, attr);
4473 proto.doMethod = function(attr, start, end) {
4476 if (this.patterns.color.test(attr)) {
4478 for (var i = 0, len = start.length; i < len; ++i) {
4479 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
4482 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
4485 val = superclass.doMethod.call(this, attr, start, end);
4491 proto.setRuntimeAttribute = function(attr) {
4492 superclass.setRuntimeAttribute.call(this, attr);
4494 if (this.patterns.color.test(attr)) {
4495 var attributes = this.attributes;
4496 var start = this.parseColor(this.runtimeAttributes[attr].start);
4497 var end = this.parseColor(this.runtimeAttributes[attr].end);
4499 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
4500 end = this.parseColor(attributes[attr].by);
4502 for (var i = 0, len = start.length; i < len; ++i) {
4503 end[i] = start[i] + end[i];
4507 this.runtimeAttributes[attr].start = start;
4508 this.runtimeAttributes[attr].end = end;
4514 * Portions of this file are based on pieces of Yahoo User Interface Library
4515 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4516 * YUI licensed under the BSD License:
4517 * http://developer.yahoo.net/yui/license.txt
4518 * <script type="text/javascript">
4524 easeNone: function (t, b, c, d) {
4525 return c * t / d + b;
4529 easeIn: function (t, b, c, d) {
4530 return c * (t /= d) * t + b;
4534 easeOut: function (t, b, c, d) {
4535 return -c * (t /= d) * (t - 2) + b;
4539 easeBoth: function (t, b, c, d) {
4540 if ((t /= d / 2) < 1) {
4541 return c / 2 * t * t + b;
4544 return -c / 2 * ((--t) * (t - 2) - 1) + b;
4548 easeInStrong: function (t, b, c, d) {
4549 return c * (t /= d) * t * t * t + b;
4553 easeOutStrong: function (t, b, c, d) {
4554 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
4558 easeBothStrong: function (t, b, c, d) {
4559 if ((t /= d / 2) < 1) {
4560 return c / 2 * t * t * t * t + b;
4563 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
4568 elasticIn: function (t, b, c, d, a, p) {
4572 if ((t /= d) == 1) {
4579 if (!a || a < Math.abs(c)) {
4584 var s = p / (2 * Math.PI) * Math.asin(c / a);
4587 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4591 elasticOut: function (t, b, c, d, a, p) {
4595 if ((t /= d) == 1) {
4602 if (!a || a < Math.abs(c)) {
4607 var s = p / (2 * Math.PI) * Math.asin(c / a);
4610 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
4614 elasticBoth: function (t, b, c, d, a, p) {
4619 if ((t /= d / 2) == 2) {
4627 if (!a || a < Math.abs(c)) {
4632 var s = p / (2 * Math.PI) * Math.asin(c / a);
4636 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
4637 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4639 return a * Math.pow(2, -10 * (t -= 1)) *
4640 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
4645 backIn: function (t, b, c, d, s) {
4646 if (typeof s == 'undefined') {
4649 return c * (t /= d) * t * ((s + 1) * t - s) + b;
4653 backOut: function (t, b, c, d, s) {
4654 if (typeof s == 'undefined') {
4657 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
4661 backBoth: function (t, b, c, d, s) {
4662 if (typeof s == 'undefined') {
4666 if ((t /= d / 2 ) < 1) {
4667 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
4669 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
4673 bounceIn: function (t, b, c, d) {
4674 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
4678 bounceOut: function (t, b, c, d) {
4679 if ((t /= d) < (1 / 2.75)) {
4680 return c * (7.5625 * t * t) + b;
4681 } else if (t < (2 / 2.75)) {
4682 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
4683 } else if (t < (2.5 / 2.75)) {
4684 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
4686 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
4690 bounceBoth: function (t, b, c, d) {
4692 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
4694 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
4697 * Portions of this file are based on pieces of Yahoo User Interface Library
4698 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4699 * YUI licensed under the BSD License:
4700 * http://developer.yahoo.net/yui/license.txt
4701 * <script type="text/javascript">
4705 Roo.lib.Motion = function(el, attributes, duration, method) {
4707 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
4711 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
4715 var superclass = Y.Motion.superclass;
4716 var proto = Y.Motion.prototype;
4718 proto.toString = function() {
4719 var el = this.getEl();
4720 var id = el.id || el.tagName;
4721 return ("Motion " + id);
4724 proto.patterns.points = /^points$/i;
4726 proto.setAttribute = function(attr, val, unit) {
4727 if (this.patterns.points.test(attr)) {
4728 unit = unit || 'px';
4729 superclass.setAttribute.call(this, 'left', val[0], unit);
4730 superclass.setAttribute.call(this, 'top', val[1], unit);
4732 superclass.setAttribute.call(this, attr, val, unit);
4736 proto.getAttribute = function(attr) {
4737 if (this.patterns.points.test(attr)) {
4739 superclass.getAttribute.call(this, 'left'),
4740 superclass.getAttribute.call(this, 'top')
4743 val = superclass.getAttribute.call(this, attr);
4749 proto.doMethod = function(attr, start, end) {
4752 if (this.patterns.points.test(attr)) {
4753 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4754 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4756 val = superclass.doMethod.call(this, attr, start, end);
4761 proto.setRuntimeAttribute = function(attr) {
4762 if (this.patterns.points.test(attr)) {
4763 var el = this.getEl();
4764 var attributes = this.attributes;
4766 var control = attributes['points']['control'] || [];
4770 if (control.length > 0 && !(control[0] instanceof Array)) {
4771 control = [control];
4774 for (i = 0,len = control.length; i < len; ++i) {
4775 tmp[i] = control[i];
4780 Roo.fly(el).position();
4782 if (isset(attributes['points']['from'])) {
4783 Roo.lib.Dom.setXY(el, attributes['points']['from']);
4786 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4789 start = this.getAttribute('points');
4792 if (isset(attributes['points']['to'])) {
4793 end = translateValues.call(this, attributes['points']['to'], start);
4795 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4796 for (i = 0,len = control.length; i < len; ++i) {
4797 control[i] = translateValues.call(this, control[i], start);
4801 } else if (isset(attributes['points']['by'])) {
4802 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4804 for (i = 0,len = control.length; i < len; ++i) {
4805 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4809 this.runtimeAttributes[attr] = [start];
4811 if (control.length > 0) {
4812 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4815 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4818 superclass.setRuntimeAttribute.call(this, attr);
4822 var translateValues = function(val, start) {
4823 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4824 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4829 var isset = function(prop) {
4830 return (typeof prop !== 'undefined');
4834 * Portions of this file are based on pieces of Yahoo User Interface Library
4835 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4836 * YUI licensed under the BSD License:
4837 * http://developer.yahoo.net/yui/license.txt
4838 * <script type="text/javascript">
4842 Roo.lib.Scroll = function(el, attributes, duration, method) {
4844 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4848 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4852 var superclass = Y.Scroll.superclass;
4853 var proto = Y.Scroll.prototype;
4855 proto.toString = function() {
4856 var el = this.getEl();
4857 var id = el.id || el.tagName;
4858 return ("Scroll " + id);
4861 proto.doMethod = function(attr, start, end) {
4864 if (attr == 'scroll') {
4866 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4867 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4871 val = superclass.doMethod.call(this, attr, start, end);
4876 proto.getAttribute = function(attr) {
4878 var el = this.getEl();
4880 if (attr == 'scroll') {
4881 val = [ el.scrollLeft, el.scrollTop ];
4883 val = superclass.getAttribute.call(this, attr);
4889 proto.setAttribute = function(attr, val, unit) {
4890 var el = this.getEl();
4892 if (attr == 'scroll') {
4893 el.scrollLeft = val[0];
4894 el.scrollTop = val[1];
4896 superclass.setAttribute.call(this, attr, val, unit);
4901 * Originally based of this code... - refactored for Roo...
4902 * https://github.com/aaalsaleh/undo-manager
4905 * @author Abdulrahman Alsaleh
4906 * @copyright 2015 Abdulrahman Alsaleh
4907 * @license MIT License (c)
4909 * Hackily modifyed by alan@roojs.com
4914 * TOTALLY UNTESTED...
4916 * Documentation to be done....
4921 * @class Roo.lib.UndoManager
4922 * An undo manager implementation in JavaScript. It follows the W3C UndoManager and DOM Transaction
4923 * Draft and the undocumented and disabled Mozilla Firefox's UndoManager implementation.
4929 editor.undoManager = new Roo.lib.UndoManager(1000, editor);
4933 * For more information see this blog post with examples:
4934 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4935 - Create Elements using DOM, HTML fragments and Templates</a>.
4937 * @param {Number} limit how far back to go ... use 1000?
4938 * @param {Object} scope usually use document..
4941 Roo.lib.UndoManager = function (limit, undoScopeHost)
4945 this.scope = undoScopeHost;
4946 this.fireEvent = typeof CustomEvent != 'undefined' && undoScopeHost && undoScopeHost.dispatchEvent;
4947 if (this.fireEvent) {
4954 Roo.lib.UndoManager.prototype = {
4965 * To push and execute a transaction, the method undoManager.transact
4966 * must be called by passing a transaction object as the first argument, and a merge
4967 * flag as the second argument. A transaction object has the following properties:
4971 undoManager.transact({
4973 execute: function() { ... },
4974 undo: function() { ... },
4975 // redo same as execute
4976 redo: function() { this.execute(); }
4979 // merge transaction
4980 undoManager.transact({
4982 execute: function() { ... }, // this will be run...
4983 undo: function() { ... }, // what to do when undo is run.
4984 // redo same as execute
4985 redo: function() { this.execute(); }
4990 * @param {Object} transaction The transaction to add to the stack.
4991 * @return {String} The HTML fragment
4995 transact : function (transaction, merge)
4997 if (arguments.length < 2) {
4998 throw new TypeError('Not enough arguments to UndoManager.transact.');
5001 transaction.execute();
5003 this.stack.splice(0, this.position);
5004 if (merge && this.length) {
5005 this.stack[0].push(transaction);
5007 this.stack.unshift([transaction]);
5012 if (this.limit && this.stack.length > this.limit) {
5013 this.length = this.stack.length = this.limit;
5015 this.length = this.stack.length;
5018 if (this.fireEvent) {
5019 this.scope.dispatchEvent(
5020 new CustomEvent('DOMTransaction', {
5022 transactions: this.stack[0].slice()
5030 Roo.log("transaction: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
5037 Roo.log("undo: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
5039 if (this.position < this.length) {
5040 for (var i = this.stack[this.position].length - 1; i >= 0; i--) {
5041 this.stack[this.position][i].undo();
5045 if (this.fireEvent) {
5046 this.scope.dispatchEvent(
5047 new CustomEvent('undo', {
5049 transactions: this.stack[this.position - 1].slice()
5061 if (this.position > 0) {
5062 for (var i = 0, n = this.stack[this.position - 1].length; i < n; i++) {
5063 this.stack[this.position - 1][i].redo();
5067 if (this.fireEvent) {
5068 this.scope.dispatchEvent(
5069 new CustomEvent('redo', {
5071 transactions: this.stack[this.position].slice()
5081 item : function (index)
5083 if (index >= 0 && index < this.length) {
5084 return this.stack[index].slice();
5089 clearUndo : function () {
5090 this.stack.length = this.length = this.position;
5093 clearRedo : function () {
5094 this.stack.splice(0, this.position);
5096 this.length = this.stack.length;
5099 * Reset the undo - probaly done on load to clear all history.
5106 this.current_html = this.scope.innerHTML;
5107 if (this.timer !== false) {
5108 clearTimeout(this.timer);
5120 // this will handle the undo/redo on the element.?
5121 bindEvents : function()
5123 var el = this.scope;
5124 el.undoManager = this;
5127 this.scope.addEventListener('keydown', function(e) {
5128 if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
5130 el.undoManager.redo(); // Ctrl/Command + Shift + Z
5132 el.undoManager.undo(); // Ctrl/Command + Z
5139 this.scope.addEventListener('keyup', function(e) {
5140 if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
5149 el.addEventListener('input', function(e) {
5150 if(el.innerHTML == t.current_html) {
5153 // only record events every second.
5154 if (t.timer !== false) {
5155 clearTimeout(t.timer);
5158 t.timer = setTimeout(function() { t.merge = false; }, 1000);
5160 t.addEvent(t.merge);
5161 t.merge = true; // ignore changes happening every second..
5165 * Manually add an event.
5166 * Normall called without arguements - and it will just get added to the stack.
5170 addEvent : function(merge)
5172 Roo.log("undomanager +" + (merge ? 'Y':'n'));
5173 // not sure if this should clear the timer
5174 merge = typeof(merge) == 'undefined' ? false : merge;
5176 this.scope.undoManager.transact({
5178 oldHTML: this.current_html,
5179 newHTML: this.scope.innerHTML,
5180 // nothing to execute (content already changed when input is fired)
5181 execute: function() { },
5183 this.scope.innerHTML = this.current_html = this.oldHTML;
5186 this.scope.innerHTML = this.current_html = this.newHTML;
5188 }, false); //merge);
5192 this.current_html = this.scope.innerHTML;
5203 * Ext JS Library 1.1.1
5204 * Copyright(c) 2006-2007, Ext JS, LLC.
5206 * Originally Released Under LGPL - original licence link has changed is not relivant.
5209 * <script type="text/javascript">
5213 // nasty IE9 hack - what a pile of crap that is..
5215 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
5216 Range.prototype.createContextualFragment = function (html) {
5217 var doc = window.document;
5218 var container = doc.createElement("div");
5219 container.innerHTML = html;
5220 var frag = doc.createDocumentFragment(), n;
5221 while ((n = container.firstChild)) {
5222 frag.appendChild(n);
5229 * @class Roo.DomHelper
5230 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
5231 * 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>.
5234 Roo.DomHelper = function(){
5235 var tempTableEl = null;
5236 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
5237 var tableRe = /^table|tbody|tr|td$/i;
5239 // build as innerHTML where available
5241 var createHtml = function(o){
5242 if(typeof o == 'string'){
5251 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
5252 if(attr == "style"){
5254 if(typeof s == "function"){
5257 if(typeof s == "string"){
5258 b += ' style="' + s + '"';
5259 }else if(typeof s == "object"){
5262 if(typeof s[key] != "function"){
5263 b += key + ":" + s[key] + ";";
5270 b += ' class="' + o["cls"] + '"';
5271 }else if(attr == "htmlFor"){
5272 b += ' for="' + o["htmlFor"] + '"';
5274 b += " " + attr + '="' + o[attr] + '"';
5278 if(emptyTags.test(o.tag)){
5282 var cn = o.children || o.cn;
5284 //http://bugs.kde.org/show_bug.cgi?id=71506
5285 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5286 for(var i = 0, len = cn.length; i < len; i++) {
5287 b += createHtml(cn[i], b);
5290 b += createHtml(cn, b);
5296 b += "</" + o.tag + ">";
5303 var createDom = function(o, parentNode){
5305 // defininition craeted..
5307 if (o.ns && o.ns != 'html') {
5309 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
5310 xmlns[o.ns] = o.xmlns;
5313 if (typeof(xmlns[o.ns]) == 'undefined') {
5314 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
5320 if (typeof(o) == 'string') {
5321 return parentNode.appendChild(document.createTextNode(o));
5323 o.tag = o.tag || div;
5324 if (o.ns && Roo.isIE) {
5326 o.tag = o.ns + ':' + o.tag;
5329 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
5330 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
5333 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
5334 attr == "style" || typeof o[attr] == "function") { continue; }
5336 if(attr=="cls" && Roo.isIE){
5337 el.className = o["cls"];
5339 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
5345 Roo.DomHelper.applyStyles(el, o.style);
5346 var cn = o.children || o.cn;
5348 //http://bugs.kde.org/show_bug.cgi?id=71506
5349 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5350 for(var i = 0, len = cn.length; i < len; i++) {
5351 createDom(cn[i], el);
5358 el.innerHTML = o.html;
5361 parentNode.appendChild(el);
5366 var ieTable = function(depth, s, h, e){
5367 tempTableEl.innerHTML = [s, h, e].join('');
5368 var i = -1, el = tempTableEl;
5369 while(++i < depth && el.firstChild){
5375 // kill repeat to save bytes
5379 tbe = '</tbody>'+te,
5385 * Nasty code for IE's broken table implementation
5387 var insertIntoTable = function(tag, where, el, html){
5389 tempTableEl = document.createElement('div');
5394 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
5397 if(where == 'beforebegin'){
5401 before = el.nextSibling;
5404 node = ieTable(4, trs, html, tre);
5406 else if(tag == 'tr'){
5407 if(where == 'beforebegin'){
5410 node = ieTable(3, tbs, html, tbe);
5411 } else if(where == 'afterend'){
5412 before = el.nextSibling;
5414 node = ieTable(3, tbs, html, tbe);
5415 } else{ // INTO a TR
5416 if(where == 'afterbegin'){
5417 before = el.firstChild;
5419 node = ieTable(4, trs, html, tre);
5421 } else if(tag == 'tbody'){
5422 if(where == 'beforebegin'){
5425 node = ieTable(2, ts, html, te);
5426 } else if(where == 'afterend'){
5427 before = el.nextSibling;
5429 node = ieTable(2, ts, html, te);
5431 if(where == 'afterbegin'){
5432 before = el.firstChild;
5434 node = ieTable(3, tbs, html, tbe);
5437 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
5440 if(where == 'afterbegin'){
5441 before = el.firstChild;
5443 node = ieTable(2, ts, html, te);
5445 el.insertBefore(node, before);
5449 // this is a bit like the react update code...
5452 var updateNode = function(from, to)
5454 // should we handle non-standard elements?
5455 Roo.log(["UpdateNode" , from, to]);
5456 if (from.nodeType != to.nodeType) {
5457 Roo.log(["ReplaceChild - mismatch notType" , to, from ]);
5458 from.parentNode.replaceChild(to, from);
5461 if (from.nodeType == 3) {
5462 // assume it's text?!
5463 if (from.data == to.data) {
5466 from.data = to.data;
5470 // assume 'to' doesnt have '1/3 nodetypes!
5471 if (from.nodeType !=1 || from.tagName != to.tagName) {
5472 Roo.log(["ReplaceChild" , from, to ]);
5473 from.parentNode.replaceChild(to, from);
5476 // compare attributes
5477 var ar = Array.from(from.attributes);
5478 for(var i = 0; i< ar.length;i++) {
5479 if (to.hasAttribute(ar[i].name)) {
5482 if (ar[i].name == 'id') { // always keep ids?
5485 if (ar[i].name == 'style') {
5486 throw "style removed?";
5488 Roo.log("removeAttribute" + ar[i].name);
5489 from.removeAttribute(ar[i].name);
5492 for(var i = 0; i< ar.length;i++) {
5493 if (from.getAttribute(ar[i].name) == to.getAttribute(ar[i].name)) {
5496 Roo.log("updateAttribute " + from.getAttribute(ar[i].name) + '=>' + to.getAttribute(ar[i].name));
5497 from.setAttribute(ar[i].name, to.getAttribute(ar[i].name));
5500 var far = Array.from(from.childNodes);
5501 var tar = Array.from(to.childNodes);
5502 // if the lengths are different.. then it's probably a editable content change, rather than
5503 // a change of the block definition..
5505 // this did notwork , as our rebuilt nodes did not include ID's so did not match at all.
5506 /*if (from.innerHTML == to.innerHTML) {
5509 if (far.length != tar.length) {
5510 from.innerHTML = to.innerHTML;
5515 for(var i = 0; i < Math.max(tar.length, far.length); i++) {
5516 if (i >= far.length) {
5517 from.appendChild(tar[i]);
5518 Roo.log(["add", tar[i]]);
5520 } else if ( i >= tar.length) {
5521 from.removeChild(far[i]);
5522 Roo.log(["remove", far[i]]);
5525 updateNode(far[i], tar[i]);
5537 /** True to force the use of DOM instead of html fragments @type Boolean */
5541 * Returns the markup for the passed Element(s) config
5542 * @param {Object} o The Dom object spec (and children)
5545 markup : function(o){
5546 return createHtml(o);
5550 * Applies a style specification to an element
5551 * @param {String/HTMLElement} el The element to apply styles to
5552 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
5553 * a function which returns such a specification.
5555 applyStyles : function(el, styles){
5558 if(typeof styles == "string"){
5559 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
5561 while ((matches = re.exec(styles)) != null){
5562 el.setStyle(matches[1], matches[2]);
5564 }else if (typeof styles == "object"){
5565 for (var style in styles){
5566 el.setStyle(style, styles[style]);
5568 }else if (typeof styles == "function"){
5569 Roo.DomHelper.applyStyles(el, styles.call());
5575 * Inserts an HTML fragment into the Dom
5576 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
5577 * @param {HTMLElement} el The context element
5578 * @param {String} html The HTML fragmenet
5579 * @return {HTMLElement} The new node
5581 insertHtml : function(where, el, html){
5582 where = where.toLowerCase();
5583 if(el.insertAdjacentHTML){
5584 if(tableRe.test(el.tagName)){
5586 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
5592 el.insertAdjacentHTML('BeforeBegin', html);
5593 return el.previousSibling;
5595 el.insertAdjacentHTML('AfterBegin', html);
5596 return el.firstChild;
5598 el.insertAdjacentHTML('BeforeEnd', html);
5599 return el.lastChild;
5601 el.insertAdjacentHTML('AfterEnd', html);
5602 return el.nextSibling;
5604 throw 'Illegal insertion point -> "' + where + '"';
5606 var range = el.ownerDocument.createRange();
5610 range.setStartBefore(el);
5611 frag = range.createContextualFragment(html);
5612 el.parentNode.insertBefore(frag, el);
5613 return el.previousSibling;
5616 range.setStartBefore(el.firstChild);
5617 frag = range.createContextualFragment(html);
5618 el.insertBefore(frag, el.firstChild);
5619 return el.firstChild;
5621 el.innerHTML = html;
5622 return el.firstChild;
5626 range.setStartAfter(el.lastChild);
5627 frag = range.createContextualFragment(html);
5628 el.appendChild(frag);
5629 return el.lastChild;
5631 el.innerHTML = html;
5632 return el.lastChild;
5635 range.setStartAfter(el);
5636 frag = range.createContextualFragment(html);
5637 el.parentNode.insertBefore(frag, el.nextSibling);
5638 return el.nextSibling;
5640 throw 'Illegal insertion point -> "' + where + '"';
5644 * Creates new Dom element(s) and inserts them before el
5645 * @param {String/HTMLElement/Element} el The context element
5646 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5647 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5648 * @return {HTMLElement/Roo.Element} The new node
5650 insertBefore : function(el, o, returnElement){
5651 return this.doInsert(el, o, returnElement, "beforeBegin");
5655 * Creates new Dom element(s) and inserts them after el
5656 * @param {String/HTMLElement/Element} el The context element
5657 * @param {Object} o The Dom object spec (and children)
5658 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5659 * @return {HTMLElement/Roo.Element} The new node
5661 insertAfter : function(el, o, returnElement){
5662 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
5666 * Creates new Dom element(s) and inserts them as the first child of el
5667 * @param {String/HTMLElement/Element} el The context element
5668 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5669 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5670 * @return {HTMLElement/Roo.Element} The new node
5672 insertFirst : function(el, o, returnElement){
5673 return this.doInsert(el, o, returnElement, "afterBegin");
5677 doInsert : function(el, o, returnElement, pos, sibling){
5678 el = Roo.getDom(el);
5680 if(this.useDom || o.ns){
5681 newNode = createDom(o, null);
5682 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
5684 var html = createHtml(o);
5685 newNode = this.insertHtml(pos, el, html);
5687 return returnElement ? Roo.get(newNode, true) : newNode;
5691 * Creates new Dom element(s) and appends them to el
5692 * @param {String/HTMLElement/Element} el The context element
5693 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5694 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5695 * @return {HTMLElement/Roo.Element} The new node
5697 append : function(el, o, returnElement){
5698 el = Roo.getDom(el);
5700 if(this.useDom || o.ns){
5701 newNode = createDom(o, null);
5702 el.appendChild(newNode);
5704 var html = createHtml(o);
5705 newNode = this.insertHtml("beforeEnd", el, html);
5707 return returnElement ? Roo.get(newNode, true) : newNode;
5711 * Creates new Dom element(s) and overwrites the contents of el with them
5712 * @param {String/HTMLElement/Element} el The context element
5713 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5714 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5715 * @return {HTMLElement/Roo.Element} The new node
5717 overwrite : function(el, o, returnElement)
5719 el = Roo.getDom(el);
5722 while (el.childNodes.length) {
5723 el.removeChild(el.firstChild);
5727 el.innerHTML = createHtml(o);
5730 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5734 * Creates a new Roo.DomHelper.Template from the Dom object spec
5735 * @param {Object} o The Dom object spec (and children)
5736 * @return {Roo.DomHelper.Template} The new template
5738 createTemplate : function(o){
5739 var html = createHtml(o);
5740 return new Roo.Template(html);
5743 * Updates the first element with the spec from the o (replacing if necessary)
5744 * This iterates through the children, and updates attributes / children etc..
5745 * @param {String/HTMLElement/Element} el The context element
5746 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5749 update : function(el, o)
5751 updateNode(Roo.getDom(el), createDom(o));
5760 * Ext JS Library 1.1.1
5761 * Copyright(c) 2006-2007, Ext JS, LLC.
5763 * Originally Released Under LGPL - original licence link has changed is not relivant.
5766 * <script type="text/javascript">
5770 * @class Roo.Template
5771 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
5772 * For a list of available format functions, see {@link Roo.util.Format}.<br />
5775 var t = new Roo.Template({
5776 html : '<div name="{id}">' +
5777 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
5779 myformat: function (value, allValues) {
5780 return 'XX' + value;
5783 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
5785 * For more information see this blog post with examples:
5786 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
5787 - Create Elements using DOM, HTML fragments and Templates</a>.
5789 * @param {Object} cfg - Configuration object.
5791 Roo.Template = function(cfg){
5793 if(cfg instanceof Array){
5795 }else if(arguments.length > 1){
5796 cfg = Array.prototype.join.call(arguments, "");
5800 if (typeof(cfg) == 'object') {
5811 Roo.Template.prototype = {
5814 * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
5820 * @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..
5821 * it should be fixed so that template is observable...
5825 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
5833 * Returns an HTML fragment of this template with the specified values applied.
5834 * @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'})
5835 * @return {String} The HTML fragment
5840 applyTemplate : function(values){
5841 //Roo.log(["applyTemplate", values]);
5845 return this.compiled(values);
5847 var useF = this.disableFormats !== true;
5848 var fm = Roo.util.Format, tpl = this;
5849 var fn = function(m, name, format, args){
5851 if(format.substr(0, 5) == "this."){
5852 return tpl.call(format.substr(5), values[name], values);
5855 // quoted values are required for strings in compiled templates,
5856 // but for non compiled we need to strip them
5857 // quoted reversed for jsmin
5858 var re = /^\s*['"](.*)["']\s*$/;
5859 args = args.split(',');
5860 for(var i = 0, len = args.length; i < len; i++){
5861 args[i] = args[i].replace(re, "$1");
5863 args = [values[name]].concat(args);
5865 args = [values[name]];
5867 return fm[format].apply(fm, args);
5870 return values[name] !== undefined ? values[name] : "";
5873 return this.html.replace(this.re, fn);
5891 this.loading = true;
5892 this.compiled = false;
5894 var cx = new Roo.data.Connection();
5898 success : function (response) {
5902 _t.set(response.responseText,true);
5908 failure : function(response) {
5909 Roo.log("Template failed to load from " + _t.url);
5916 * Sets the HTML used as the template and optionally compiles it.
5917 * @param {String} html
5918 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
5919 * @return {Roo.Template} this
5921 set : function(html, compile){
5923 this.compiled = false;
5931 * True to disable format functions (defaults to false)
5934 disableFormats : false,
5937 * The regular expression used to match template variables
5941 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
5944 * Compiles the template into an internal function, eliminating the RegEx overhead.
5945 * @return {Roo.Template} this
5947 compile : function(){
5948 var fm = Roo.util.Format;
5949 var useF = this.disableFormats !== true;
5950 var sep = Roo.isGecko ? "+" : ",";
5951 var fn = function(m, name, format, args){
5953 args = args ? ',' + args : "";
5954 if(format.substr(0, 5) != "this."){
5955 format = "fm." + format + '(';
5957 format = 'this.call("'+ format.substr(5) + '", ';
5961 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
5963 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
5966 // branched to use + in gecko and [].join() in others
5968 body = "this.compiled = function(values){ return '" +
5969 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
5972 body = ["this.compiled = function(values){ return ['"];
5973 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
5974 body.push("'].join('');};");
5975 body = body.join('');
5985 // private function used to call members
5986 call : function(fnName, value, allValues){
5987 return this[fnName](value, allValues);
5991 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
5992 * @param {String/HTMLElement/Roo.Element} el The context element
5993 * @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'})
5994 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5995 * @return {HTMLElement/Roo.Element} The new node or Element
5997 insertFirst: function(el, values, returnElement){
5998 return this.doInsert('afterBegin', el, values, returnElement);
6002 * Applies the supplied values to the template and inserts the new node(s) before el.
6003 * @param {String/HTMLElement/Roo.Element} el The context element
6004 * @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'})
6005 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6006 * @return {HTMLElement/Roo.Element} The new node or Element
6008 insertBefore: function(el, values, returnElement){
6009 return this.doInsert('beforeBegin', el, values, returnElement);
6013 * Applies the supplied values to the template and inserts the new node(s) after el.
6014 * @param {String/HTMLElement/Roo.Element} el The context element
6015 * @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'})
6016 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6017 * @return {HTMLElement/Roo.Element} The new node or Element
6019 insertAfter : function(el, values, returnElement){
6020 return this.doInsert('afterEnd', el, values, returnElement);
6024 * Applies the supplied values to the template and appends the new node(s) to el.
6025 * @param {String/HTMLElement/Roo.Element} el The context element
6026 * @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'})
6027 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6028 * @return {HTMLElement/Roo.Element} The new node or Element
6030 append : function(el, values, returnElement){
6031 return this.doInsert('beforeEnd', el, values, returnElement);
6034 doInsert : function(where, el, values, returnEl){
6035 el = Roo.getDom(el);
6036 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
6037 return returnEl ? Roo.get(newNode, true) : newNode;
6041 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
6042 * @param {String/HTMLElement/Roo.Element} el The context element
6043 * @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'})
6044 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6045 * @return {HTMLElement/Roo.Element} The new node or Element
6047 overwrite : function(el, values, returnElement){
6048 el = Roo.getDom(el);
6049 el.innerHTML = this.applyTemplate(values);
6050 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
6054 * Alias for {@link #applyTemplate}
6057 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
6060 Roo.DomHelper.Template = Roo.Template;
6063 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
6064 * @param {String/HTMLElement} el A DOM element or its id
6065 * @returns {Roo.Template} The created template
6068 Roo.Template.from = function(el){
6069 el = Roo.getDom(el);
6070 return new Roo.Template(el.value || el.innerHTML);
6073 * Ext JS Library 1.1.1
6074 * Copyright(c) 2006-2007, Ext JS, LLC.
6076 * Originally Released Under LGPL - original licence link has changed is not relivant.
6079 * <script type="text/javascript">
6084 * This is code is also distributed under MIT license for use
6085 * with jQuery and prototype JavaScript libraries.
6088 * @class Roo.DomQuery
6089 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).
6091 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>
6094 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.
6096 <h4>Element Selectors:</h4>
6098 <li> <b>*</b> any element</li>
6099 <li> <b>E</b> an element with the tag E</li>
6100 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
6101 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
6102 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
6103 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
6105 <h4>Attribute Selectors:</h4>
6106 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
6108 <li> <b>E[foo]</b> has an attribute "foo"</li>
6109 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
6110 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
6111 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
6112 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
6113 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
6114 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
6116 <h4>Pseudo Classes:</h4>
6118 <li> <b>E:first-child</b> E is the first child of its parent</li>
6119 <li> <b>E:last-child</b> E is the last child of its parent</li>
6120 <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>
6121 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
6122 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
6123 <li> <b>E:only-child</b> E is the only child of its parent</li>
6124 <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>
6125 <li> <b>E:first</b> the first E in the resultset</li>
6126 <li> <b>E:last</b> the last E in the resultset</li>
6127 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
6128 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
6129 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
6130 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
6131 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
6132 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
6133 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
6134 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
6135 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
6137 <h4>CSS Value Selectors:</h4>
6139 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
6140 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
6141 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
6142 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
6143 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
6144 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
6148 Roo.DomQuery = function(){
6149 var cache = {}, simpleCache = {}, valueCache = {};
6150 var nonSpace = /\S/;
6151 var trimRe = /^\s+|\s+$/g;
6152 var tplRe = /\{(\d+)\}/g;
6153 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
6154 var tagTokenRe = /^(#)?([\w-\*]+)/;
6155 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
6157 function child(p, index){
6159 var n = p.firstChild;
6161 if(n.nodeType == 1){
6172 while((n = n.nextSibling) && n.nodeType != 1);
6177 while((n = n.previousSibling) && n.nodeType != 1);
6181 function children(d){
6182 var n = d.firstChild, ni = -1;
6184 var nx = n.nextSibling;
6185 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
6195 function byClassName(c, a, v){
6199 var r = [], ri = -1, cn;
6200 for(var i = 0, ci; ci = c[i]; i++){
6204 ( (ci instanceof SVGElement) ? ci.className.baseVal : ci.className)
6205 +' ').indexOf(v) != -1){
6212 function attrValue(n, attr){
6213 if(!n.tagName && typeof n.length != "undefined"){
6222 if(attr == "class" || attr == "className"){
6223 return (n instanceof SVGElement) ? n.className.baseVal : n.className;
6225 return n.getAttribute(attr) || n[attr];
6229 function getNodes(ns, mode, tagName){
6230 var result = [], ri = -1, cs;
6234 tagName = tagName || "*";
6235 if(typeof ns.getElementsByTagName != "undefined"){
6239 for(var i = 0, ni; ni = ns[i]; i++){
6240 cs = ni.getElementsByTagName(tagName);
6241 for(var j = 0, ci; ci = cs[j]; j++){
6245 }else if(mode == "/" || mode == ">"){
6246 var utag = tagName.toUpperCase();
6247 for(var i = 0, ni, cn; ni = ns[i]; i++){
6248 cn = ni.children || ni.childNodes;
6249 for(var j = 0, cj; cj = cn[j]; j++){
6250 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
6255 }else if(mode == "+"){
6256 var utag = tagName.toUpperCase();
6257 for(var i = 0, n; n = ns[i]; i++){
6258 while((n = n.nextSibling) && n.nodeType != 1);
6259 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
6263 }else if(mode == "~"){
6264 for(var i = 0, n; n = ns[i]; i++){
6265 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
6274 function concat(a, b){
6278 for(var i = 0, l = b.length; i < l; i++){
6284 function byTag(cs, tagName){
6285 if(cs.tagName || cs == document){
6291 var r = [], ri = -1;
6292 tagName = tagName.toLowerCase();
6293 for(var i = 0, ci; ci = cs[i]; i++){
6294 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
6301 function byId(cs, attr, id){
6302 if(cs.tagName || cs == document){
6308 var r = [], ri = -1;
6309 for(var i = 0,ci; ci = cs[i]; i++){
6310 if(ci && ci.id == id){
6318 function byAttribute(cs, attr, value, op, custom){
6319 var r = [], ri = -1, st = custom=="{";
6320 var f = Roo.DomQuery.operators[op];
6321 for(var i = 0, ci; ci = cs[i]; i++){
6324 a = Roo.DomQuery.getStyle(ci, attr);
6326 else if(attr == "class" || attr == "className"){
6327 a = (ci instanceof SVGElement) ? ci.className.baseVal : ci.className;
6328 }else if(attr == "for"){
6330 }else if(attr == "href"){
6331 a = ci.getAttribute("href", 2);
6333 a = ci.getAttribute(attr);
6335 if((f && f(a, value)) || (!f && a)){
6342 function byPseudo(cs, name, value){
6343 return Roo.DomQuery.pseudos[name](cs, value);
6346 // This is for IE MSXML which does not support expandos.
6347 // IE runs the same speed using setAttribute, however FF slows way down
6348 // and Safari completely fails so they need to continue to use expandos.
6349 var isIE = window.ActiveXObject ? true : false;
6351 // this eval is stop the compressor from
6352 // renaming the variable to something shorter
6354 /** eval:var:batch */
6359 function nodupIEXml(cs){
6361 cs[0].setAttribute("_nodup", d);
6363 for(var i = 1, len = cs.length; i < len; i++){
6365 if(!c.getAttribute("_nodup") != d){
6366 c.setAttribute("_nodup", d);
6370 for(var i = 0, len = cs.length; i < len; i++){
6371 cs[i].removeAttribute("_nodup");
6380 var len = cs.length, c, i, r = cs, cj, ri = -1;
6381 if(!len || typeof cs.nodeType != "undefined" || len == 1){
6384 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
6385 return nodupIEXml(cs);
6389 for(i = 1; c = cs[i]; i++){
6394 for(var j = 0; j < i; j++){
6397 for(j = i+1; cj = cs[j]; j++){
6409 function quickDiffIEXml(c1, c2){
6411 for(var i = 0, len = c1.length; i < len; i++){
6412 c1[i].setAttribute("_qdiff", d);
6415 for(var i = 0, len = c2.length; i < len; i++){
6416 if(c2[i].getAttribute("_qdiff") != d){
6417 r[r.length] = c2[i];
6420 for(var i = 0, len = c1.length; i < len; i++){
6421 c1[i].removeAttribute("_qdiff");
6426 function quickDiff(c1, c2){
6427 var len1 = c1.length;
6431 if(isIE && c1[0].selectSingleNode){
6432 return quickDiffIEXml(c1, c2);
6435 for(var i = 0; i < len1; i++){
6439 for(var i = 0, len = c2.length; i < len; i++){
6440 if(c2[i]._qdiff != d){
6441 r[r.length] = c2[i];
6447 function quickId(ns, mode, root, id){
6449 var d = root.ownerDocument || root;
6450 return d.getElementById(id);
6452 ns = getNodes(ns, mode, "*");
6453 return byId(ns, null, id);
6457 getStyle : function(el, name){
6458 return Roo.fly(el).getStyle(name);
6461 * Compiles a selector/xpath query into a reusable function. The returned function
6462 * takes one parameter "root" (optional), which is the context node from where the query should start.
6463 * @param {String} selector The selector/xpath query
6464 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
6465 * @return {Function}
6467 compile : function(path, type){
6468 type = type || "select";
6470 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
6471 var q = path, mode, lq;
6472 var tk = Roo.DomQuery.matchers;
6473 var tklen = tk.length;
6476 // accept leading mode switch
6477 var lmode = q.match(modeRe);
6478 if(lmode && lmode[1]){
6479 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
6480 q = q.replace(lmode[1], "");
6482 // strip leading slashes
6483 while(path.substr(0, 1)=="/"){
6484 path = path.substr(1);
6487 while(q && lq != q){
6489 var tm = q.match(tagTokenRe);
6490 if(type == "select"){
6493 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
6495 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
6497 q = q.replace(tm[0], "");
6498 }else if(q.substr(0, 1) != '@'){
6499 fn[fn.length] = 'n = getNodes(n, mode, "*");';
6504 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
6506 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
6508 q = q.replace(tm[0], "");
6511 while(!(mm = q.match(modeRe))){
6512 var matched = false;
6513 for(var j = 0; j < tklen; j++){
6515 var m = q.match(t.re);
6517 fn[fn.length] = t.select.replace(tplRe, function(x, i){
6520 q = q.replace(m[0], "");
6525 // prevent infinite loop on bad selector
6527 throw 'Error parsing selector, parsing failed at "' + q + '"';
6531 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
6532 q = q.replace(mm[1], "");
6535 fn[fn.length] = "return nodup(n);\n}";
6538 * list of variables that need from compression as they are used by eval.
6548 * eval:var:byClassName
6550 * eval:var:byAttribute
6551 * eval:var:attrValue
6559 * Selects a group of elements.
6560 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
6561 * @param {Node} root (optional) The start of the query (defaults to document).
6564 select : function(path, root, type){
6565 if(!root || root == document){
6568 if(typeof root == "string"){
6569 root = document.getElementById(root);
6571 var paths = path.split(",");
6573 for(var i = 0, len = paths.length; i < len; i++){
6574 var p = paths[i].replace(trimRe, "");
6576 cache[p] = Roo.DomQuery.compile(p);
6578 throw p + " is not a valid selector";
6581 var result = cache[p](root);
6582 if(result && result != document){
6583 results = results.concat(result);
6586 if(paths.length > 1){
6587 return nodup(results);
6593 * Selects a single element.
6594 * @param {String} selector The selector/xpath query
6595 * @param {Node} root (optional) The start of the query (defaults to document).
6598 selectNode : function(path, root){
6599 return Roo.DomQuery.select(path, root)[0];
6603 * Selects the value of a node, optionally replacing null with the defaultValue.
6604 * @param {String} selector The selector/xpath query
6605 * @param {Node} root (optional) The start of the query (defaults to document).
6606 * @param {String} defaultValue
6608 selectValue : function(path, root, defaultValue){
6609 path = path.replace(trimRe, "");
6610 if(!valueCache[path]){
6611 valueCache[path] = Roo.DomQuery.compile(path, "select");
6613 var n = valueCache[path](root);
6614 n = n[0] ? n[0] : n;
6615 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
6616 return ((v === null||v === undefined||v==='') ? defaultValue : v);
6620 * Selects the value of a node, parsing integers and floats.
6621 * @param {String} selector The selector/xpath query
6622 * @param {Node} root (optional) The start of the query (defaults to document).
6623 * @param {Number} defaultValue
6626 selectNumber : function(path, root, defaultValue){
6627 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
6628 return parseFloat(v);
6632 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
6633 * @param {String/HTMLElement/Array} el An element id, element or array of elements
6634 * @param {String} selector The simple selector to test
6637 is : function(el, ss){
6638 if(typeof el == "string"){
6639 el = document.getElementById(el);
6641 var isArray = (el instanceof Array);
6642 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
6643 return isArray ? (result.length == el.length) : (result.length > 0);
6647 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
6648 * @param {Array} el An array of elements to filter
6649 * @param {String} selector The simple selector to test
6650 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
6651 * the selector instead of the ones that match
6654 filter : function(els, ss, nonMatches){
6655 ss = ss.replace(trimRe, "");
6656 if(!simpleCache[ss]){
6657 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
6659 var result = simpleCache[ss](els);
6660 return nonMatches ? quickDiff(result, els) : result;
6664 * Collection of matching regular expressions and code snippets.
6668 select: 'n = byClassName(n, null, " {1} ");'
6670 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
6671 select: 'n = byPseudo(n, "{1}", "{2}");'
6673 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
6674 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
6677 select: 'n = byId(n, null, "{1}");'
6680 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
6685 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
6686 * 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, > <.
6689 "=" : function(a, v){
6692 "!=" : function(a, v){
6695 "^=" : function(a, v){
6696 return a && a.substr(0, v.length) == v;
6698 "$=" : function(a, v){
6699 return a && a.substr(a.length-v.length) == v;
6701 "*=" : function(a, v){
6702 return a && a.indexOf(v) !== -1;
6704 "%=" : function(a, v){
6705 return (a % v) == 0;
6707 "|=" : function(a, v){
6708 return a && (a == v || a.substr(0, v.length+1) == v+'-');
6710 "~=" : function(a, v){
6711 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
6716 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
6717 * and the argument (if any) supplied in the selector.
6720 "first-child" : function(c){
6721 var r = [], ri = -1, n;
6722 for(var i = 0, ci; ci = n = c[i]; i++){
6723 while((n = n.previousSibling) && n.nodeType != 1);
6731 "last-child" : function(c){
6732 var r = [], ri = -1, n;
6733 for(var i = 0, ci; ci = n = c[i]; i++){
6734 while((n = n.nextSibling) && n.nodeType != 1);
6742 "nth-child" : function(c, a) {
6743 var r = [], ri = -1;
6744 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
6745 var f = (m[1] || 1) - 0, l = m[2] - 0;
6746 for(var i = 0, n; n = c[i]; i++){
6747 var pn = n.parentNode;
6748 if (batch != pn._batch) {
6750 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
6751 if(cn.nodeType == 1){
6758 if (l == 0 || n.nodeIndex == l){
6761 } else if ((n.nodeIndex + l) % f == 0){
6769 "only-child" : function(c){
6770 var r = [], ri = -1;;
6771 for(var i = 0, ci; ci = c[i]; i++){
6772 if(!prev(ci) && !next(ci)){
6779 "empty" : function(c){
6780 var r = [], ri = -1;
6781 for(var i = 0, ci; ci = c[i]; i++){
6782 var cns = ci.childNodes, j = 0, cn, empty = true;
6785 if(cn.nodeType == 1 || cn.nodeType == 3){
6797 "contains" : function(c, v){
6798 var r = [], ri = -1;
6799 for(var i = 0, ci; ci = c[i]; i++){
6800 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
6807 "nodeValue" : function(c, v){
6808 var r = [], ri = -1;
6809 for(var i = 0, ci; ci = c[i]; i++){
6810 if(ci.firstChild && ci.firstChild.nodeValue == v){
6817 "checked" : function(c){
6818 var r = [], ri = -1;
6819 for(var i = 0, ci; ci = c[i]; i++){
6820 if(ci.checked == true){
6827 "not" : function(c, ss){
6828 return Roo.DomQuery.filter(c, ss, true);
6831 "odd" : function(c){
6832 return this["nth-child"](c, "odd");
6835 "even" : function(c){
6836 return this["nth-child"](c, "even");
6839 "nth" : function(c, a){
6840 return c[a-1] || [];
6843 "first" : function(c){
6847 "last" : function(c){
6848 return c[c.length-1] || [];
6851 "has" : function(c, ss){
6852 var s = Roo.DomQuery.select;
6853 var r = [], ri = -1;
6854 for(var i = 0, ci; ci = c[i]; i++){
6855 if(s(ss, ci).length > 0){
6862 "next" : function(c, ss){
6863 var is = Roo.DomQuery.is;
6864 var r = [], ri = -1;
6865 for(var i = 0, ci; ci = c[i]; i++){
6874 "prev" : function(c, ss){
6875 var is = Roo.DomQuery.is;
6876 var r = [], ri = -1;
6877 for(var i = 0, ci; ci = c[i]; i++){
6890 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
6891 * @param {String} path The selector/xpath query
6892 * @param {Node} root (optional) The start of the query (defaults to document).
6897 Roo.query = Roo.DomQuery.select;
6900 * Ext JS Library 1.1.1
6901 * Copyright(c) 2006-2007, Ext JS, LLC.
6903 * Originally Released Under LGPL - original licence link has changed is not relivant.
6906 * <script type="text/javascript">
6910 * @class Roo.util.Observable
6911 * Base class that provides a common interface for publishing events. Subclasses are expected to
6912 * to have a property "events" with all the events defined.<br>
6915 Employee = function(name){
6922 Roo.extend(Employee, Roo.util.Observable);
6924 * @param {Object} config properties to use (incuding events / listeners)
6927 Roo.util.Observable = function(cfg){
6930 this.addEvents(cfg.events || {});
6932 delete cfg.events; // make sure
6935 Roo.apply(this, cfg);
6938 this.on(this.listeners);
6939 delete this.listeners;
6942 Roo.util.Observable.prototype = {
6944 * @cfg {Object} listeners list of events and functions to call for this object,
6948 'click' : function(e) {
6958 * Fires the specified event with the passed parameters (minus the event name).
6959 * @param {String} eventName
6960 * @param {Object...} args Variable number of parameters are passed to handlers
6961 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
6963 fireEvent : function(){
6964 var ce = this.events[arguments[0].toLowerCase()];
6965 if(typeof ce == "object"){
6966 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
6973 filterOptRe : /^(?:scope|delay|buffer|single)$/,
6976 * Appends an event handler to this component
6977 * @param {String} eventName The type of event to listen for
6978 * @param {Function} handler The method the event invokes
6979 * @param {Object} scope (optional) The scope in which to execute the handler
6980 * function. The handler function's "this" context.
6981 * @param {Object} options (optional) An object containing handler configuration
6982 * properties. This may contain any of the following properties:<ul>
6983 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6984 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6985 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6986 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6987 * by the specified number of milliseconds. If the event fires again within that time, the original
6988 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6991 * <b>Combining Options</b><br>
6992 * Using the options argument, it is possible to combine different types of listeners:<br>
6994 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
6996 el.on('click', this.onClick, this, {
7003 * <b>Attaching multiple handlers in 1 call</b><br>
7004 * The method also allows for a single argument to be passed which is a config object containing properties
7005 * which specify multiple handlers.
7014 fn: this.onMouseOver,
7018 fn: this.onMouseOut,
7024 * Or a shorthand syntax which passes the same scope object to all handlers:
7027 'click': this.onClick,
7028 'mouseover': this.onMouseOver,
7029 'mouseout': this.onMouseOut,
7034 addListener : function(eventName, fn, scope, o){
7035 if(typeof eventName == "object"){
7038 if(this.filterOptRe.test(e)){
7041 if(typeof o[e] == "function"){
7043 this.addListener(e, o[e], o.scope, o);
7045 // individual options
7046 this.addListener(e, o[e].fn, o[e].scope, o[e]);
7051 o = (!o || typeof o == "boolean") ? {} : o;
7052 eventName = eventName.toLowerCase();
7053 var ce = this.events[eventName] || true;
7054 if(typeof ce == "boolean"){
7055 ce = new Roo.util.Event(this, eventName);
7056 this.events[eventName] = ce;
7058 ce.addListener(fn, scope, o);
7062 * Removes a listener
7063 * @param {String} eventName The type of event to listen for
7064 * @param {Function} handler The handler to remove
7065 * @param {Object} scope (optional) The scope (this object) for the handler
7067 removeListener : function(eventName, fn, scope){
7068 var ce = this.events[eventName.toLowerCase()];
7069 if(typeof ce == "object"){
7070 ce.removeListener(fn, scope);
7075 * Removes all listeners for this object
7077 purgeListeners : function(){
7078 for(var evt in this.events){
7079 if(typeof this.events[evt] == "object"){
7080 this.events[evt].clearListeners();
7085 relayEvents : function(o, events){
7086 var createHandler = function(ename){
7089 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
7092 for(var i = 0, len = events.length; i < len; i++){
7093 var ename = events[i];
7094 if(!this.events[ename]){
7095 this.events[ename] = true;
7097 o.on(ename, createHandler(ename), this);
7102 * Used to define events on this Observable
7103 * @param {Object} object The object with the events defined
7105 addEvents : function(o){
7109 Roo.applyIf(this.events, o);
7113 * Checks to see if this object has any listeners for a specified event
7114 * @param {String} eventName The name of the event to check for
7115 * @return {Boolean} True if the event is being listened for, else false
7117 hasListener : function(eventName){
7118 var e = this.events[eventName];
7119 return typeof e == "object" && e.listeners.length > 0;
7123 * Appends an event handler to this element (shorthand for addListener)
7124 * @param {String} eventName The type of event to listen for
7125 * @param {Function} handler The method the event invokes
7126 * @param {Object} scope (optional) The scope in which to execute the handler
7127 * function. The handler function's "this" context.
7128 * @param {Object} options (optional)
7131 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
7133 * Removes a listener (shorthand for removeListener)
7134 * @param {String} eventName The type of event to listen for
7135 * @param {Function} handler The handler to remove
7136 * @param {Object} scope (optional) The scope (this object) for the handler
7139 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
7142 * Starts capture on the specified Observable. All events will be passed
7143 * to the supplied function with the event name + standard signature of the event
7144 * <b>before</b> the event is fired. If the supplied function returns false,
7145 * the event will not fire.
7146 * @param {Observable} o The Observable to capture
7147 * @param {Function} fn The function to call
7148 * @param {Object} scope (optional) The scope (this object) for the fn
7151 Roo.util.Observable.capture = function(o, fn, scope){
7152 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
7156 * Removes <b>all</b> added captures from the Observable.
7157 * @param {Observable} o The Observable to release
7160 Roo.util.Observable.releaseCapture = function(o){
7161 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
7166 var createBuffered = function(h, o, scope){
7167 var task = new Roo.util.DelayedTask();
7169 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
7173 var createSingle = function(h, e, fn, scope){
7175 e.removeListener(fn, scope);
7176 return h.apply(scope, arguments);
7180 var createDelayed = function(h, o, scope){
7182 var args = Array.prototype.slice.call(arguments, 0);
7183 setTimeout(function(){
7184 h.apply(scope, args);
7189 Roo.util.Event = function(obj, name){
7192 this.listeners = [];
7195 Roo.util.Event.prototype = {
7196 addListener : function(fn, scope, options){
7197 var o = options || {};
7198 scope = scope || this.obj;
7199 if(!this.isListening(fn, scope)){
7200 var l = {fn: fn, scope: scope, options: o};
7203 h = createDelayed(h, o, scope);
7206 h = createSingle(h, this, fn, scope);
7209 h = createBuffered(h, o, scope);
7212 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
7213 this.listeners.push(l);
7215 this.listeners = this.listeners.slice(0);
7216 this.listeners.push(l);
7221 findListener : function(fn, scope){
7222 scope = scope || this.obj;
7223 var ls = this.listeners;
7224 for(var i = 0, len = ls.length; i < len; i++){
7226 if(l.fn == fn && l.scope == scope){
7233 isListening : function(fn, scope){
7234 return this.findListener(fn, scope) != -1;
7237 removeListener : function(fn, scope){
7239 if((index = this.findListener(fn, scope)) != -1){
7241 this.listeners.splice(index, 1);
7243 this.listeners = this.listeners.slice(0);
7244 this.listeners.splice(index, 1);
7251 clearListeners : function(){
7252 this.listeners = [];
7256 var ls = this.listeners, scope, len = ls.length;
7259 var args = Array.prototype.slice.call(arguments, 0);
7260 for(var i = 0; i < len; i++){
7262 if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
7263 this.firing = false;
7267 this.firing = false;
7274 * Copyright(c) 2007-2017, Roo J Solutions Ltd
7281 * @class Roo.Document
7282 * @extends Roo.util.Observable
7283 * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
7285 * @param {Object} config the methods and properties of the 'base' class for the application.
7287 * Generic Page handler - implement this to start your app..
7290 * MyProject = new Roo.Document({
7292 'load' : true // your events..
7295 'ready' : function() {
7296 // fired on Roo.onReady()
7301 Roo.Document = function(cfg) {
7306 Roo.util.Observable.call(this,cfg);
7310 Roo.onReady(function() {
7311 _this.fireEvent('ready');
7317 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
7319 * Ext JS Library 1.1.1
7320 * Copyright(c) 2006-2007, Ext JS, LLC.
7322 * Originally Released Under LGPL - original licence link has changed is not relivant.
7325 * <script type="text/javascript">
7329 * @class Roo.EventManager
7330 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
7331 * several useful events directly.
7332 * See {@link Roo.EventObject} for more details on normalized event objects.
7335 Roo.EventManager = function(){
7336 var docReadyEvent, docReadyProcId, docReadyState = false;
7337 var resizeEvent, resizeTask, textEvent, textSize;
7338 var E = Roo.lib.Event;
7339 var D = Roo.lib.Dom;
7344 var fireDocReady = function(){
7346 docReadyState = true;
7349 clearInterval(docReadyProcId);
7351 if(Roo.isGecko || Roo.isOpera) {
7352 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
7355 var defer = document.getElementById("ie-deferred-loader");
7357 defer.onreadystatechange = null;
7358 defer.parentNode.removeChild(defer);
7362 docReadyEvent.fire();
7363 docReadyEvent.clearListeners();
7368 var initDocReady = function(){
7369 docReadyEvent = new Roo.util.Event();
7370 if(Roo.isGecko || Roo.isOpera) {
7371 document.addEventListener("DOMContentLoaded", fireDocReady, false);
7373 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
7374 var defer = document.getElementById("ie-deferred-loader");
7375 defer.onreadystatechange = function(){
7376 if(this.readyState == "complete"){
7380 }else if(Roo.isSafari){
7381 docReadyProcId = setInterval(function(){
7382 var rs = document.readyState;
7383 if(rs == "complete") {
7388 // no matter what, make sure it fires on load
7389 E.on(window, "load", fireDocReady);
7392 var createBuffered = function(h, o){
7393 var task = new Roo.util.DelayedTask(h);
7395 // create new event object impl so new events don't wipe out properties
7396 e = new Roo.EventObjectImpl(e);
7397 task.delay(o.buffer, h, null, [e]);
7401 var createSingle = function(h, el, ename, fn){
7403 Roo.EventManager.removeListener(el, ename, fn);
7408 var createDelayed = function(h, o){
7410 // create new event object impl so new events don't wipe out properties
7411 e = new Roo.EventObjectImpl(e);
7412 setTimeout(function(){
7417 var transitionEndVal = false;
7419 var transitionEnd = function()
7421 if (transitionEndVal) {
7422 return transitionEndVal;
7424 var el = document.createElement('div');
7426 var transEndEventNames = {
7427 WebkitTransition : 'webkitTransitionEnd',
7428 MozTransition : 'transitionend',
7429 OTransition : 'oTransitionEnd otransitionend',
7430 transition : 'transitionend'
7433 for (var name in transEndEventNames) {
7434 if (el.style[name] !== undefined) {
7435 transitionEndVal = transEndEventNames[name];
7436 return transitionEndVal ;
7443 var listen = function(element, ename, opt, fn, scope)
7445 var o = (!opt || typeof opt == "boolean") ? {} : opt;
7446 fn = fn || o.fn; scope = scope || o.scope;
7447 var el = Roo.getDom(element);
7451 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
7454 if (ename == 'transitionend') {
7455 ename = transitionEnd();
7457 var h = function(e){
7458 e = Roo.EventObject.setEvent(e);
7461 t = e.getTarget(o.delegate, el);
7468 if(o.stopEvent === true){
7471 if(o.preventDefault === true){
7474 if(o.stopPropagation === true){
7475 e.stopPropagation();
7478 if(o.normalized === false){
7482 fn.call(scope || el, e, t, o);
7485 h = createDelayed(h, o);
7488 h = createSingle(h, el, ename, fn);
7491 h = createBuffered(h, o);
7494 fn._handlers = fn._handlers || [];
7497 fn._handlers.push([Roo.id(el), ename, h]);
7501 E.on(el, ename, h); // this adds the actuall listener to the object..
7504 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
7505 el.addEventListener("DOMMouseScroll", h, false);
7506 E.on(window, 'unload', function(){
7507 el.removeEventListener("DOMMouseScroll", h, false);
7510 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7511 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
7516 var stopListening = function(el, ename, fn){
7517 var id = Roo.id(el), hds = fn._handlers, hd = fn;
7519 for(var i = 0, len = hds.length; i < len; i++){
7521 if(h[0] == id && h[1] == ename){
7528 E.un(el, ename, hd);
7529 el = Roo.getDom(el);
7530 if(ename == "mousewheel" && el.addEventListener){
7531 el.removeEventListener("DOMMouseScroll", hd, false);
7533 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7534 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
7538 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
7545 * @scope Roo.EventManager
7550 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
7551 * object with a Roo.EventObject
7552 * @param {Function} fn The method the event invokes
7553 * @param {Object} scope An object that becomes the scope of the handler
7554 * @param {boolean} override If true, the obj passed in becomes
7555 * the execution scope of the listener
7556 * @return {Function} The wrapped function
7559 wrap : function(fn, scope, override){
7561 Roo.EventObject.setEvent(e);
7562 fn.call(override ? scope || window : window, Roo.EventObject, scope);
7567 * Appends an event handler to an element (shorthand for addListener)
7568 * @param {String/HTMLElement} element The html element or id to assign the
7569 * @param {String} eventName The type of event to listen for
7570 * @param {Function} handler The method the event invokes
7571 * @param {Object} scope (optional) The scope in which to execute the handler
7572 * function. The handler function's "this" context.
7573 * @param {Object} options (optional) An object containing handler configuration
7574 * properties. This may contain any of the following properties:<ul>
7575 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7576 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7577 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7578 * <li>preventDefault {Boolean} True to prevent the default action</li>
7579 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7580 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7581 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7582 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7583 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7584 * by the specified number of milliseconds. If the event fires again within that time, the original
7585 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7588 * <b>Combining Options</b><br>
7589 * Using the options argument, it is possible to combine different types of listeners:<br>
7591 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7593 el.on('click', this.onClick, this, {
7600 * <b>Attaching multiple handlers in 1 call</b><br>
7601 * The method also allows for a single argument to be passed which is a config object containing properties
7602 * which specify multiple handlers.
7612 fn: this.onMouseOver
7621 * Or a shorthand syntax:<br>
7624 'click' : this.onClick,
7625 'mouseover' : this.onMouseOver,
7626 'mouseout' : this.onMouseOut
7630 addListener : function(element, eventName, fn, scope, options){
7631 if(typeof eventName == "object"){
7637 if(typeof o[e] == "function"){
7639 listen(element, e, o, o[e], o.scope);
7641 // individual options
7642 listen(element, e, o[e]);
7647 return listen(element, eventName, options, fn, scope);
7651 * Removes an event handler
7653 * @param {String/HTMLElement} element The id or html element to remove the
7655 * @param {String} eventName The type of event
7656 * @param {Function} fn
7657 * @return {Boolean} True if a listener was actually removed
7659 removeListener : function(element, eventName, fn){
7660 return stopListening(element, eventName, fn);
7664 * Fires when the document is ready (before onload and before images are loaded). Can be
7665 * accessed shorthanded Roo.onReady().
7666 * @param {Function} fn The method the event invokes
7667 * @param {Object} scope An object that becomes the scope of the handler
7668 * @param {boolean} options
7670 onDocumentReady : function(fn, scope, options){
7671 if(docReadyState){ // if it already fired
7672 docReadyEvent.addListener(fn, scope, options);
7673 docReadyEvent.fire();
7674 docReadyEvent.clearListeners();
7680 docReadyEvent.addListener(fn, scope, options);
7684 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
7685 * @param {Function} fn The method the event invokes
7686 * @param {Object} scope An object that becomes the scope of the handler
7687 * @param {boolean} options
7689 onWindowResize : function(fn, scope, options)
7692 resizeEvent = new Roo.util.Event();
7693 resizeTask = new Roo.util.DelayedTask(function(){
7694 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7696 E.on(window, "resize", function()
7699 resizeTask.delay(50);
7701 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7705 resizeEvent.addListener(fn, scope, options);
7709 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
7710 * @param {Function} fn The method the event invokes
7711 * @param {Object} scope An object that becomes the scope of the handler
7712 * @param {boolean} options
7714 onTextResize : function(fn, scope, options){
7716 textEvent = new Roo.util.Event();
7717 var textEl = new Roo.Element(document.createElement('div'));
7718 textEl.dom.className = 'x-text-resize';
7719 textEl.dom.innerHTML = 'X';
7720 textEl.appendTo(document.body);
7721 textSize = textEl.dom.offsetHeight;
7722 setInterval(function(){
7723 if(textEl.dom.offsetHeight != textSize){
7724 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
7726 }, this.textResizeInterval);
7728 textEvent.addListener(fn, scope, options);
7732 * Removes the passed window resize listener.
7733 * @param {Function} fn The method the event invokes
7734 * @param {Object} scope The scope of handler
7736 removeResizeListener : function(fn, scope){
7738 resizeEvent.removeListener(fn, scope);
7743 fireResize : function(){
7745 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7749 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
7753 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
7755 textResizeInterval : 50
7760 * @scopeAlias pub=Roo.EventManager
7764 * Appends an event handler to an element (shorthand for addListener)
7765 * @param {String/HTMLElement} element The html element or id to assign the
7766 * @param {String} eventName The type of event to listen for
7767 * @param {Function} handler The method the event invokes
7768 * @param {Object} scope (optional) The scope in which to execute the handler
7769 * function. The handler function's "this" context.
7770 * @param {Object} options (optional) An object containing handler configuration
7771 * properties. This may contain any of the following properties:<ul>
7772 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7773 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7774 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7775 * <li>preventDefault {Boolean} True to prevent the default action</li>
7776 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7777 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7778 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7779 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7780 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7781 * by the specified number of milliseconds. If the event fires again within that time, the original
7782 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7785 * <b>Combining Options</b><br>
7786 * Using the options argument, it is possible to combine different types of listeners:<br>
7788 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7790 el.on('click', this.onClick, this, {
7797 * <b>Attaching multiple handlers in 1 call</b><br>
7798 * The method also allows for a single argument to be passed which is a config object containing properties
7799 * which specify multiple handlers.
7809 fn: this.onMouseOver
7818 * Or a shorthand syntax:<br>
7821 'click' : this.onClick,
7822 'mouseover' : this.onMouseOver,
7823 'mouseout' : this.onMouseOut
7827 pub.on = pub.addListener;
7828 pub.un = pub.removeListener;
7830 pub.stoppedMouseDownEvent = new Roo.util.Event();
7834 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
7835 * @param {Function} fn The method the event invokes
7836 * @param {Object} scope An object that becomes the scope of the handler
7837 * @param {boolean} override If true, the obj passed in becomes
7838 * the execution scope of the listener
7842 Roo.onReady = Roo.EventManager.onDocumentReady;
7844 Roo.onReady(function(){
7845 var bd = Roo.get(document.body);
7850 : Roo.isIE11 ? "roo-ie11"
7851 : Roo.isEdge ? "roo-edge"
7852 : Roo.isGecko ? "roo-gecko"
7853 : Roo.isOpera ? "roo-opera"
7854 : Roo.isSafari ? "roo-safari" : ""];
7857 cls.push("roo-mac");
7860 cls.push("roo-linux");
7863 cls.push("roo-ios");
7866 cls.push("roo-touch");
7868 if(Roo.isBorderBox){
7869 cls.push('roo-border-box');
7871 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
7872 var p = bd.dom.parentNode;
7874 p.className += ' roo-strict';
7877 bd.addClass(cls.join(' '));
7881 * @class Roo.EventObject
7882 * EventObject exposes the Yahoo! UI Event functionality directly on the object
7883 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
7886 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
7888 var target = e.getTarget();
7891 var myDiv = Roo.get("myDiv");
7892 myDiv.on("click", handleClick);
7894 Roo.EventManager.on("myDiv", 'click', handleClick);
7895 Roo.EventManager.addListener("myDiv", 'click', handleClick);
7899 Roo.EventObject = function(){
7901 var E = Roo.lib.Event;
7903 // safari keypress events for special keys return bad keycodes
7906 63235 : 39, // right
7909 63276 : 33, // page up
7910 63277 : 34, // page down
7911 63272 : 46, // delete
7916 // normalize button clicks
7917 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
7918 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
7920 Roo.EventObjectImpl = function(e){
7922 this.setEvent(e.browserEvent || e);
7925 Roo.EventObjectImpl.prototype = {
7927 * Used to fix doc tools.
7928 * @scope Roo.EventObject.prototype
7934 /** The normal browser event */
7935 browserEvent : null,
7936 /** The button pressed in a mouse event */
7938 /** True if the shift key was down during the event */
7940 /** True if the control key was down during the event */
7942 /** True if the alt key was down during the event */
8001 setEvent : function(e){
8002 if(e == this || (e && e.browserEvent)){ // already wrapped
8005 this.browserEvent = e;
8007 // normalize buttons
8008 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
8009 if(e.type == 'click' && this.button == -1){
8013 this.shiftKey = e.shiftKey;
8014 // mac metaKey behaves like ctrlKey
8015 this.ctrlKey = e.ctrlKey || e.metaKey;
8016 this.altKey = e.altKey;
8017 // in getKey these will be normalized for the mac
8018 this.keyCode = e.keyCode;
8019 // keyup warnings on firefox.
8020 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
8021 // cache the target for the delayed and or buffered events
8022 this.target = E.getTarget(e);
8024 this.xy = E.getXY(e);
8027 this.shiftKey = false;
8028 this.ctrlKey = false;
8029 this.altKey = false;
8039 * Stop the event (preventDefault and stopPropagation)
8041 stopEvent : function(){
8042 if(this.browserEvent){
8043 if(this.browserEvent.type == 'mousedown'){
8044 Roo.EventManager.stoppedMouseDownEvent.fire(this);
8046 E.stopEvent(this.browserEvent);
8051 * Prevents the browsers default handling of the event.
8053 preventDefault : function(){
8054 if(this.browserEvent){
8055 E.preventDefault(this.browserEvent);
8060 isNavKeyPress : function(){
8061 var k = this.keyCode;
8062 k = Roo.isSafari ? (safariKeys[k] || k) : k;
8063 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
8066 isSpecialKey : function(){
8067 var k = this.keyCode;
8068 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
8069 (k == 16) || (k == 17) ||
8070 (k >= 18 && k <= 20) ||
8071 (k >= 33 && k <= 35) ||
8072 (k >= 36 && k <= 39) ||
8073 (k >= 44 && k <= 45);
8076 * Cancels bubbling of the event.
8078 stopPropagation : function(){
8079 if(this.browserEvent){
8080 if(this.type == 'mousedown'){
8081 Roo.EventManager.stoppedMouseDownEvent.fire(this);
8083 E.stopPropagation(this.browserEvent);
8088 * Gets the key code for the event.
8091 getCharCode : function(){
8092 return this.charCode || this.keyCode;
8096 * Returns a normalized keyCode for the event.
8097 * @return {Number} The key code
8099 getKey : function(){
8100 var k = this.keyCode || this.charCode;
8101 return Roo.isSafari ? (safariKeys[k] || k) : k;
8105 * Gets the x coordinate of the event.
8108 getPageX : function(){
8113 * Gets the y coordinate of the event.
8116 getPageY : function(){
8121 * Gets the time of the event.
8124 getTime : function(){
8125 if(this.browserEvent){
8126 return E.getTime(this.browserEvent);
8132 * Gets the page coordinates of the event.
8133 * @return {Array} The xy values like [x, y]
8140 * Gets the target for the event.
8141 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
8142 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8143 search as a number or element (defaults to 10 || document.body)
8144 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8145 * @return {HTMLelement}
8147 getTarget : function(selector, maxDepth, returnEl){
8148 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
8151 * Gets the related target.
8152 * @return {HTMLElement}
8154 getRelatedTarget : function(){
8155 if(this.browserEvent){
8156 return E.getRelatedTarget(this.browserEvent);
8162 * Normalizes mouse wheel delta across browsers
8163 * @return {Number} The delta
8165 getWheelDelta : function(){
8166 var e = this.browserEvent;
8168 if(e.wheelDelta){ /* IE/Opera. */
8169 delta = e.wheelDelta/120;
8170 }else if(e.detail){ /* Mozilla case. */
8171 delta = -e.detail/3;
8177 * Returns true if the control, meta, shift or alt key was pressed during this event.
8180 hasModifier : function(){
8181 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
8185 * Returns true if the target of this event equals el or is a child of el
8186 * @param {String/HTMLElement/Element} el
8187 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
8190 within : function(el, related){
8191 var t = this[related ? "getRelatedTarget" : "getTarget"]();
8192 return t && Roo.fly(el).contains(t);
8195 getPoint : function(){
8196 return new Roo.lib.Point(this.xy[0], this.xy[1]);
8200 return new Roo.EventObjectImpl();
8205 * Ext JS Library 1.1.1
8206 * Copyright(c) 2006-2007, Ext JS, LLC.
8208 * Originally Released Under LGPL - original licence link has changed is not relivant.
8211 * <script type="text/javascript">
8215 // was in Composite Element!??!?!
8218 var D = Roo.lib.Dom;
8219 var E = Roo.lib.Event;
8220 var A = Roo.lib.Anim;
8222 // local style camelizing for speed
8224 var camelRe = /(-[a-z])/gi;
8225 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
8226 var view = document.defaultView;
8229 * @class Roo.Element
8230 * Represents an Element in the DOM.<br><br>
8233 var el = Roo.get("my-div");
8236 var el = getEl("my-div");
8238 // or with a DOM element
8239 var el = Roo.get(myDivElement);
8241 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
8242 * each call instead of constructing a new one.<br><br>
8243 * <b>Animations</b><br />
8244 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
8245 * should either be a boolean (true) or an object literal with animation options. The animation options are:
8247 Option Default Description
8248 --------- -------- ---------------------------------------------
8249 duration .35 The duration of the animation in seconds
8250 easing easeOut The YUI easing method
8251 callback none A function to execute when the anim completes
8252 scope this The scope (this) of the callback function
8254 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
8255 * manipulate the animation. Here's an example:
8257 var el = Roo.get("my-div");
8262 // default animation
8263 el.setWidth(100, true);
8265 // animation with some options set
8272 // using the "anim" property to get the Anim object
8278 el.setWidth(100, opt);
8280 if(opt.anim.isAnimated()){
8284 * <b> Composite (Collections of) Elements</b><br />
8285 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
8286 * @constructor Create a new Element directly.
8287 * @param {String/HTMLElement} element
8288 * @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).
8290 Roo.Element = function(element, forceNew)
8292 var dom = typeof element == "string" ?
8293 document.getElementById(element) : element;
8295 this.listeners = {};
8297 if(!dom){ // invalid id/element
8301 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
8302 return Roo.Element.cache[id];
8312 * The DOM element ID
8315 this.id = id || Roo.id(dom);
8317 return this; // assumed for cctor?
8320 var El = Roo.Element;
8324 * The element's default display mode (defaults to "")
8327 originalDisplay : "",
8330 // note this is overridden in BS version..
8333 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
8339 * Sets the element's visibility mode. When setVisible() is called it
8340 * will use this to determine whether to set the visibility or the display property.
8341 * @param visMode Element.VISIBILITY or Element.DISPLAY
8342 * @return {Roo.Element} this
8344 setVisibilityMode : function(visMode){
8345 this.visibilityMode = visMode;
8349 * Convenience method for setVisibilityMode(Element.DISPLAY)
8350 * @param {String} display (optional) What to set display to when visible
8351 * @return {Roo.Element} this
8353 enableDisplayMode : function(display){
8354 this.setVisibilityMode(El.DISPLAY);
8355 if(typeof display != "undefined") { this.originalDisplay = display; }
8360 * 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)
8361 * @param {String} selector The simple selector to test
8362 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8363 search as a number or element (defaults to 10 || document.body)
8364 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8365 * @return {HTMLElement} The matching DOM node (or null if no match was found)
8367 findParent : function(simpleSelector, maxDepth, returnEl){
8368 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
8369 maxDepth = maxDepth || 50;
8370 if(typeof maxDepth != "number"){
8371 stopEl = Roo.getDom(maxDepth);
8374 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
8375 if(dq.is(p, simpleSelector)){
8376 return returnEl ? Roo.get(p) : p;
8386 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
8387 * @param {String} selector The simple selector to test
8388 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8389 search as a number or element (defaults to 10 || document.body)
8390 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8391 * @return {HTMLElement} The matching DOM node (or null if no match was found)
8393 findParentNode : function(simpleSelector, maxDepth, returnEl){
8394 var p = Roo.fly(this.dom.parentNode, '_internal');
8395 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
8399 * Looks at the scrollable parent element
8401 findScrollableParent : function()
8403 var overflowRegex = /(auto|scroll)/;
8405 if(this.getStyle('position') === 'fixed'){
8406 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8409 var excludeStaticParent = this.getStyle('position') === "absolute";
8411 for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
8413 if (excludeStaticParent && parent.getStyle('position') === "static") {
8417 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
8421 if(parent.dom.nodeName.toLowerCase() == 'body'){
8422 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8426 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8430 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
8431 * This is a shortcut for findParentNode() that always returns an Roo.Element.
8432 * @param {String} selector The simple selector to test
8433 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8434 search as a number or element (defaults to 10 || document.body)
8435 * @return {Roo.Element} The matching DOM node (or null if no match was found)
8437 up : function(simpleSelector, maxDepth){
8438 return this.findParentNode(simpleSelector, maxDepth, true);
8444 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
8445 * @param {String} selector The simple selector to test
8446 * @return {Boolean} True if this element matches the selector, else false
8448 is : function(simpleSelector){
8449 return Roo.DomQuery.is(this.dom, simpleSelector);
8453 * Perform animation on this element.
8454 * @param {Object} args The YUI animation control args
8455 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
8456 * @param {Function} onComplete (optional) Function to call when animation completes
8457 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
8458 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
8459 * @return {Roo.Element} this
8461 animate : function(args, duration, onComplete, easing, animType){
8462 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
8467 * @private Internal animation call
8469 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
8470 animType = animType || 'run';
8472 var anim = Roo.lib.Anim[animType](
8474 (opt.duration || defaultDur) || .35,
8475 (opt.easing || defaultEase) || 'easeOut',
8477 Roo.callback(cb, this);
8478 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
8486 // private legacy anim prep
8487 preanim : function(a, i){
8488 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
8492 * Removes worthless text nodes
8493 * @param {Boolean} forceReclean (optional) By default the element
8494 * keeps track if it has been cleaned already so
8495 * you can call this over and over. However, if you update the element and
8496 * need to force a reclean, you can pass true.
8498 clean : function(forceReclean){
8499 if(this.isCleaned && forceReclean !== true){
8503 var d = this.dom, n = d.firstChild, ni = -1;
8505 var nx = n.nextSibling;
8506 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
8513 this.isCleaned = true;
8518 calcOffsetsTo : function(el){
8521 var restorePos = false;
8522 if(el.getStyle('position') == 'static'){
8523 el.position('relative');
8528 while(op && op != d && op.tagName != 'HTML'){
8531 op = op.offsetParent;
8534 el.position('static');
8540 * Scrolls this element into view within the passed container.
8541 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
8542 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
8543 * @return {Roo.Element} this
8545 scrollIntoView : function(container, hscroll){
8546 var c = Roo.getDom(container) || document.body;
8549 var o = this.calcOffsetsTo(c),
8552 b = t+el.offsetHeight,
8553 r = l+el.offsetWidth;
8555 var ch = c.clientHeight;
8556 var ct = parseInt(c.scrollTop, 10);
8557 var cl = parseInt(c.scrollLeft, 10);
8559 var cr = cl + c.clientWidth;
8567 if(hscroll !== false){
8571 c.scrollLeft = r-c.clientWidth;
8578 scrollChildIntoView : function(child, hscroll){
8579 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
8583 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
8584 * the new height may not be available immediately.
8585 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
8586 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
8587 * @param {Function} onComplete (optional) Function to call when animation completes
8588 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
8589 * @return {Roo.Element} this
8591 autoHeight : function(animate, duration, onComplete, easing){
8592 var oldHeight = this.getHeight();
8594 this.setHeight(1); // force clipping
8595 setTimeout(function(){
8596 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
8598 this.setHeight(height);
8600 if(typeof onComplete == "function"){
8604 this.setHeight(oldHeight); // restore original height
8605 this.setHeight(height, animate, duration, function(){
8607 if(typeof onComplete == "function") { onComplete(); }
8608 }.createDelegate(this), easing);
8610 }.createDelegate(this), 0);
8615 * Returns true if this element is an ancestor of the passed element
8616 * @param {HTMLElement/String} el The element to check
8617 * @return {Boolean} True if this element is an ancestor of el, else false
8619 contains : function(el){
8620 if(!el){return false;}
8621 return D.isAncestor(this.dom, el.dom ? el.dom : el);
8625 * Checks whether the element is currently visible using both visibility and display properties.
8626 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
8627 * @return {Boolean} True if the element is currently visible, else false
8629 isVisible : function(deep) {
8630 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
8631 if(deep !== true || !vis){
8634 var p = this.dom.parentNode;
8635 while(p && p.tagName.toLowerCase() != "body"){
8636 if(!Roo.fly(p, '_isVisible').isVisible()){
8645 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
8646 * @param {String} selector The CSS selector
8647 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
8648 * @return {CompositeElement/CompositeElementLite} The composite element
8650 select : function(selector, unique){
8651 return El.select(selector, unique, this.dom);
8655 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
8656 * @param {String} selector The CSS selector
8657 * @return {Array} An array of the matched nodes
8659 query : function(selector, unique){
8660 return Roo.DomQuery.select(selector, this.dom);
8664 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
8665 * @param {String} selector The CSS selector
8666 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8667 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8669 child : function(selector, returnDom){
8670 var n = Roo.DomQuery.selectNode(selector, this.dom);
8671 return returnDom ? n : Roo.get(n);
8675 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
8676 * @param {String} selector The CSS selector
8677 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8678 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8680 down : function(selector, returnDom){
8681 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
8682 return returnDom ? n : Roo.get(n);
8686 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
8687 * @param {String} group The group the DD object is member of
8688 * @param {Object} config The DD config object
8689 * @param {Object} overrides An object containing methods to override/implement on the DD object
8690 * @return {Roo.dd.DD} The DD object
8692 initDD : function(group, config, overrides){
8693 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
8694 return Roo.apply(dd, overrides);
8698 * Initializes a {@link Roo.dd.DDProxy} object for this element.
8699 * @param {String} group The group the DDProxy object is member of
8700 * @param {Object} config The DDProxy config object
8701 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
8702 * @return {Roo.dd.DDProxy} The DDProxy object
8704 initDDProxy : function(group, config, overrides){
8705 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
8706 return Roo.apply(dd, overrides);
8710 * Initializes a {@link Roo.dd.DDTarget} object for this element.
8711 * @param {String} group The group the DDTarget object is member of
8712 * @param {Object} config The DDTarget config object
8713 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
8714 * @return {Roo.dd.DDTarget} The DDTarget object
8716 initDDTarget : function(group, config, overrides){
8717 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
8718 return Roo.apply(dd, overrides);
8722 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
8723 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
8724 * @param {Boolean} visible Whether the element is visible
8725 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8726 * @return {Roo.Element} this
8728 setVisible : function(visible, animate){
8730 if(this.visibilityMode == El.DISPLAY){
8731 this.setDisplayed(visible);
8734 this.dom.style.visibility = visible ? "visible" : "hidden";
8737 // closure for composites
8739 var visMode = this.visibilityMode;
8741 this.setOpacity(.01);
8742 this.setVisible(true);
8744 this.anim({opacity: { to: (visible?1:0) }},
8745 this.preanim(arguments, 1),
8746 null, .35, 'easeIn', function(){
8748 if(visMode == El.DISPLAY){
8749 dom.style.display = "none";
8751 dom.style.visibility = "hidden";
8753 Roo.get(dom).setOpacity(1);
8761 * Returns true if display is not "none"
8764 isDisplayed : function() {
8765 return this.getStyle("display") != "none";
8769 * Toggles the element's visibility or display, depending on visibility mode.
8770 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8771 * @return {Roo.Element} this
8773 toggle : function(animate){
8774 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
8779 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
8780 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
8781 * @return {Roo.Element} this
8783 setDisplayed : function(value) {
8784 if(typeof value == "boolean"){
8785 value = value ? this.originalDisplay : "none";
8787 this.setStyle("display", value);
8792 * Tries to focus the element. Any exceptions are caught and ignored.
8793 * @return {Roo.Element} this
8795 focus : function() {
8803 * Tries to blur the element. Any exceptions are caught and ignored.
8804 * @return {Roo.Element} this
8814 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
8815 * @param {String/Array} className The CSS class to add, or an array of classes
8816 * @return {Roo.Element} this
8818 addClass : function(className){
8819 if(className instanceof Array){
8820 for(var i = 0, len = className.length; i < len; i++) {
8821 this.addClass(className[i]);
8824 if(className && !this.hasClass(className)){
8825 if (this.dom instanceof SVGElement) {
8826 this.dom.className.baseVal =this.dom.className.baseVal + " " + className;
8828 this.dom.className = this.dom.className + " " + className;
8836 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
8837 * @param {String/Array} className The CSS class to add, or an array of classes
8838 * @return {Roo.Element} this
8840 radioClass : function(className){
8841 var siblings = this.dom.parentNode.childNodes;
8842 for(var i = 0; i < siblings.length; i++) {
8843 var s = siblings[i];
8844 if(s.nodeType == 1){
8845 Roo.get(s).removeClass(className);
8848 this.addClass(className);
8853 * Removes one or more CSS classes from the element.
8854 * @param {String/Array} className The CSS class to remove, or an array of classes
8855 * @return {Roo.Element} this
8857 removeClass : function(className){
8859 var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
8860 if(!className || !cn){
8863 if(className instanceof Array){
8864 for(var i = 0, len = className.length; i < len; i++) {
8865 this.removeClass(className[i]);
8868 if(this.hasClass(className)){
8869 var re = this.classReCache[className];
8871 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
8872 this.classReCache[className] = re;
8874 if (this.dom instanceof SVGElement) {
8875 this.dom.className.baseVal = cn.replace(re, " ");
8877 this.dom.className = cn.replace(re, " ");
8888 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
8889 * @param {String} className The CSS class to toggle
8890 * @return {Roo.Element} this
8892 toggleClass : function(className){
8893 if(this.hasClass(className)){
8894 this.removeClass(className);
8896 this.addClass(className);
8902 * Checks if the specified CSS class exists on this element's DOM node.
8903 * @param {String} className The CSS class to check for
8904 * @return {Boolean} True if the class exists, else false
8906 hasClass : function(className){
8907 if (this.dom instanceof SVGElement) {
8908 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1;
8910 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
8914 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
8915 * @param {String} oldClassName The CSS class to replace
8916 * @param {String} newClassName The replacement CSS class
8917 * @return {Roo.Element} this
8919 replaceClass : function(oldClassName, newClassName){
8920 this.removeClass(oldClassName);
8921 this.addClass(newClassName);
8926 * Returns an object with properties matching the styles requested.
8927 * For example, el.getStyles('color', 'font-size', 'width') might return
8928 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
8929 * @param {String} style1 A style name
8930 * @param {String} style2 A style name
8931 * @param {String} etc.
8932 * @return {Object} The style object
8934 getStyles : function(){
8935 var a = arguments, len = a.length, r = {};
8936 for(var i = 0; i < len; i++){
8937 r[a[i]] = this.getStyle(a[i]);
8943 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
8944 * @param {String} property The style property whose value is returned.
8945 * @return {String} The current value of the style property for this element.
8947 getStyle : function(){
8948 return view && view.getComputedStyle ?
8950 var el = this.dom, v, cs, camel;
8951 if(prop == 'float'){
8954 if(el.style && (v = el.style[prop])){
8957 if(cs = view.getComputedStyle(el, "")){
8958 if(!(camel = propCache[prop])){
8959 camel = propCache[prop] = prop.replace(camelRe, camelFn);
8966 var el = this.dom, v, cs, camel;
8967 if(prop == 'opacity'){
8968 if(typeof el.style.filter == 'string'){
8969 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
8971 var fv = parseFloat(m[1]);
8973 return fv ? fv / 100 : 0;
8978 }else if(prop == 'float'){
8979 prop = "styleFloat";
8981 if(!(camel = propCache[prop])){
8982 camel = propCache[prop] = prop.replace(camelRe, camelFn);
8984 if(v = el.style[camel]){
8987 if(cs = el.currentStyle){
8995 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
8996 * @param {String/Object} property The style property to be set, or an object of multiple styles.
8997 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
8998 * @return {Roo.Element} this
9000 setStyle : function(prop, value){
9001 if(typeof prop == "string"){
9003 if (prop == 'float') {
9004 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
9009 if(!(camel = propCache[prop])){
9010 camel = propCache[prop] = prop.replace(camelRe, camelFn);
9013 if(camel == 'opacity') {
9014 this.setOpacity(value);
9016 this.dom.style[camel] = value;
9019 for(var style in prop){
9020 if(typeof prop[style] != "function"){
9021 this.setStyle(style, prop[style]);
9029 * More flexible version of {@link #setStyle} for setting style properties.
9030 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
9031 * a function which returns such a specification.
9032 * @return {Roo.Element} this
9034 applyStyles : function(style){
9035 Roo.DomHelper.applyStyles(this.dom, style);
9040 * 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).
9041 * @return {Number} The X position of the element
9044 return D.getX(this.dom);
9048 * 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).
9049 * @return {Number} The Y position of the element
9052 return D.getY(this.dom);
9056 * 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).
9057 * @return {Array} The XY position of the element
9060 return D.getXY(this.dom);
9064 * 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).
9065 * @param {Number} The X position of the element
9066 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9067 * @return {Roo.Element} this
9069 setX : function(x, animate){
9071 D.setX(this.dom, x);
9073 this.setXY([x, this.getY()], this.preanim(arguments, 1));
9079 * 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).
9080 * @param {Number} The Y position of the element
9081 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9082 * @return {Roo.Element} this
9084 setY : function(y, animate){
9086 D.setY(this.dom, y);
9088 this.setXY([this.getX(), y], this.preanim(arguments, 1));
9094 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
9095 * @param {String} left The left CSS property value
9096 * @return {Roo.Element} this
9098 setLeft : function(left){
9099 this.setStyle("left", this.addUnits(left));
9104 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
9105 * @param {String} top The top CSS property value
9106 * @return {Roo.Element} this
9108 setTop : function(top){
9109 this.setStyle("top", this.addUnits(top));
9114 * Sets the element's CSS right style.
9115 * @param {String} right The right CSS property value
9116 * @return {Roo.Element} this
9118 setRight : function(right){
9119 this.setStyle("right", this.addUnits(right));
9124 * Sets the element's CSS bottom style.
9125 * @param {String} bottom The bottom CSS property value
9126 * @return {Roo.Element} this
9128 setBottom : function(bottom){
9129 this.setStyle("bottom", this.addUnits(bottom));
9134 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9135 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9136 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
9137 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9138 * @return {Roo.Element} this
9140 setXY : function(pos, animate){
9142 D.setXY(this.dom, pos);
9144 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
9150 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9151 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9152 * @param {Number} x X value for new position (coordinates are page-based)
9153 * @param {Number} y Y value for new position (coordinates are page-based)
9154 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9155 * @return {Roo.Element} this
9157 setLocation : function(x, y, animate){
9158 this.setXY([x, y], this.preanim(arguments, 2));
9163 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9164 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9165 * @param {Number} x X value for new position (coordinates are page-based)
9166 * @param {Number} y Y value for new position (coordinates are page-based)
9167 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9168 * @return {Roo.Element} this
9170 moveTo : function(x, y, animate){
9171 this.setXY([x, y], this.preanim(arguments, 2));
9176 * Returns the region of the given element.
9177 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
9178 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
9180 getRegion : function(){
9181 return D.getRegion(this.dom);
9185 * Returns the offset height of the element
9186 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
9187 * @return {Number} The element's height
9189 getHeight : function(contentHeight){
9190 var h = this.dom.offsetHeight || 0;
9191 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
9195 * Returns the offset width of the element
9196 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
9197 * @return {Number} The element's width
9199 getWidth : function(contentWidth){
9200 var w = this.dom.offsetWidth || 0;
9201 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
9205 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
9206 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
9207 * if a height has not been set using CSS.
9210 getComputedHeight : function(){
9211 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
9213 h = parseInt(this.getStyle('height'), 10) || 0;
9214 if(!this.isBorderBox()){
9215 h += this.getFrameWidth('tb');
9222 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
9223 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
9224 * if a width has not been set using CSS.
9227 getComputedWidth : function(){
9228 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
9230 w = parseInt(this.getStyle('width'), 10) || 0;
9231 if(!this.isBorderBox()){
9232 w += this.getFrameWidth('lr');
9239 * Returns the size of the element.
9240 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
9241 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
9243 getSize : function(contentSize){
9244 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
9248 * Returns the width and height of the viewport.
9249 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
9251 getViewSize : function(){
9252 var d = this.dom, doc = document, aw = 0, ah = 0;
9253 if(d == doc || d == doc.body){
9254 return {width : D.getViewWidth(), height: D.getViewHeight()};
9257 width : d.clientWidth,
9258 height: d.clientHeight
9264 * Returns the value of the "value" attribute
9265 * @param {Boolean} asNumber true to parse the value as a number
9266 * @return {String/Number}
9268 getValue : function(asNumber){
9269 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
9273 adjustWidth : function(width){
9274 if(typeof width == "number"){
9275 if(this.autoBoxAdjust && !this.isBorderBox()){
9276 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9286 adjustHeight : function(height){
9287 if(typeof height == "number"){
9288 if(this.autoBoxAdjust && !this.isBorderBox()){
9289 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9299 * Set the width of the element
9300 * @param {Number} width The new width
9301 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9302 * @return {Roo.Element} this
9304 setWidth : function(width, animate){
9305 width = this.adjustWidth(width);
9307 this.dom.style.width = this.addUnits(width);
9309 this.anim({width: {to: width}}, this.preanim(arguments, 1));
9315 * Set the height of the element
9316 * @param {Number} height The new height
9317 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9318 * @return {Roo.Element} this
9320 setHeight : function(height, animate){
9321 height = this.adjustHeight(height);
9323 this.dom.style.height = this.addUnits(height);
9325 this.anim({height: {to: height}}, this.preanim(arguments, 1));
9331 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
9332 * @param {Number} width The new width
9333 * @param {Number} height The new height
9334 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9335 * @return {Roo.Element} this
9337 setSize : function(width, height, animate){
9338 if(typeof width == "object"){ // in case of object from getSize()
9339 height = width.height; width = width.width;
9341 width = this.adjustWidth(width); height = this.adjustHeight(height);
9343 this.dom.style.width = this.addUnits(width);
9344 this.dom.style.height = this.addUnits(height);
9346 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
9352 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
9353 * @param {Number} x X value for new position (coordinates are page-based)
9354 * @param {Number} y Y value for new position (coordinates are page-based)
9355 * @param {Number} width The new width
9356 * @param {Number} height The new height
9357 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9358 * @return {Roo.Element} this
9360 setBounds : function(x, y, width, height, animate){
9362 this.setSize(width, height);
9363 this.setLocation(x, y);
9365 width = this.adjustWidth(width); height = this.adjustHeight(height);
9366 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
9367 this.preanim(arguments, 4), 'motion');
9373 * 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.
9374 * @param {Roo.lib.Region} region The region to fill
9375 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9376 * @return {Roo.Element} this
9378 setRegion : function(region, animate){
9379 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
9384 * Appends an event handler
9386 * @param {String} eventName The type of event to append
9387 * @param {Function} fn The method the event invokes
9388 * @param {Object} scope (optional) The scope (this object) of the fn
9389 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9391 addListener : function(eventName, fn, scope, options)
9393 if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
9394 this.addListener('touchstart', this.onTapHandler, this);
9397 // we need to handle a special case where dom element is a svg element.
9398 // in this case we do not actua
9403 if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
9404 if (typeof(this.listeners[eventName]) == 'undefined') {
9405 this.listeners[eventName] = new Roo.util.Event(this, eventName);
9407 this.listeners[eventName].addListener(fn, scope, options);
9412 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
9417 onTapHandler : function(event)
9419 if(!this.tapedTwice) {
9420 this.tapedTwice = true;
9422 setTimeout( function() {
9423 s.tapedTwice = false;
9427 event.preventDefault();
9428 var revent = new MouseEvent('dblclick', {
9434 this.dom.dispatchEvent(revent);
9435 //action on double tap goes below
9440 * Removes an event handler from this element
9441 * @param {String} eventName the type of event to remove
9442 * @param {Function} fn the method the event invokes
9443 * @param {Function} scope (needed for svg fake listeners)
9444 * @return {Roo.Element} this
9446 removeListener : function(eventName, fn, scope){
9447 Roo.EventManager.removeListener(this.dom, eventName, fn);
9448 if (typeof(this.listeners) == 'undefined' || typeof(this.listeners[eventName]) == 'undefined') {
9451 this.listeners[eventName].removeListener(fn, scope);
9456 * Removes all previous added listeners from this element
9457 * @return {Roo.Element} this
9459 removeAllListeners : function(){
9460 E.purgeElement(this.dom);
9461 this.listeners = {};
9465 relayEvent : function(eventName, observable){
9466 this.on(eventName, function(e){
9467 observable.fireEvent(eventName, e);
9473 * Set the opacity of the element
9474 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
9475 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9476 * @return {Roo.Element} this
9478 setOpacity : function(opacity, animate){
9480 var s = this.dom.style;
9483 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
9484 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
9486 s.opacity = opacity;
9489 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
9495 * Gets the left X coordinate
9496 * @param {Boolean} local True to get the local css position instead of page coordinate
9499 getLeft : function(local){
9503 return parseInt(this.getStyle("left"), 10) || 0;
9508 * Gets the right X coordinate of the element (element X position + element width)
9509 * @param {Boolean} local True to get the local css position instead of page coordinate
9512 getRight : function(local){
9514 return this.getX() + this.getWidth();
9516 return (this.getLeft(true) + this.getWidth()) || 0;
9521 * Gets the top Y coordinate
9522 * @param {Boolean} local True to get the local css position instead of page coordinate
9525 getTop : function(local) {
9529 return parseInt(this.getStyle("top"), 10) || 0;
9534 * Gets the bottom Y coordinate of the element (element Y position + element height)
9535 * @param {Boolean} local True to get the local css position instead of page coordinate
9538 getBottom : function(local){
9540 return this.getY() + this.getHeight();
9542 return (this.getTop(true) + this.getHeight()) || 0;
9547 * Initializes positioning on this element. If a desired position is not passed, it will make the
9548 * the element positioned relative IF it is not already positioned.
9549 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
9550 * @param {Number} zIndex (optional) The zIndex to apply
9551 * @param {Number} x (optional) Set the page X position
9552 * @param {Number} y (optional) Set the page Y position
9554 position : function(pos, zIndex, x, y){
9556 if(this.getStyle('position') == 'static'){
9557 this.setStyle('position', 'relative');
9560 this.setStyle("position", pos);
9563 this.setStyle("z-index", zIndex);
9565 if(x !== undefined && y !== undefined){
9567 }else if(x !== undefined){
9569 }else if(y !== undefined){
9575 * Clear positioning back to the default when the document was loaded
9576 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
9577 * @return {Roo.Element} this
9579 clearPositioning : function(value){
9587 "position" : "static"
9593 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
9594 * snapshot before performing an update and then restoring the element.
9597 getPositioning : function(){
9598 var l = this.getStyle("left");
9599 var t = this.getStyle("top");
9601 "position" : this.getStyle("position"),
9603 "right" : l ? "" : this.getStyle("right"),
9605 "bottom" : t ? "" : this.getStyle("bottom"),
9606 "z-index" : this.getStyle("z-index")
9611 * Gets the width of the border(s) for the specified side(s)
9612 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9613 * passing lr would get the border (l)eft width + the border (r)ight width.
9614 * @return {Number} The width of the sides passed added together
9616 getBorderWidth : function(side){
9617 return this.addStyles(side, El.borders);
9621 * Gets the width of the padding(s) for the specified side(s)
9622 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9623 * passing lr would get the padding (l)eft + the padding (r)ight.
9624 * @return {Number} The padding of the sides passed added together
9626 getPadding : function(side){
9627 return this.addStyles(side, El.paddings);
9631 * Set positioning with an object returned by getPositioning().
9632 * @param {Object} posCfg
9633 * @return {Roo.Element} this
9635 setPositioning : function(pc){
9636 this.applyStyles(pc);
9637 if(pc.right == "auto"){
9638 this.dom.style.right = "";
9640 if(pc.bottom == "auto"){
9641 this.dom.style.bottom = "";
9647 fixDisplay : function(){
9648 if(this.getStyle("display") == "none"){
9649 this.setStyle("visibility", "hidden");
9650 this.setStyle("display", this.originalDisplay); // first try reverting to default
9651 if(this.getStyle("display") == "none"){ // if that fails, default to block
9652 this.setStyle("display", "block");
9658 * Quick set left and top adding default units
9659 * @param {String} left The left CSS property value
9660 * @param {String} top The top CSS property value
9661 * @return {Roo.Element} this
9663 setLeftTop : function(left, top){
9664 this.dom.style.left = this.addUnits(left);
9665 this.dom.style.top = this.addUnits(top);
9670 * Move this element relative to its current position.
9671 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9672 * @param {Number} distance How far to move the element in pixels
9673 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9674 * @return {Roo.Element} this
9676 move : function(direction, distance, animate){
9677 var xy = this.getXY();
9678 direction = direction.toLowerCase();
9682 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
9686 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
9691 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
9696 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
9703 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
9704 * @return {Roo.Element} this
9707 if(!this.isClipped){
9708 this.isClipped = true;
9709 this.originalClip = {
9710 "o": this.getStyle("overflow"),
9711 "x": this.getStyle("overflow-x"),
9712 "y": this.getStyle("overflow-y")
9714 this.setStyle("overflow", "hidden");
9715 this.setStyle("overflow-x", "hidden");
9716 this.setStyle("overflow-y", "hidden");
9722 * Return clipping (overflow) to original clipping before clip() was called
9723 * @return {Roo.Element} this
9725 unclip : function(){
9727 this.isClipped = false;
9728 var o = this.originalClip;
9729 if(o.o){this.setStyle("overflow", o.o);}
9730 if(o.x){this.setStyle("overflow-x", o.x);}
9731 if(o.y){this.setStyle("overflow-y", o.y);}
9738 * Gets the x,y coordinates specified by the anchor position on the element.
9739 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
9740 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
9741 * {width: (target width), height: (target height)} (defaults to the element's current size)
9742 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
9743 * @return {Array} [x, y] An array containing the element's x and y coordinates
9745 getAnchorXY : function(anchor, local, s){
9746 //Passing a different size is useful for pre-calculating anchors,
9747 //especially for anchored animations that change the el size.
9749 var w, h, vp = false;
9752 if(d == document.body || d == document){
9754 w = D.getViewWidth(); h = D.getViewHeight();
9756 w = this.getWidth(); h = this.getHeight();
9759 w = s.width; h = s.height;
9761 var x = 0, y = 0, r = Math.round;
9762 switch((anchor || "tl").toLowerCase()){
9804 var sc = this.getScroll();
9805 return [x + sc.left, y + sc.top];
9807 //Add the element's offset xy
9808 var o = this.getXY();
9809 return [x+o[0], y+o[1]];
9813 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
9814 * supported position values.
9815 * @param {String/HTMLElement/Roo.Element} element The element to align to.
9816 * @param {String} position The position to align to.
9817 * @param {Array} offsets (optional) Offset the positioning by [x, y]
9818 * @return {Array} [x, y]
9820 getAlignToXY : function(el, p, o)
9825 throw "Element.alignTo with an element that doesn't exist";
9827 var c = false; //constrain to viewport
9828 var p1 = "", p2 = "";
9835 }else if(p.indexOf("-") == -1){
9838 p = p.toLowerCase();
9839 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
9841 throw "Element.alignTo with an invalid alignment " + p;
9843 p1 = m[1]; p2 = m[2]; c = !!m[3];
9845 //Subtract the aligned el's internal xy from the target's offset xy
9846 //plus custom offset to get the aligned el's new offset xy
9847 var a1 = this.getAnchorXY(p1, true);
9848 var a2 = el.getAnchorXY(p2, false);
9849 var x = a2[0] - a1[0] + o[0];
9850 var y = a2[1] - a1[1] + o[1];
9852 //constrain the aligned el to viewport if necessary
9853 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
9854 // 5px of margin for ie
9855 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
9857 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
9858 //perpendicular to the vp border, allow the aligned el to slide on that border,
9859 //otherwise swap the aligned el to the opposite border of the target.
9860 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
9861 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
9862 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t") );
9863 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
9866 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
9867 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
9869 if((x+w) > dw + scrollX){
9870 x = swapX ? r.left-w : dw+scrollX-w;
9873 x = swapX ? r.right : scrollX;
9875 if((y+h) > dh + scrollY){
9876 y = swapY ? r.top-h : dh+scrollY-h;
9879 y = swapY ? r.bottom : scrollY;
9886 getConstrainToXY : function(){
9887 var os = {top:0, left:0, bottom:0, right: 0};
9889 return function(el, local, offsets, proposedXY){
9891 offsets = offsets ? Roo.applyIf(offsets, os) : os;
9893 var vw, vh, vx = 0, vy = 0;
9894 if(el.dom == document.body || el.dom == document){
9895 vw = Roo.lib.Dom.getViewWidth();
9896 vh = Roo.lib.Dom.getViewHeight();
9898 vw = el.dom.clientWidth;
9899 vh = el.dom.clientHeight;
9901 var vxy = el.getXY();
9907 var s = el.getScroll();
9909 vx += offsets.left + s.left;
9910 vy += offsets.top + s.top;
9912 vw -= offsets.right;
9913 vh -= offsets.bottom;
9918 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
9919 var x = xy[0], y = xy[1];
9920 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
9922 // only move it if it needs it
9925 // first validate right/bottom
9934 // then make sure top/left isn't negative
9943 return moved ? [x, y] : false;
9948 adjustForConstraints : function(xy, parent, offsets){
9949 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
9953 * Aligns this element with another element relative to the specified anchor points. If the other element is the
9954 * document it aligns it to the viewport.
9955 * The position parameter is optional, and can be specified in any one of the following formats:
9957 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
9958 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
9959 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
9960 * deprecated in favor of the newer two anchor syntax below</i>.</li>
9961 * <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
9962 * element's anchor point, and the second value is used as the target's anchor point.</li>
9964 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
9965 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
9966 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
9967 * that specified in order to enforce the viewport constraints.
9968 * Following are all of the supported anchor positions:
9971 ----- -----------------------------
9972 tl The top left corner (default)
9973 t The center of the top edge
9974 tr The top right corner
9975 l The center of the left edge
9976 c In the center of the element
9977 r The center of the right edge
9978 bl The bottom left corner
9979 b The center of the bottom edge
9980 br The bottom right corner
9984 // align el to other-el using the default positioning ("tl-bl", non-constrained)
9985 el.alignTo("other-el");
9987 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
9988 el.alignTo("other-el", "tr?");
9990 // align the bottom right corner of el with the center left edge of other-el
9991 el.alignTo("other-el", "br-l?");
9993 // align the center of el with the bottom left corner of other-el and
9994 // adjust the x position by -6 pixels (and the y position by 0)
9995 el.alignTo("other-el", "c-bl", [-6, 0]);
9997 * @param {String/HTMLElement/Roo.Element} element The element to align to.
9998 * @param {String} position The position to align to.
9999 * @param {Array} offsets (optional) Offset the positioning by [x, y]
10000 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10001 * @return {Roo.Element} this
10003 alignTo : function(element, position, offsets, animate){
10004 var xy = this.getAlignToXY(element, position, offsets);
10005 this.setXY(xy, this.preanim(arguments, 3));
10010 * Anchors an element to another element and realigns it when the window is resized.
10011 * @param {String/HTMLElement/Roo.Element} element The element to align to.
10012 * @param {String} position The position to align to.
10013 * @param {Array} offsets (optional) Offset the positioning by [x, y]
10014 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
10015 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
10016 * is a number, it is used as the buffer delay (defaults to 50ms).
10017 * @param {Function} callback The function to call after the animation finishes
10018 * @return {Roo.Element} this
10020 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
10021 var action = function(){
10022 this.alignTo(el, alignment, offsets, animate);
10023 Roo.callback(callback, this);
10025 Roo.EventManager.onWindowResize(action, this);
10026 var tm = typeof monitorScroll;
10027 if(tm != 'undefined'){
10028 Roo.EventManager.on(window, 'scroll', action, this,
10029 {buffer: tm == 'number' ? monitorScroll : 50});
10031 action.call(this); // align immediately
10035 * Clears any opacity settings from this element. Required in some cases for IE.
10036 * @return {Roo.Element} this
10038 clearOpacity : function(){
10039 if (window.ActiveXObject) {
10040 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
10041 this.dom.style.filter = "";
10044 this.dom.style.opacity = "";
10045 this.dom.style["-moz-opacity"] = "";
10046 this.dom.style["-khtml-opacity"] = "";
10052 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
10053 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10054 * @return {Roo.Element} this
10056 hide : function(animate){
10057 this.setVisible(false, this.preanim(arguments, 0));
10062 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
10063 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10064 * @return {Roo.Element} this
10066 show : function(animate){
10067 this.setVisible(true, this.preanim(arguments, 0));
10072 * @private Test if size has a unit, otherwise appends the default
10074 addUnits : function(size){
10075 return Roo.Element.addUnits(size, this.defaultUnit);
10079 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
10080 * @return {Roo.Element} this
10082 beginMeasure : function(){
10084 if(el.offsetWidth || el.offsetHeight){
10085 return this; // offsets work already
10088 var p = this.dom, b = document.body; // start with this element
10089 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
10090 var pe = Roo.get(p);
10091 if(pe.getStyle('display') == 'none'){
10092 changed.push({el: p, visibility: pe.getStyle("visibility")});
10093 p.style.visibility = "hidden";
10094 p.style.display = "block";
10098 this._measureChanged = changed;
10104 * Restores displays to before beginMeasure was called
10105 * @return {Roo.Element} this
10107 endMeasure : function(){
10108 var changed = this._measureChanged;
10110 for(var i = 0, len = changed.length; i < len; i++) {
10111 var r = changed[i];
10112 r.el.style.visibility = r.visibility;
10113 r.el.style.display = "none";
10115 this._measureChanged = null;
10121 * Update the innerHTML of this element, optionally searching for and processing scripts
10122 * @param {String} html The new HTML
10123 * @param {Boolean} loadScripts (optional) true to look for and process scripts
10124 * @param {Function} callback For async script loading you can be noticed when the update completes
10125 * @return {Roo.Element} this
10127 update : function(html, loadScripts, callback){
10128 if(typeof html == "undefined"){
10131 if(loadScripts !== true){
10132 this.dom.innerHTML = html;
10133 if(typeof callback == "function"){
10139 var dom = this.dom;
10141 html += '<span id="' + id + '"></span>';
10143 E.onAvailable(id, function(){
10144 var hd = document.getElementsByTagName("head")[0];
10145 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
10146 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
10147 var typeRe = /\stype=([\'\"])(.*?)\1/i;
10150 while(match = re.exec(html)){
10151 var attrs = match[1];
10152 var srcMatch = attrs ? attrs.match(srcRe) : false;
10153 if(srcMatch && srcMatch[2]){
10154 var s = document.createElement("script");
10155 s.src = srcMatch[2];
10156 var typeMatch = attrs.match(typeRe);
10157 if(typeMatch && typeMatch[2]){
10158 s.type = typeMatch[2];
10161 }else if(match[2] && match[2].length > 0){
10162 if(window.execScript) {
10163 window.execScript(match[2]);
10171 window.eval(match[2]);
10175 var el = document.getElementById(id);
10176 if(el){el.parentNode.removeChild(el);}
10177 if(typeof callback == "function"){
10181 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
10186 * Direct access to the UpdateManager update() method (takes the same parameters).
10187 * @param {String/Function} url The url for this request or a function to call to get the url
10188 * @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}
10189 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
10190 * @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.
10191 * @return {Roo.Element} this
10194 var um = this.getUpdateManager();
10195 um.update.apply(um, arguments);
10200 * Gets this element's UpdateManager
10201 * @return {Roo.UpdateManager} The UpdateManager
10203 getUpdateManager : function(){
10204 if(!this.updateManager){
10205 this.updateManager = new Roo.UpdateManager(this);
10207 return this.updateManager;
10211 * Disables text selection for this element (normalized across browsers)
10212 * @return {Roo.Element} this
10214 unselectable : function(){
10215 this.dom.unselectable = "on";
10216 this.swallowEvent("selectstart", true);
10217 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
10218 this.addClass("x-unselectable");
10223 * Calculates the x, y to center this element on the screen
10224 * @return {Array} The x, y values [x, y]
10226 getCenterXY : function(){
10227 return this.getAlignToXY(document, 'c-c');
10231 * Centers the Element in either the viewport, or another Element.
10232 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
10234 center : function(centerIn){
10235 this.alignTo(centerIn || document, 'c-c');
10240 * Tests various css rules/browsers to determine if this element uses a border box
10241 * @return {Boolean}
10243 isBorderBox : function(){
10244 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
10248 * Return a box {x, y, width, height} that can be used to set another elements
10249 * size/location to match this element.
10250 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
10251 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
10252 * @return {Object} box An object in the format {x, y, width, height}
10254 getBox : function(contentBox, local){
10259 var left = parseInt(this.getStyle("left"), 10) || 0;
10260 var top = parseInt(this.getStyle("top"), 10) || 0;
10263 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
10265 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
10267 var l = this.getBorderWidth("l")+this.getPadding("l");
10268 var r = this.getBorderWidth("r")+this.getPadding("r");
10269 var t = this.getBorderWidth("t")+this.getPadding("t");
10270 var b = this.getBorderWidth("b")+this.getPadding("b");
10271 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)};
10273 bx.right = bx.x + bx.width;
10274 bx.bottom = bx.y + bx.height;
10279 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
10280 for more information about the sides.
10281 * @param {String} sides
10284 getFrameWidth : function(sides, onlyContentBox){
10285 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
10289 * 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.
10290 * @param {Object} box The box to fill {x, y, width, height}
10291 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
10292 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10293 * @return {Roo.Element} this
10295 setBox : function(box, adjust, animate){
10296 var w = box.width, h = box.height;
10297 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
10298 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
10299 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
10301 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
10306 * Forces the browser to repaint this element
10307 * @return {Roo.Element} this
10309 repaint : function(){
10310 var dom = this.dom;
10311 this.addClass("x-repaint");
10312 setTimeout(function(){
10313 Roo.get(dom).removeClass("x-repaint");
10319 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
10320 * then it returns the calculated width of the sides (see getPadding)
10321 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
10322 * @return {Object/Number}
10324 getMargins : function(side){
10327 top: parseInt(this.getStyle("margin-top"), 10) || 0,
10328 left: parseInt(this.getStyle("margin-left"), 10) || 0,
10329 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
10330 right: parseInt(this.getStyle("margin-right"), 10) || 0
10333 return this.addStyles(side, El.margins);
10338 addStyles : function(sides, styles){
10340 for(var i = 0, len = sides.length; i < len; i++){
10341 v = this.getStyle(styles[sides.charAt(i)]);
10343 w = parseInt(v, 10);
10351 * Creates a proxy element of this element
10352 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
10353 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
10354 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
10355 * @return {Roo.Element} The new proxy element
10357 createProxy : function(config, renderTo, matchBox){
10359 renderTo = Roo.getDom(renderTo);
10361 renderTo = document.body;
10363 config = typeof config == "object" ?
10364 config : {tag : "div", cls: config};
10365 var proxy = Roo.DomHelper.append(renderTo, config, true);
10367 proxy.setBox(this.getBox());
10373 * Puts a mask over this element to disable user interaction. Requires core.css.
10374 * This method can only be applied to elements which accept child nodes.
10375 * @param {String} msg (optional) A message to display in the mask
10376 * @param {String} msgCls (optional) A css class to apply to the msg element - use no-spinner to hide the spinner on bootstrap
10377 * @return {Element} The mask element
10379 mask : function(msg, msgCls)
10381 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
10382 this.setStyle("position", "relative");
10385 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
10388 this.addClass("x-masked");
10389 this._mask.setDisplayed(true);
10393 var dom = this.dom;
10394 while (dom && dom.style) {
10395 if (!isNaN(parseInt(dom.style.zIndex))) {
10396 z = Math.max(z, parseInt(dom.style.zIndex));
10398 dom = dom.parentNode;
10400 // if we are masking the body - then it hides everything..
10401 if (this.dom == document.body) {
10403 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
10404 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
10407 if(typeof msg == 'string'){
10408 if(!this._maskMsg){
10409 this._maskMsg = Roo.DomHelper.append(this.dom, {
10410 cls: "roo-el-mask-msg",
10414 cls: 'fa fa-spinner fa-spin'
10422 var mm = this._maskMsg;
10423 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
10424 if (mm.dom.lastChild) { // weird IE issue?
10425 mm.dom.lastChild.innerHTML = msg;
10427 mm.setDisplayed(true);
10429 mm.setStyle('z-index', z + 102);
10431 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
10432 this._mask.setHeight(this.getHeight());
10434 this._mask.setStyle('z-index', z + 100);
10440 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
10441 * it is cached for reuse.
10443 unmask : function(removeEl){
10445 if(removeEl === true){
10446 this._mask.remove();
10449 this._maskMsg.remove();
10450 delete this._maskMsg;
10453 this._mask.setDisplayed(false);
10455 this._maskMsg.setDisplayed(false);
10459 this.removeClass("x-masked");
10463 * Returns true if this element is masked
10464 * @return {Boolean}
10466 isMasked : function(){
10467 return this._mask && this._mask.isVisible();
10471 * Creates an iframe shim for this element to keep selects and other windowed objects from
10473 * @return {Roo.Element} The new shim element
10475 createShim : function(){
10476 var el = document.createElement('iframe');
10477 el.frameBorder = 'no';
10478 el.className = 'roo-shim';
10479 if(Roo.isIE && Roo.isSecure){
10480 el.src = Roo.SSL_SECURE_URL;
10482 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
10483 shim.autoBoxAdjust = false;
10488 * Removes this element from the DOM and deletes it from the cache
10490 remove : function(){
10491 if(this.dom.parentNode){
10492 this.dom.parentNode.removeChild(this.dom);
10494 delete El.cache[this.dom.id];
10498 * Sets up event handlers to add and remove a css class when the mouse is over this element
10499 * @param {String} className
10500 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
10501 * mouseout events for children elements
10502 * @return {Roo.Element} this
10504 addClassOnOver : function(className, preventFlicker){
10505 this.on("mouseover", function(){
10506 Roo.fly(this, '_internal').addClass(className);
10508 var removeFn = function(e){
10509 if(preventFlicker !== true || !e.within(this, true)){
10510 Roo.fly(this, '_internal').removeClass(className);
10513 this.on("mouseout", removeFn, this.dom);
10518 * Sets up event handlers to add and remove a css class when this element has the focus
10519 * @param {String} className
10520 * @return {Roo.Element} this
10522 addClassOnFocus : function(className){
10523 this.on("focus", function(){
10524 Roo.fly(this, '_internal').addClass(className);
10526 this.on("blur", function(){
10527 Roo.fly(this, '_internal').removeClass(className);
10532 * 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)
10533 * @param {String} className
10534 * @return {Roo.Element} this
10536 addClassOnClick : function(className){
10537 var dom = this.dom;
10538 this.on("mousedown", function(){
10539 Roo.fly(dom, '_internal').addClass(className);
10540 var d = Roo.get(document);
10541 var fn = function(){
10542 Roo.fly(dom, '_internal').removeClass(className);
10543 d.removeListener("mouseup", fn);
10545 d.on("mouseup", fn);
10551 * Stops the specified event from bubbling and optionally prevents the default action
10552 * @param {String} eventName
10553 * @param {Boolean} preventDefault (optional) true to prevent the default action too
10554 * @return {Roo.Element} this
10556 swallowEvent : function(eventName, preventDefault){
10557 var fn = function(e){
10558 e.stopPropagation();
10559 if(preventDefault){
10560 e.preventDefault();
10563 if(eventName instanceof Array){
10564 for(var i = 0, len = eventName.length; i < len; i++){
10565 this.on(eventName[i], fn);
10569 this.on(eventName, fn);
10576 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
10579 * Sizes this element to its parent element's dimensions performing
10580 * neccessary box adjustments.
10581 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
10582 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
10583 * @return {Roo.Element} this
10585 fitToParent : function(monitorResize, targetParent) {
10586 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
10587 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
10588 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
10591 var p = Roo.get(targetParent || this.dom.parentNode);
10592 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
10593 if (monitorResize === true) {
10594 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
10595 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
10601 * Gets the next sibling, skipping text nodes
10602 * @return {HTMLElement} The next sibling or null
10604 getNextSibling : function(){
10605 var n = this.dom.nextSibling;
10606 while(n && n.nodeType != 1){
10613 * Gets the previous sibling, skipping text nodes
10614 * @return {HTMLElement} The previous sibling or null
10616 getPrevSibling : function(){
10617 var n = this.dom.previousSibling;
10618 while(n && n.nodeType != 1){
10619 n = n.previousSibling;
10626 * Appends the passed element(s) to this element
10627 * @param {String/HTMLElement/Array/Element/CompositeElement} el
10628 * @return {Roo.Element} this
10630 appendChild: function(el){
10637 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
10638 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
10639 * automatically generated with the specified attributes.
10640 * @param {HTMLElement} insertBefore (optional) a child element of this element
10641 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
10642 * @return {Roo.Element} The new child element
10644 createChild: function(config, insertBefore, returnDom){
10645 config = config || {tag:'div'};
10647 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
10649 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
10653 * Appends this element to the passed element
10654 * @param {String/HTMLElement/Element} el The new parent element
10655 * @return {Roo.Element} this
10657 appendTo: function(el){
10658 el = Roo.getDom(el);
10659 el.appendChild(this.dom);
10664 * Inserts this element before the passed element in the DOM
10665 * @param {String/HTMLElement/Element} el The element to insert before
10666 * @return {Roo.Element} this
10668 insertBefore: function(el){
10669 el = Roo.getDom(el);
10670 el.parentNode.insertBefore(this.dom, el);
10675 * Inserts this element after the passed element in the DOM
10676 * @param {String/HTMLElement/Element} el The element to insert after
10677 * @return {Roo.Element} this
10679 insertAfter: function(el){
10680 el = Roo.getDom(el);
10681 el.parentNode.insertBefore(this.dom, el.nextSibling);
10686 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
10687 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10688 * @return {Roo.Element} The new child
10690 insertFirst: function(el, returnDom){
10692 if(typeof el == 'object' && !el.nodeType){ // dh config
10693 return this.createChild(el, this.dom.firstChild, returnDom);
10695 el = Roo.getDom(el);
10696 this.dom.insertBefore(el, this.dom.firstChild);
10697 return !returnDom ? Roo.get(el) : el;
10702 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
10703 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10704 * @param {String} where (optional) 'before' or 'after' defaults to before
10705 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10706 * @return {Roo.Element} the inserted Element
10708 insertSibling: function(el, where, returnDom){
10709 where = where ? where.toLowerCase() : 'before';
10711 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
10713 if(typeof el == 'object' && !el.nodeType){ // dh config
10714 if(where == 'after' && !this.dom.nextSibling){
10715 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
10717 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
10721 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
10722 where == 'before' ? this.dom : this.dom.nextSibling);
10731 * Creates and wraps this element with another element
10732 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
10733 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10734 * @return {HTMLElement/Element} The newly created wrapper element
10736 wrap: function(config, returnDom){
10738 config = {tag: "div"};
10740 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
10741 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
10746 * Replaces the passed element with this element
10747 * @param {String/HTMLElement/Element} el The element to replace
10748 * @return {Roo.Element} this
10750 replace: function(el){
10752 this.insertBefore(el);
10758 * Inserts an html fragment into this element
10759 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
10760 * @param {String} html The HTML fragment
10761 * @param {Boolean} returnEl True to return an Roo.Element
10762 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
10764 insertHtml : function(where, html, returnEl){
10765 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
10766 return returnEl ? Roo.get(el) : el;
10770 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
10771 * @param {Object} o The object with the attributes
10772 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
10773 * @return {Roo.Element} this
10775 set : function(o, useSet){
10777 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
10778 for(var attr in o){
10779 if(attr == "style" || typeof o[attr] == "function") { continue; }
10781 el.className = o["cls"];
10784 el.setAttribute(attr, o[attr]);
10786 el[attr] = o[attr];
10791 Roo.DomHelper.applyStyles(el, o.style);
10797 * Convenience method for constructing a KeyMap
10798 * @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:
10799 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
10800 * @param {Function} fn The function to call
10801 * @param {Object} scope (optional) The scope of the function
10802 * @return {Roo.KeyMap} The KeyMap created
10804 addKeyListener : function(key, fn, scope){
10806 if(typeof key != "object" || key instanceof Array){
10822 return new Roo.KeyMap(this, config);
10826 * Creates a KeyMap for this element
10827 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
10828 * @return {Roo.KeyMap} The KeyMap created
10830 addKeyMap : function(config){
10831 return new Roo.KeyMap(this, config);
10835 * Returns true if this element is scrollable.
10836 * @return {Boolean}
10838 isScrollable : function(){
10839 var dom = this.dom;
10840 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
10844 * 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().
10845 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
10846 * @param {Number} value The new scroll value
10847 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10848 * @return {Element} this
10851 scrollTo : function(side, value, animate){
10852 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
10853 if(!animate || !A){
10854 this.dom[prop] = value;
10856 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
10857 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
10863 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
10864 * within this element's scrollable range.
10865 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
10866 * @param {Number} distance How far to scroll the element in pixels
10867 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10868 * @return {Boolean} Returns true if a scroll was triggered or false if the element
10869 * was scrolled as far as it could go.
10871 scroll : function(direction, distance, animate){
10872 if(!this.isScrollable()){
10876 var l = el.scrollLeft, t = el.scrollTop;
10877 var w = el.scrollWidth, h = el.scrollHeight;
10878 var cw = el.clientWidth, ch = el.clientHeight;
10879 direction = direction.toLowerCase();
10880 var scrolled = false;
10881 var a = this.preanim(arguments, 2);
10886 var v = Math.min(l + distance, w-cw);
10887 this.scrollTo("left", v, a);
10894 var v = Math.max(l - distance, 0);
10895 this.scrollTo("left", v, a);
10903 var v = Math.max(t - distance, 0);
10904 this.scrollTo("top", v, a);
10912 var v = Math.min(t + distance, h-ch);
10913 this.scrollTo("top", v, a);
10922 * Translates the passed page coordinates into left/top css values for this element
10923 * @param {Number/Array} x The page x or an array containing [x, y]
10924 * @param {Number} y The page y
10925 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
10927 translatePoints : function(x, y){
10928 if(typeof x == 'object' || x instanceof Array){
10929 y = x[1]; x = x[0];
10931 var p = this.getStyle('position');
10932 var o = this.getXY();
10934 var l = parseInt(this.getStyle('left'), 10);
10935 var t = parseInt(this.getStyle('top'), 10);
10938 l = (p == "relative") ? 0 : this.dom.offsetLeft;
10941 t = (p == "relative") ? 0 : this.dom.offsetTop;
10944 return {left: (x - o[0] + l), top: (y - o[1] + t)};
10948 * Returns the current scroll position of the element.
10949 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
10951 getScroll : function(){
10952 var d = this.dom, doc = document;
10953 if(d == doc || d == doc.body){
10954 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
10955 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
10956 return {left: l, top: t};
10958 return {left: d.scrollLeft, top: d.scrollTop};
10963 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
10964 * are convert to standard 6 digit hex color.
10965 * @param {String} attr The css attribute
10966 * @param {String} defaultValue The default value to use when a valid color isn't found
10967 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
10970 getColor : function(attr, defaultValue, prefix){
10971 var v = this.getStyle(attr);
10972 if(!v || v == "transparent" || v == "inherit") {
10973 return defaultValue;
10975 var color = typeof prefix == "undefined" ? "#" : prefix;
10976 if(v.substr(0, 4) == "rgb("){
10977 var rvs = v.slice(4, v.length -1).split(",");
10978 for(var i = 0; i < 3; i++){
10979 var h = parseInt(rvs[i]).toString(16);
10986 if(v.substr(0, 1) == "#"){
10987 if(v.length == 4) {
10988 for(var i = 1; i < 4; i++){
10989 var c = v.charAt(i);
10992 }else if(v.length == 7){
10993 color += v.substr(1);
10997 return(color.length > 5 ? color.toLowerCase() : defaultValue);
11001 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
11002 * gradient background, rounded corners and a 4-way shadow.
11003 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
11004 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
11005 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
11006 * @return {Roo.Element} this
11008 boxWrap : function(cls){
11009 cls = cls || 'x-box';
11010 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
11011 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
11016 * Returns the value of a namespaced attribute from the element's underlying DOM node.
11017 * @param {String} namespace The namespace in which to look for the attribute
11018 * @param {String} name The attribute name
11019 * @return {String} The attribute value
11021 getAttributeNS : Roo.isIE ? function(ns, name){
11023 var type = typeof d[ns+":"+name];
11024 if(type != 'undefined' && type != 'unknown'){
11025 return d[ns+":"+name];
11028 } : function(ns, name){
11030 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
11035 * Sets or Returns the value the dom attribute value
11036 * @param {String|Object} name The attribute name (or object to set multiple attributes)
11037 * @param {String} value (optional) The value to set the attribute to
11038 * @return {String} The attribute value
11040 attr : function(name){
11041 if (arguments.length > 1) {
11042 this.dom.setAttribute(name, arguments[1]);
11043 return arguments[1];
11045 if (typeof(name) == 'object') {
11046 for(var i in name) {
11047 this.attr(i, name[i]);
11053 if (!this.dom.hasAttribute(name)) {
11056 return this.dom.getAttribute(name);
11063 var ep = El.prototype;
11066 * Appends an event handler (Shorthand for addListener)
11067 * @param {String} eventName The type of event to append
11068 * @param {Function} fn The method the event invokes
11069 * @param {Object} scope (optional) The scope (this object) of the fn
11070 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
11073 ep.on = ep.addListener;
11074 // backwards compat
11075 ep.mon = ep.addListener;
11078 * Removes an event handler from this element (shorthand for removeListener)
11079 * @param {String} eventName the type of event to remove
11080 * @param {Function} fn the method the event invokes
11081 * @return {Roo.Element} this
11084 ep.un = ep.removeListener;
11087 * true to automatically adjust width and height settings for box-model issues (default to true)
11089 ep.autoBoxAdjust = true;
11092 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
11095 El.addUnits = function(v, defaultUnit){
11096 if(v === "" || v == "auto"){
11099 if(v === undefined){
11102 if(typeof v == "number" || !El.unitPattern.test(v)){
11103 return v + (defaultUnit || 'px');
11108 // special markup used throughout Roo when box wrapping elements
11109 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>';
11111 * Visibility mode constant - Use visibility to hide element
11117 * Visibility mode constant - Use display to hide element
11123 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
11124 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
11125 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
11137 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
11138 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
11139 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
11140 * @return {Element} The Element object
11143 El.get = function(el){
11145 if(!el){ return null; }
11146 if(typeof el == "string"){ // element id
11147 if(!(elm = document.getElementById(el))){
11150 if(ex = El.cache[el]){
11153 ex = El.cache[el] = new El(elm);
11156 }else if(el.tagName){ // dom element
11160 if(ex = El.cache[id]){
11163 ex = El.cache[id] = new El(el);
11166 }else if(el instanceof El){
11168 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
11169 // catch case where it hasn't been appended
11170 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
11173 }else if(el.isComposite){
11175 }else if(el instanceof Array){
11176 return El.select(el);
11177 }else if(el == document){
11178 // create a bogus element object representing the document object
11180 var f = function(){};
11181 f.prototype = El.prototype;
11183 docEl.dom = document;
11191 El.uncache = function(el){
11192 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
11194 delete El.cache[a[i].id || a[i]];
11200 // Garbage collection - uncache elements/purge listeners on orphaned elements
11201 // so we don't hold a reference and cause the browser to retain them
11202 El.garbageCollect = function(){
11203 if(!Roo.enableGarbageCollector){
11204 clearInterval(El.collectorThread);
11207 for(var eid in El.cache){
11208 var el = El.cache[eid], d = el.dom;
11209 // -------------------------------------------------------
11210 // Determining what is garbage:
11211 // -------------------------------------------------------
11213 // dom node is null, definitely garbage
11214 // -------------------------------------------------------
11216 // no parentNode == direct orphan, definitely garbage
11217 // -------------------------------------------------------
11218 // !d.offsetParent && !document.getElementById(eid)
11219 // display none elements have no offsetParent so we will
11220 // also try to look it up by it's id. However, check
11221 // offsetParent first so we don't do unneeded lookups.
11222 // This enables collection of elements that are not orphans
11223 // directly, but somewhere up the line they have an orphan
11225 // -------------------------------------------------------
11226 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
11227 delete El.cache[eid];
11228 if(d && Roo.enableListenerCollection){
11234 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
11238 El.Flyweight = function(dom){
11241 El.Flyweight.prototype = El.prototype;
11243 El._flyweights = {};
11245 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
11246 * the dom node can be overwritten by other code.
11247 * @param {String/HTMLElement} el The dom node or id
11248 * @param {String} named (optional) Allows for creation of named reusable flyweights to
11249 * prevent conflicts (e.g. internally Roo uses "_internal")
11251 * @return {Element} The shared Element object
11253 El.fly = function(el, named){
11254 named = named || '_global';
11255 el = Roo.getDom(el);
11259 if(!El._flyweights[named]){
11260 El._flyweights[named] = new El.Flyweight();
11262 El._flyweights[named].dom = el;
11263 return El._flyweights[named];
11267 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
11268 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
11269 * Shorthand of {@link Roo.Element#get}
11270 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
11271 * @return {Element} The Element object
11277 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
11278 * the dom node can be overwritten by other code.
11279 * Shorthand of {@link Roo.Element#fly}
11280 * @param {String/HTMLElement} el The dom node or id
11281 * @param {String} named (optional) Allows for creation of named reusable flyweights to
11282 * prevent conflicts (e.g. internally Roo uses "_internal")
11284 * @return {Element} The shared Element object
11290 // speedy lookup for elements never to box adjust
11291 var noBoxAdjust = Roo.isStrict ? {
11294 input:1, select:1, textarea:1
11296 if(Roo.isIE || Roo.isGecko){
11297 noBoxAdjust['button'] = 1;
11301 Roo.EventManager.on(window, 'unload', function(){
11303 delete El._flyweights;
11311 Roo.Element.selectorFunction = Roo.DomQuery.select;
11314 Roo.Element.select = function(selector, unique, root){
11316 if(typeof selector == "string"){
11317 els = Roo.Element.selectorFunction(selector, root);
11318 }else if(selector.length !== undefined){
11321 throw "Invalid selector";
11323 if(unique === true){
11324 return new Roo.CompositeElement(els);
11326 return new Roo.CompositeElementLite(els);
11330 * Selects elements based on the passed CSS selector to enable working on them as 1.
11331 * @param {String/Array} selector The CSS selector or an array of elements
11332 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
11333 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
11334 * @return {CompositeElementLite/CompositeElement}
11338 Roo.select = Roo.Element.select;
11355 * Ext JS Library 1.1.1
11356 * Copyright(c) 2006-2007, Ext JS, LLC.
11358 * Originally Released Under LGPL - original licence link has changed is not relivant.
11361 * <script type="text/javascript">
11366 //Notifies Element that fx methods are available
11367 Roo.enableFx = true;
11371 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
11372 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
11373 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
11374 * Element effects to work.</p><br/>
11376 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
11377 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
11378 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
11379 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
11380 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
11381 * expected results and should be done with care.</p><br/>
11383 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
11384 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
11387 ----- -----------------------------
11388 tl The top left corner
11389 t The center of the top edge
11390 tr The top right corner
11391 l The center of the left edge
11392 r The center of the right edge
11393 bl The bottom left corner
11394 b The center of the bottom edge
11395 br The bottom right corner
11397 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
11398 * below are common options that can be passed to any Fx method.</b>
11399 * @cfg {Function} callback A function called when the effect is finished
11400 * @cfg {Object} scope The scope of the effect function
11401 * @cfg {String} easing A valid Easing value for the effect
11402 * @cfg {String} afterCls A css class to apply after the effect
11403 * @cfg {Number} duration The length of time (in seconds) that the effect should last
11404 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
11405 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
11406 * effects that end with the element being visually hidden, ignored otherwise)
11407 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
11408 * a function which returns such a specification that will be applied to the Element after the effect finishes
11409 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
11410 * @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
11411 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
11415 * Slides the element into view. An anchor point can be optionally passed to set the point of
11416 * origin for the slide effect. This function automatically handles wrapping the element with
11417 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
11420 // default: slide the element in from the top
11423 // custom: slide the element in from the right with a 2-second duration
11424 el.slideIn('r', { duration: 2 });
11426 // common config options shown with default values
11432 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11433 * @param {Object} options (optional) Object literal with any of the Fx config options
11434 * @return {Roo.Element} The Element
11436 slideIn : function(anchor, o){
11437 var el = this.getFxEl();
11440 el.queueFx(o, function(){
11442 anchor = anchor || "t";
11444 // fix display to visibility
11447 // restore values after effect
11448 var r = this.getFxRestore();
11449 var b = this.getBox();
11450 // fixed size for slide
11454 var wrap = this.fxWrap(r.pos, o, "hidden");
11456 var st = this.dom.style;
11457 st.visibility = "visible";
11458 st.position = "absolute";
11460 // clear out temp styles after slide and unwrap
11461 var after = function(){
11462 el.fxUnwrap(wrap, r.pos, o);
11463 st.width = r.width;
11464 st.height = r.height;
11467 // time to calc the positions
11468 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
11470 switch(anchor.toLowerCase()){
11472 wrap.setSize(b.width, 0);
11473 st.left = st.bottom = "0";
11477 wrap.setSize(0, b.height);
11478 st.right = st.top = "0";
11482 wrap.setSize(0, b.height);
11483 wrap.setX(b.right);
11484 st.left = st.top = "0";
11485 a = {width: bw, points: pt};
11488 wrap.setSize(b.width, 0);
11489 wrap.setY(b.bottom);
11490 st.left = st.top = "0";
11491 a = {height: bh, points: pt};
11494 wrap.setSize(0, 0);
11495 st.right = st.bottom = "0";
11496 a = {width: bw, height: bh};
11499 wrap.setSize(0, 0);
11500 wrap.setY(b.y+b.height);
11501 st.right = st.top = "0";
11502 a = {width: bw, height: bh, points: pt};
11505 wrap.setSize(0, 0);
11506 wrap.setXY([b.right, b.bottom]);
11507 st.left = st.top = "0";
11508 a = {width: bw, height: bh, points: pt};
11511 wrap.setSize(0, 0);
11512 wrap.setX(b.x+b.width);
11513 st.left = st.bottom = "0";
11514 a = {width: bw, height: bh, points: pt};
11517 this.dom.style.visibility = "visible";
11520 arguments.callee.anim = wrap.fxanim(a,
11530 * Slides the element out of view. An anchor point can be optionally passed to set the end point
11531 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
11532 * 'hidden') but block elements will still take up space in the document. The element must be removed
11533 * from the DOM using the 'remove' config option if desired. This function automatically handles
11534 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
11537 // default: slide the element out to the top
11540 // custom: slide the element out to the right with a 2-second duration
11541 el.slideOut('r', { duration: 2 });
11543 // common config options shown with default values
11551 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11552 * @param {Object} options (optional) Object literal with any of the Fx config options
11553 * @return {Roo.Element} The Element
11555 slideOut : function(anchor, o){
11556 var el = this.getFxEl();
11559 el.queueFx(o, function(){
11561 anchor = anchor || "t";
11563 // restore values after effect
11564 var r = this.getFxRestore();
11566 var b = this.getBox();
11567 // fixed size for slide
11571 var wrap = this.fxWrap(r.pos, o, "visible");
11573 var st = this.dom.style;
11574 st.visibility = "visible";
11575 st.position = "absolute";
11579 var after = function(){
11581 el.setDisplayed(false);
11586 el.fxUnwrap(wrap, r.pos, o);
11588 st.width = r.width;
11589 st.height = r.height;
11594 var a, zero = {to: 0};
11595 switch(anchor.toLowerCase()){
11597 st.left = st.bottom = "0";
11598 a = {height: zero};
11601 st.right = st.top = "0";
11605 st.left = st.top = "0";
11606 a = {width: zero, points: {to:[b.right, b.y]}};
11609 st.left = st.top = "0";
11610 a = {height: zero, points: {to:[b.x, b.bottom]}};
11613 st.right = st.bottom = "0";
11614 a = {width: zero, height: zero};
11617 st.right = st.top = "0";
11618 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
11621 st.left = st.top = "0";
11622 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
11625 st.left = st.bottom = "0";
11626 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
11630 arguments.callee.anim = wrap.fxanim(a,
11640 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
11641 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
11642 * The element must be removed from the DOM using the 'remove' config option if desired.
11648 // common config options shown with default values
11656 * @param {Object} options (optional) Object literal with any of the Fx config options
11657 * @return {Roo.Element} The Element
11659 puff : function(o){
11660 var el = this.getFxEl();
11663 el.queueFx(o, function(){
11664 this.clearOpacity();
11667 // restore values after effect
11668 var r = this.getFxRestore();
11669 var st = this.dom.style;
11671 var after = function(){
11673 el.setDisplayed(false);
11680 el.setPositioning(r.pos);
11681 st.width = r.width;
11682 st.height = r.height;
11687 var width = this.getWidth();
11688 var height = this.getHeight();
11690 arguments.callee.anim = this.fxanim({
11691 width : {to: this.adjustWidth(width * 2)},
11692 height : {to: this.adjustHeight(height * 2)},
11693 points : {by: [-(width * .5), -(height * .5)]},
11695 fontSize: {to:200, unit: "%"}
11706 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
11707 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
11708 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
11714 // all config options shown with default values
11722 * @param {Object} options (optional) Object literal with any of the Fx config options
11723 * @return {Roo.Element} The Element
11725 switchOff : function(o){
11726 var el = this.getFxEl();
11729 el.queueFx(o, function(){
11730 this.clearOpacity();
11733 // restore values after effect
11734 var r = this.getFxRestore();
11735 var st = this.dom.style;
11737 var after = function(){
11739 el.setDisplayed(false);
11745 el.setPositioning(r.pos);
11746 st.width = r.width;
11747 st.height = r.height;
11752 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
11753 this.clearOpacity();
11757 points:{by:[0, this.getHeight() * .5]}
11758 }, o, 'motion', 0.3, 'easeIn', after);
11759 }).defer(100, this);
11766 * Highlights the Element by setting a color (applies to the background-color by default, but can be
11767 * changed using the "attr" config option) and then fading back to the original color. If no original
11768 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
11771 // default: highlight background to yellow
11774 // custom: highlight foreground text to blue for 2 seconds
11775 el.highlight("0000ff", { attr: 'color', duration: 2 });
11777 // common config options shown with default values
11778 el.highlight("ffff9c", {
11779 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
11780 endColor: (current color) or "ffffff",
11785 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
11786 * @param {Object} options (optional) Object literal with any of the Fx config options
11787 * @return {Roo.Element} The Element
11789 highlight : function(color, o){
11790 var el = this.getFxEl();
11793 el.queueFx(o, function(){
11794 color = color || "ffff9c";
11795 attr = o.attr || "backgroundColor";
11797 this.clearOpacity();
11800 var origColor = this.getColor(attr);
11801 var restoreColor = this.dom.style[attr];
11802 endColor = (o.endColor || origColor) || "ffffff";
11804 var after = function(){
11805 el.dom.style[attr] = restoreColor;
11810 a[attr] = {from: color, to: endColor};
11811 arguments.callee.anim = this.fxanim(a,
11821 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
11824 // default: a single light blue ripple
11827 // custom: 3 red ripples lasting 3 seconds total
11828 el.frame("ff0000", 3, { duration: 3 });
11830 // common config options shown with default values
11831 el.frame("C3DAF9", 1, {
11832 duration: 1 //duration of entire animation (not each individual ripple)
11833 // Note: Easing is not configurable and will be ignored if included
11836 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
11837 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
11838 * @param {Object} options (optional) Object literal with any of the Fx config options
11839 * @return {Roo.Element} The Element
11841 frame : function(color, count, o){
11842 var el = this.getFxEl();
11845 el.queueFx(o, function(){
11846 color = color || "#C3DAF9";
11847 if(color.length == 6){
11848 color = "#" + color;
11850 count = count || 1;
11851 duration = o.duration || 1;
11854 var b = this.getBox();
11855 var animFn = function(){
11856 var proxy = this.createProxy({
11859 visbility:"hidden",
11860 position:"absolute",
11861 "z-index":"35000", // yee haw
11862 border:"0px solid " + color
11865 var scale = Roo.isBorderBox ? 2 : 1;
11867 top:{from:b.y, to:b.y - 20},
11868 left:{from:b.x, to:b.x - 20},
11869 borderWidth:{from:0, to:10},
11870 opacity:{from:1, to:0},
11871 height:{from:b.height, to:(b.height + (20*scale))},
11872 width:{from:b.width, to:(b.width + (20*scale))}
11873 }, duration, function(){
11877 animFn.defer((duration/2)*1000, this);
11888 * Creates a pause before any subsequent queued effects begin. If there are
11889 * no effects queued after the pause it will have no effect.
11894 * @param {Number} seconds The length of time to pause (in seconds)
11895 * @return {Roo.Element} The Element
11897 pause : function(seconds){
11898 var el = this.getFxEl();
11901 el.queueFx(o, function(){
11902 setTimeout(function(){
11904 }, seconds * 1000);
11910 * Fade an element in (from transparent to opaque). The ending opacity can be specified
11911 * using the "endOpacity" config option.
11914 // default: fade in from opacity 0 to 100%
11917 // custom: fade in from opacity 0 to 75% over 2 seconds
11918 el.fadeIn({ endOpacity: .75, duration: 2});
11920 // common config options shown with default values
11922 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
11927 * @param {Object} options (optional) Object literal with any of the Fx config options
11928 * @return {Roo.Element} The Element
11930 fadeIn : function(o){
11931 var el = this.getFxEl();
11933 el.queueFx(o, function(){
11934 this.setOpacity(0);
11936 this.dom.style.visibility = 'visible';
11937 var to = o.endOpacity || 1;
11938 arguments.callee.anim = this.fxanim({opacity:{to:to}},
11939 o, null, .5, "easeOut", function(){
11941 this.clearOpacity();
11950 * Fade an element out (from opaque to transparent). The ending opacity can be specified
11951 * using the "endOpacity" config option.
11954 // default: fade out from the element's current opacity to 0
11957 // custom: fade out from the element's current opacity to 25% over 2 seconds
11958 el.fadeOut({ endOpacity: .25, duration: 2});
11960 // common config options shown with default values
11962 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
11969 * @param {Object} options (optional) Object literal with any of the Fx config options
11970 * @return {Roo.Element} The Element
11972 fadeOut : function(o){
11973 var el = this.getFxEl();
11975 el.queueFx(o, function(){
11976 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
11977 o, null, .5, "easeOut", function(){
11978 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
11979 this.dom.style.display = "none";
11981 this.dom.style.visibility = "hidden";
11983 this.clearOpacity();
11991 * Animates the transition of an element's dimensions from a starting height/width
11992 * to an ending height/width.
11995 // change height and width to 100x100 pixels
11996 el.scale(100, 100);
11998 // common config options shown with default values. The height and width will default to
11999 // the element's existing values if passed as null.
12002 [element's height], {
12007 * @param {Number} width The new width (pass undefined to keep the original width)
12008 * @param {Number} height The new height (pass undefined to keep the original height)
12009 * @param {Object} options (optional) Object literal with any of the Fx config options
12010 * @return {Roo.Element} The Element
12012 scale : function(w, h, o){
12013 this.shift(Roo.apply({}, o, {
12021 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
12022 * Any of these properties not specified in the config object will not be changed. This effect
12023 * requires that at least one new dimension, position or opacity setting must be passed in on
12024 * the config object in order for the function to have any effect.
12027 // slide the element horizontally to x position 200 while changing the height and opacity
12028 el.shift({ x: 200, height: 50, opacity: .8 });
12030 // common config options shown with default values.
12032 width: [element's width],
12033 height: [element's height],
12034 x: [element's x position],
12035 y: [element's y position],
12036 opacity: [element's opacity],
12041 * @param {Object} options Object literal with any of the Fx config options
12042 * @return {Roo.Element} The Element
12044 shift : function(o){
12045 var el = this.getFxEl();
12047 el.queueFx(o, function(){
12048 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
12049 if(w !== undefined){
12050 a.width = {to: this.adjustWidth(w)};
12052 if(h !== undefined){
12053 a.height = {to: this.adjustHeight(h)};
12055 if(x !== undefined || y !== undefined){
12057 x !== undefined ? x : this.getX(),
12058 y !== undefined ? y : this.getY()
12061 if(op !== undefined){
12062 a.opacity = {to: op};
12064 if(o.xy !== undefined){
12065 a.points = {to: o.xy};
12067 arguments.callee.anim = this.fxanim(a,
12068 o, 'motion', .35, "easeOut", function(){
12076 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
12077 * ending point of the effect.
12080 // default: slide the element downward while fading out
12083 // custom: slide the element out to the right with a 2-second duration
12084 el.ghost('r', { duration: 2 });
12086 // common config options shown with default values
12094 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
12095 * @param {Object} options (optional) Object literal with any of the Fx config options
12096 * @return {Roo.Element} The Element
12098 ghost : function(anchor, o){
12099 var el = this.getFxEl();
12102 el.queueFx(o, function(){
12103 anchor = anchor || "b";
12105 // restore values after effect
12106 var r = this.getFxRestore();
12107 var w = this.getWidth(),
12108 h = this.getHeight();
12110 var st = this.dom.style;
12112 var after = function(){
12114 el.setDisplayed(false);
12120 el.setPositioning(r.pos);
12121 st.width = r.width;
12122 st.height = r.height;
12127 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
12128 switch(anchor.toLowerCase()){
12155 arguments.callee.anim = this.fxanim(a,
12165 * Ensures that all effects queued after syncFx is called on the element are
12166 * run concurrently. This is the opposite of {@link #sequenceFx}.
12167 * @return {Roo.Element} The Element
12169 syncFx : function(){
12170 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
12179 * Ensures that all effects queued after sequenceFx is called on the element are
12180 * run in sequence. This is the opposite of {@link #syncFx}.
12181 * @return {Roo.Element} The Element
12183 sequenceFx : function(){
12184 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
12186 concurrent : false,
12193 nextFx : function(){
12194 var ef = this.fxQueue[0];
12201 * Returns true if the element has any effects actively running or queued, else returns false.
12202 * @return {Boolean} True if element has active effects, else false
12204 hasActiveFx : function(){
12205 return this.fxQueue && this.fxQueue[0];
12209 * Stops any running effects and clears the element's internal effects queue if it contains
12210 * any additional effects that haven't started yet.
12211 * @return {Roo.Element} The Element
12213 stopFx : function(){
12214 if(this.hasActiveFx()){
12215 var cur = this.fxQueue[0];
12216 if(cur && cur.anim && cur.anim.isAnimated()){
12217 this.fxQueue = [cur]; // clear out others
12218 cur.anim.stop(true);
12225 beforeFx : function(o){
12226 if(this.hasActiveFx() && !o.concurrent){
12237 * Returns true if the element is currently blocking so that no other effect can be queued
12238 * until this effect is finished, else returns false if blocking is not set. This is commonly
12239 * used to ensure that an effect initiated by a user action runs to completion prior to the
12240 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
12241 * @return {Boolean} True if blocking, else false
12243 hasFxBlock : function(){
12244 var q = this.fxQueue;
12245 return q && q[0] && q[0].block;
12249 queueFx : function(o, fn){
12253 if(!this.hasFxBlock()){
12254 Roo.applyIf(o, this.fxDefaults);
12256 var run = this.beforeFx(o);
12257 fn.block = o.block;
12258 this.fxQueue.push(fn);
12270 fxWrap : function(pos, o, vis){
12272 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
12275 wrapXY = this.getXY();
12277 var div = document.createElement("div");
12278 div.style.visibility = vis;
12279 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
12280 wrap.setPositioning(pos);
12281 if(wrap.getStyle("position") == "static"){
12282 wrap.position("relative");
12284 this.clearPositioning('auto');
12286 wrap.dom.appendChild(this.dom);
12288 wrap.setXY(wrapXY);
12295 fxUnwrap : function(wrap, pos, o){
12296 this.clearPositioning();
12297 this.setPositioning(pos);
12299 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
12305 getFxRestore : function(){
12306 var st = this.dom.style;
12307 return {pos: this.getPositioning(), width: st.width, height : st.height};
12311 afterFx : function(o){
12313 this.applyStyles(o.afterStyle);
12316 this.addClass(o.afterCls);
12318 if(o.remove === true){
12321 Roo.callback(o.callback, o.scope, [this]);
12323 this.fxQueue.shift();
12329 getFxEl : function(){ // support for composite element fx
12330 return Roo.get(this.dom);
12334 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
12335 animType = animType || 'run';
12337 var anim = Roo.lib.Anim[animType](
12339 (opt.duration || defaultDur) || .35,
12340 (opt.easing || defaultEase) || 'easeOut',
12342 Roo.callback(cb, this);
12351 // backwords compat
12352 Roo.Fx.resize = Roo.Fx.scale;
12354 //When included, Roo.Fx is automatically applied to Element so that all basic
12355 //effects are available directly via the Element API
12356 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
12358 * Ext JS Library 1.1.1
12359 * Copyright(c) 2006-2007, Ext JS, LLC.
12361 * Originally Released Under LGPL - original licence link has changed is not relivant.
12364 * <script type="text/javascript">
12369 * @class Roo.CompositeElement
12370 * Standard composite class. Creates a Roo.Element for every element in the collection.
12372 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12373 * actions will be performed on all the elements in this collection.</b>
12375 * All methods return <i>this</i> and can be chained.
12377 var els = Roo.select("#some-el div.some-class", true);
12378 // or select directly from an existing element
12379 var el = Roo.get('some-el');
12380 el.select('div.some-class', true);
12382 els.setWidth(100); // all elements become 100 width
12383 els.hide(true); // all elements fade out and hide
12385 els.setWidth(100).hide(true);
12388 Roo.CompositeElement = function(els){
12389 this.elements = [];
12390 this.addElements(els);
12392 Roo.CompositeElement.prototype = {
12394 addElements : function(els){
12398 if(typeof els == "string"){
12399 els = Roo.Element.selectorFunction(els);
12401 var yels = this.elements;
12402 var index = yels.length-1;
12403 for(var i = 0, len = els.length; i < len; i++) {
12404 yels[++index] = Roo.get(els[i]);
12410 * Clears this composite and adds the elements returned by the passed selector.
12411 * @param {String/Array} els A string CSS selector, an array of elements or an element
12412 * @return {CompositeElement} this
12414 fill : function(els){
12415 this.elements = [];
12421 * Filters this composite to only elements that match the passed selector.
12422 * @param {String} selector A string CSS selector
12423 * @param {Boolean} inverse return inverse filter (not matches)
12424 * @return {CompositeElement} this
12426 filter : function(selector, inverse){
12428 inverse = inverse || false;
12429 this.each(function(el){
12430 var match = inverse ? !el.is(selector) : el.is(selector);
12432 els[els.length] = el.dom;
12439 invoke : function(fn, args){
12440 var els = this.elements;
12441 for(var i = 0, len = els.length; i < len; i++) {
12442 Roo.Element.prototype[fn].apply(els[i], args);
12447 * Adds elements to this composite.
12448 * @param {String/Array} els A string CSS selector, an array of elements or an element
12449 * @return {CompositeElement} this
12451 add : function(els){
12452 if(typeof els == "string"){
12453 this.addElements(Roo.Element.selectorFunction(els));
12454 }else if(els.length !== undefined){
12455 this.addElements(els);
12457 this.addElements([els]);
12462 * Calls the passed function passing (el, this, index) for each element in this composite.
12463 * @param {Function} fn The function to call
12464 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12465 * @return {CompositeElement} this
12467 each : function(fn, scope){
12468 var els = this.elements;
12469 for(var i = 0, len = els.length; i < len; i++){
12470 if(fn.call(scope || els[i], els[i], this, i) === false) {
12478 * Returns the Element object at the specified index
12479 * @param {Number} index
12480 * @return {Roo.Element}
12482 item : function(index){
12483 return this.elements[index] || null;
12487 * Returns the first Element
12488 * @return {Roo.Element}
12490 first : function(){
12491 return this.item(0);
12495 * Returns the last Element
12496 * @return {Roo.Element}
12499 return this.item(this.elements.length-1);
12503 * Returns the number of elements in this composite
12506 getCount : function(){
12507 return this.elements.length;
12511 * Returns true if this composite contains the passed element
12514 contains : function(el){
12515 return this.indexOf(el) !== -1;
12519 * Returns true if this composite contains the passed element
12522 indexOf : function(el){
12523 return this.elements.indexOf(Roo.get(el));
12528 * Removes the specified element(s).
12529 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
12530 * or an array of any of those.
12531 * @param {Boolean} removeDom (optional) True to also remove the element from the document
12532 * @return {CompositeElement} this
12534 removeElement : function(el, removeDom){
12535 if(el instanceof Array){
12536 for(var i = 0, len = el.length; i < len; i++){
12537 this.removeElement(el[i]);
12541 var index = typeof el == 'number' ? el : this.indexOf(el);
12544 var d = this.elements[index];
12548 d.parentNode.removeChild(d);
12551 this.elements.splice(index, 1);
12557 * Replaces the specified element with the passed element.
12558 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
12560 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
12561 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
12562 * @return {CompositeElement} this
12564 replaceElement : function(el, replacement, domReplace){
12565 var index = typeof el == 'number' ? el : this.indexOf(el);
12568 this.elements[index].replaceWith(replacement);
12570 this.elements.splice(index, 1, Roo.get(replacement))
12577 * Removes all elements.
12579 clear : function(){
12580 this.elements = [];
12584 Roo.CompositeElement.createCall = function(proto, fnName){
12585 if(!proto[fnName]){
12586 proto[fnName] = function(){
12587 return this.invoke(fnName, arguments);
12591 for(var fnName in Roo.Element.prototype){
12592 if(typeof Roo.Element.prototype[fnName] == "function"){
12593 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
12599 * Ext JS Library 1.1.1
12600 * Copyright(c) 2006-2007, Ext JS, LLC.
12602 * Originally Released Under LGPL - original licence link has changed is not relivant.
12605 * <script type="text/javascript">
12609 * @class Roo.CompositeElementLite
12610 * @extends Roo.CompositeElement
12611 * Flyweight composite class. Reuses the same Roo.Element for element operations.
12613 var els = Roo.select("#some-el div.some-class");
12614 // or select directly from an existing element
12615 var el = Roo.get('some-el');
12616 el.select('div.some-class');
12618 els.setWidth(100); // all elements become 100 width
12619 els.hide(true); // all elements fade out and hide
12621 els.setWidth(100).hide(true);
12622 </code></pre><br><br>
12623 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12624 * actions will be performed on all the elements in this collection.</b>
12626 Roo.CompositeElementLite = function(els){
12627 Roo.CompositeElementLite.superclass.constructor.call(this, els);
12628 this.el = new Roo.Element.Flyweight();
12630 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
12631 addElements : function(els){
12633 if(els instanceof Array){
12634 this.elements = this.elements.concat(els);
12636 var yels = this.elements;
12637 var index = yels.length-1;
12638 for(var i = 0, len = els.length; i < len; i++) {
12639 yels[++index] = els[i];
12645 invoke : function(fn, args){
12646 var els = this.elements;
12648 for(var i = 0, len = els.length; i < len; i++) {
12650 Roo.Element.prototype[fn].apply(el, args);
12655 * Returns a flyweight Element of the dom element object at the specified index
12656 * @param {Number} index
12657 * @return {Roo.Element}
12659 item : function(index){
12660 if(!this.elements[index]){
12663 this.el.dom = this.elements[index];
12667 // fixes scope with flyweight
12668 addListener : function(eventName, handler, scope, opt){
12669 var els = this.elements;
12670 for(var i = 0, len = els.length; i < len; i++) {
12671 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
12677 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
12678 * passed is the flyweight (shared) Roo.Element instance, so if you require a
12679 * a reference to the dom node, use el.dom.</b>
12680 * @param {Function} fn The function to call
12681 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12682 * @return {CompositeElement} this
12684 each : function(fn, scope){
12685 var els = this.elements;
12687 for(var i = 0, len = els.length; i < len; i++){
12689 if(fn.call(scope || el, el, this, i) === false){
12696 indexOf : function(el){
12697 return this.elements.indexOf(Roo.getDom(el));
12700 replaceElement : function(el, replacement, domReplace){
12701 var index = typeof el == 'number' ? el : this.indexOf(el);
12703 replacement = Roo.getDom(replacement);
12705 var d = this.elements[index];
12706 d.parentNode.insertBefore(replacement, d);
12707 d.parentNode.removeChild(d);
12709 this.elements.splice(index, 1, replacement);
12714 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
12718 * Ext JS Library 1.1.1
12719 * Copyright(c) 2006-2007, Ext JS, LLC.
12721 * Originally Released Under LGPL - original licence link has changed is not relivant.
12724 * <script type="text/javascript">
12730 * @class Roo.data.Connection
12731 * @extends Roo.util.Observable
12732 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
12733 * either to a configured URL, or to a URL specified at request time.
12735 * Requests made by this class are asynchronous, and will return immediately. No data from
12736 * the server will be available to the statement immediately following the {@link #request} call.
12737 * To process returned data, use a callback in the request options object, or an event listener.
12739 * Note: If you are doing a file upload, you will not get a normal response object sent back to
12740 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
12741 * The response object is created using the innerHTML of the IFRAME's document as the responseText
12742 * property and, if present, the IFRAME's XML document as the responseXML property.
12744 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
12745 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
12746 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
12747 * standard DOM methods.
12749 * @param {Object} config a configuration object.
12751 Roo.data.Connection = function(config){
12752 Roo.apply(this, config);
12755 * @event beforerequest
12756 * Fires before a network request is made to retrieve a data object.
12757 * @param {Connection} conn This Connection object.
12758 * @param {Object} options The options config object passed to the {@link #request} method.
12760 "beforerequest" : true,
12762 * @event requestcomplete
12763 * Fires if the request was successfully completed.
12764 * @param {Connection} conn This Connection object.
12765 * @param {Object} response The XHR object containing the response data.
12766 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12767 * @param {Object} options The options config object passed to the {@link #request} method.
12769 "requestcomplete" : true,
12771 * @event requestexception
12772 * Fires if an error HTTP status was returned from the server.
12773 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
12774 * @param {Connection} conn This Connection object.
12775 * @param {Object} response The XHR object containing the response data.
12776 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12777 * @param {Object} options The options config object passed to the {@link #request} method.
12779 "requestexception" : true
12781 Roo.data.Connection.superclass.constructor.call(this);
12784 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
12786 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12789 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12790 * extra parameters to each request made by this object. (defaults to undefined)
12793 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12794 * to each request made by this object. (defaults to undefined)
12797 * @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)
12800 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12804 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12810 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12813 disableCaching: true,
12816 * Sends an HTTP request to a remote server.
12817 * @param {Object} options An object which may contain the following properties:<ul>
12818 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
12819 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
12820 * request, a url encoded string or a function to call to get either.</li>
12821 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
12822 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
12823 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
12824 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
12825 * <li>options {Object} The parameter to the request call.</li>
12826 * <li>success {Boolean} True if the request succeeded.</li>
12827 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12829 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
12830 * The callback is passed the following parameters:<ul>
12831 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12832 * <li>options {Object} The parameter to the request call.</li>
12834 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
12835 * The callback is passed the following parameters:<ul>
12836 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12837 * <li>options {Object} The parameter to the request call.</li>
12839 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
12840 * for the callback function. Defaults to the browser window.</li>
12841 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
12842 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
12843 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
12844 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
12845 * params for the post data. Any params will be appended to the URL.</li>
12846 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
12848 * @return {Number} transactionId
12850 request : function(o){
12851 if(this.fireEvent("beforerequest", this, o) !== false){
12854 if(typeof p == "function"){
12855 p = p.call(o.scope||window, o);
12857 if(typeof p == "object"){
12858 p = Roo.urlEncode(o.params);
12860 if(this.extraParams){
12861 var extras = Roo.urlEncode(this.extraParams);
12862 p = p ? (p + '&' + extras) : extras;
12865 var url = o.url || this.url;
12866 if(typeof url == 'function'){
12867 url = url.call(o.scope||window, o);
12871 var form = Roo.getDom(o.form);
12872 url = url || form.action;
12874 var enctype = form.getAttribute("enctype");
12877 return this.doFormDataUpload(o, url);
12880 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
12881 return this.doFormUpload(o, p, url);
12883 var f = Roo.lib.Ajax.serializeForm(form);
12884 p = p ? (p + '&' + f) : f;
12887 if (!o.form && o.formData) {
12888 o.formData = o.formData === true ? new FormData() : o.formData;
12889 for (var k in o.params) {
12890 o.formData.append(k,o.params[k]);
12893 return this.doFormDataUpload(o, url);
12897 var hs = o.headers;
12898 if(this.defaultHeaders){
12899 hs = Roo.apply(hs || {}, this.defaultHeaders);
12906 success: this.handleResponse,
12907 failure: this.handleFailure,
12909 argument: {options: o},
12910 timeout : o.timeout || this.timeout
12913 var method = o.method||this.method||(p ? "POST" : "GET");
12915 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
12916 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
12919 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
12923 }else if(this.autoAbort !== false){
12927 if((method == 'GET' && p) || o.xmlData){
12928 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
12931 Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
12932 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
12933 Roo.lib.Ajax.useDefaultHeader == true;
12934 return this.transId;
12936 Roo.callback(o.callback, o.scope, [o, null, null]);
12942 * Determine whether this object has a request outstanding.
12943 * @param {Number} transactionId (Optional) defaults to the last transaction
12944 * @return {Boolean} True if there is an outstanding request.
12946 isLoading : function(transId){
12948 return Roo.lib.Ajax.isCallInProgress(transId);
12950 return this.transId ? true : false;
12955 * Aborts any outstanding request.
12956 * @param {Number} transactionId (Optional) defaults to the last transaction
12958 abort : function(transId){
12959 if(transId || this.isLoading()){
12960 Roo.lib.Ajax.abort(transId || this.transId);
12965 handleResponse : function(response){
12966 this.transId = false;
12967 var options = response.argument.options;
12968 response.argument = options ? options.argument : null;
12969 this.fireEvent("requestcomplete", this, response, options);
12970 Roo.callback(options.success, options.scope, [response, options]);
12971 Roo.callback(options.callback, options.scope, [options, true, response]);
12975 handleFailure : function(response, e){
12976 this.transId = false;
12977 var options = response.argument.options;
12978 response.argument = options ? options.argument : null;
12979 this.fireEvent("requestexception", this, response, options, e);
12980 Roo.callback(options.failure, options.scope, [response, options]);
12981 Roo.callback(options.callback, options.scope, [options, false, response]);
12985 doFormUpload : function(o, ps, url){
12987 var frame = document.createElement('iframe');
12990 frame.className = 'x-hidden';
12992 frame.src = Roo.SSL_SECURE_URL;
12994 document.body.appendChild(frame);
12997 document.frames[id].name = id;
13000 var form = Roo.getDom(o.form);
13002 form.method = 'POST';
13003 form.enctype = form.encoding = 'multipart/form-data';
13009 if(ps){ // add dynamic params
13011 ps = Roo.urlDecode(ps, false);
13013 if(ps.hasOwnProperty(k)){
13014 hd = document.createElement('input');
13015 hd.type = 'hidden';
13018 form.appendChild(hd);
13025 var r = { // bogus response object
13030 r.argument = o ? o.argument : null;
13035 doc = frame.contentWindow.document;
13037 doc = (frame.contentDocument || window.frames[id].document);
13039 if(doc && doc.body){
13040 r.responseText = doc.body.innerHTML;
13042 if(doc && doc.XMLDocument){
13043 r.responseXML = doc.XMLDocument;
13045 r.responseXML = doc;
13052 Roo.EventManager.removeListener(frame, 'load', cb, this);
13054 this.fireEvent("requestcomplete", this, r, o);
13055 Roo.callback(o.success, o.scope, [r, o]);
13056 Roo.callback(o.callback, o.scope, [o, true, r]);
13058 setTimeout(function(){document.body.removeChild(frame);}, 100);
13061 Roo.EventManager.on(frame, 'load', cb, this);
13064 if(hiddens){ // remove dynamic params
13065 for(var i = 0, len = hiddens.length; i < len; i++){
13066 form.removeChild(hiddens[i]);
13070 // this is a 'formdata version???'
13073 doFormDataUpload : function(o, url)
13077 var form = Roo.getDom(o.form);
13078 form.enctype = form.encoding = 'multipart/form-data';
13079 formData = o.formData === true ? new FormData(form) : o.formData;
13081 formData = o.formData === true ? new FormData() : o.formData;
13086 success: this.handleResponse,
13087 failure: this.handleFailure,
13089 argument: {options: o},
13090 timeout : o.timeout || this.timeout
13093 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
13097 }else if(this.autoAbort !== false){
13101 //Roo.lib.Ajax.defaultPostHeader = null;
13102 Roo.lib.Ajax.useDefaultHeader = false;
13103 this.transId = Roo.lib.Ajax.request( "POST", url, cb, formData, o);
13104 Roo.lib.Ajax.useDefaultHeader = true;
13112 * Ext JS Library 1.1.1
13113 * Copyright(c) 2006-2007, Ext JS, LLC.
13115 * Originally Released Under LGPL - original licence link has changed is not relivant.
13118 * <script type="text/javascript">
13122 * Global Ajax request class.
13125 * @extends Roo.data.Connection
13128 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
13129 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
13130 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
13131 * @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)
13132 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
13133 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
13134 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
13136 Roo.Ajax = new Roo.data.Connection({
13145 * Serialize the passed form into a url encoded string
13147 * @param {String/HTMLElement} form
13150 serializeForm : function(form){
13151 return Roo.lib.Ajax.serializeForm(form);
13155 * Ext JS Library 1.1.1
13156 * Copyright(c) 2006-2007, Ext JS, LLC.
13158 * Originally Released Under LGPL - original licence link has changed is not relivant.
13161 * <script type="text/javascript">
13166 * @class Roo.UpdateManager
13167 * @extends Roo.util.Observable
13168 * Provides AJAX-style update for Element object.<br><br>
13171 * // Get it from a Roo.Element object
13172 * var el = Roo.get("foo");
13173 * var mgr = el.getUpdateManager();
13174 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
13176 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
13178 * // or directly (returns the same UpdateManager instance)
13179 * var mgr = new Roo.UpdateManager("myElementId");
13180 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
13181 * mgr.on("update", myFcnNeedsToKnow);
13183 // short handed call directly from the element object
13184 Roo.get("foo").load({
13188 text: "Loading Foo..."
13192 * Create new UpdateManager directly.
13193 * @param {String/HTMLElement/Roo.Element} el The element to update
13194 * @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).
13196 Roo.UpdateManager = function(el, forceNew){
13198 if(!forceNew && el.updateManager){
13199 return el.updateManager;
13202 * The Element object
13203 * @type Roo.Element
13207 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
13210 this.defaultUrl = null;
13214 * @event beforeupdate
13215 * Fired before an update is made, return false from your handler and the update is cancelled.
13216 * @param {Roo.Element} el
13217 * @param {String/Object/Function} url
13218 * @param {String/Object} params
13220 "beforeupdate": true,
13223 * Fired after successful update is made.
13224 * @param {Roo.Element} el
13225 * @param {Object} oResponseObject The response Object
13230 * Fired on update failure.
13231 * @param {Roo.Element} el
13232 * @param {Object} oResponseObject The response Object
13236 var d = Roo.UpdateManager.defaults;
13238 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
13241 this.sslBlankUrl = d.sslBlankUrl;
13243 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
13246 this.disableCaching = d.disableCaching;
13248 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
13251 this.indicatorText = d.indicatorText;
13253 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
13256 this.showLoadIndicator = d.showLoadIndicator;
13258 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
13261 this.timeout = d.timeout;
13264 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
13267 this.loadScripts = d.loadScripts;
13270 * Transaction object of current executing transaction
13272 this.transaction = null;
13277 this.autoRefreshProcId = null;
13279 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
13282 this.refreshDelegate = this.refresh.createDelegate(this);
13284 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
13287 this.updateDelegate = this.update.createDelegate(this);
13289 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
13292 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
13296 this.successDelegate = this.processSuccess.createDelegate(this);
13300 this.failureDelegate = this.processFailure.createDelegate(this);
13302 if(!this.renderer){
13304 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
13306 this.renderer = new Roo.UpdateManager.BasicRenderer();
13309 Roo.UpdateManager.superclass.constructor.call(this);
13312 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
13314 * Get the Element this UpdateManager is bound to
13315 * @return {Roo.Element} The element
13317 getEl : function(){
13321 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
13322 * @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:
13325 url: "your-url.php",<br/>
13326 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
13327 callback: yourFunction,<br/>
13328 scope: yourObject, //(optional scope) <br/>
13329 discardUrl: false, <br/>
13330 nocache: false,<br/>
13331 text: "Loading...",<br/>
13333 scripts: false<br/>
13336 * The only required property is url. The optional properties nocache, text and scripts
13337 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
13338 * @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}
13339 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13340 * @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.
13342 update : function(url, params, callback, discardUrl){
13343 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
13344 var method = this.method,
13346 if(typeof url == "object"){ // must be config object
13349 params = params || cfg.params;
13350 callback = callback || cfg.callback;
13351 discardUrl = discardUrl || cfg.discardUrl;
13352 if(callback && cfg.scope){
13353 callback = callback.createDelegate(cfg.scope);
13355 if(typeof cfg.method != "undefined"){method = cfg.method;};
13356 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
13357 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
13358 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
13359 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
13361 this.showLoading();
13363 this.defaultUrl = url;
13365 if(typeof url == "function"){
13366 url = url.call(this);
13369 method = method || (params ? "POST" : "GET");
13370 if(method == "GET"){
13371 url = this.prepareUrl(url);
13374 var o = Roo.apply(cfg ||{}, {
13377 success: this.successDelegate,
13378 failure: this.failureDelegate,
13379 callback: undefined,
13380 timeout: (this.timeout*1000),
13381 argument: {"url": url, "form": null, "callback": callback, "params": params}
13383 Roo.log("updated manager called with timeout of " + o.timeout);
13384 this.transaction = Roo.Ajax.request(o);
13389 * 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.
13390 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
13391 * @param {String/HTMLElement} form The form Id or form element
13392 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
13393 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
13394 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13396 formUpdate : function(form, url, reset, callback){
13397 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
13398 if(typeof url == "function"){
13399 url = url.call(this);
13401 form = Roo.getDom(form);
13402 this.transaction = Roo.Ajax.request({
13405 success: this.successDelegate,
13406 failure: this.failureDelegate,
13407 timeout: (this.timeout*1000),
13408 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
13410 this.showLoading.defer(1, this);
13415 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
13416 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13418 refresh : function(callback){
13419 if(this.defaultUrl == null){
13422 this.update(this.defaultUrl, null, callback, true);
13426 * Set this element to auto refresh.
13427 * @param {Number} interval How often to update (in seconds).
13428 * @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)
13429 * @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}
13430 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13431 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
13433 startAutoRefresh : function(interval, url, params, callback, refreshNow){
13435 this.update(url || this.defaultUrl, params, callback, true);
13437 if(this.autoRefreshProcId){
13438 clearInterval(this.autoRefreshProcId);
13440 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
13444 * Stop auto refresh on this element.
13446 stopAutoRefresh : function(){
13447 if(this.autoRefreshProcId){
13448 clearInterval(this.autoRefreshProcId);
13449 delete this.autoRefreshProcId;
13453 isAutoRefreshing : function(){
13454 return this.autoRefreshProcId ? true : false;
13457 * Called to update the element to "Loading" state. Override to perform custom action.
13459 showLoading : function(){
13460 if(this.showLoadIndicator){
13461 this.el.update(this.indicatorText);
13466 * Adds unique parameter to query string if disableCaching = true
13469 prepareUrl : function(url){
13470 if(this.disableCaching){
13471 var append = "_dc=" + (new Date().getTime());
13472 if(url.indexOf("?") !== -1){
13473 url += "&" + append;
13475 url += "?" + append;
13484 processSuccess : function(response){
13485 this.transaction = null;
13486 if(response.argument.form && response.argument.reset){
13487 try{ // put in try/catch since some older FF releases had problems with this
13488 response.argument.form.reset();
13491 if(this.loadScripts){
13492 this.renderer.render(this.el, response, this,
13493 this.updateComplete.createDelegate(this, [response]));
13495 this.renderer.render(this.el, response, this);
13496 this.updateComplete(response);
13500 updateComplete : function(response){
13501 this.fireEvent("update", this.el, response);
13502 if(typeof response.argument.callback == "function"){
13503 response.argument.callback(this.el, true, response);
13510 processFailure : function(response){
13511 this.transaction = null;
13512 this.fireEvent("failure", this.el, response);
13513 if(typeof response.argument.callback == "function"){
13514 response.argument.callback(this.el, false, response);
13519 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
13520 * @param {Object} renderer The object implementing the render() method
13522 setRenderer : function(renderer){
13523 this.renderer = renderer;
13526 getRenderer : function(){
13527 return this.renderer;
13531 * Set the defaultUrl used for updates
13532 * @param {String/Function} defaultUrl The url or a function to call to get the url
13534 setDefaultUrl : function(defaultUrl){
13535 this.defaultUrl = defaultUrl;
13539 * Aborts the executing transaction
13541 abort : function(){
13542 if(this.transaction){
13543 Roo.Ajax.abort(this.transaction);
13548 * Returns true if an update is in progress
13549 * @return {Boolean}
13551 isUpdating : function(){
13552 if(this.transaction){
13553 return Roo.Ajax.isLoading(this.transaction);
13560 * @class Roo.UpdateManager.defaults
13561 * @static (not really - but it helps the doc tool)
13562 * The defaults collection enables customizing the default properties of UpdateManager
13564 Roo.UpdateManager.defaults = {
13566 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
13572 * True to process scripts by default (Defaults to false).
13575 loadScripts : false,
13578 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
13581 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
13583 * Whether to append unique parameter on get request to disable caching (Defaults to false).
13586 disableCaching : false,
13588 * Whether to show indicatorText when loading (Defaults to true).
13591 showLoadIndicator : true,
13593 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
13596 indicatorText : '<div class="loading-indicator">Loading...</div>'
13600 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
13602 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
13603 * @param {String/HTMLElement/Roo.Element} el The element to update
13604 * @param {String} url The url
13605 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
13606 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
13609 * @member Roo.UpdateManager
13611 Roo.UpdateManager.updateElement = function(el, url, params, options){
13612 var um = Roo.get(el, true).getUpdateManager();
13613 Roo.apply(um, options);
13614 um.update(url, params, options ? options.callback : null);
13616 // alias for backwards compat
13617 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
13619 * @class Roo.UpdateManager.BasicRenderer
13620 * Default Content renderer. Updates the elements innerHTML with the responseText.
13622 Roo.UpdateManager.BasicRenderer = function(){};
13624 Roo.UpdateManager.BasicRenderer.prototype = {
13626 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
13627 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
13628 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
13629 * @param {Roo.Element} el The element being rendered
13630 * @param {Object} response The YUI Connect response object
13631 * @param {UpdateManager} updateManager The calling update manager
13632 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
13634 render : function(el, response, updateManager, callback){
13635 el.update(response.responseText, updateManager.loadScripts, callback);
13641 * (c)) Alan Knowles
13647 * @class Roo.DomTemplate
13648 * @extends Roo.Template
13649 * An effort at a dom based template engine..
13651 * Similar to XTemplate, except it uses dom parsing to create the template..
13653 * Supported features:
13658 {a_variable} - output encoded.
13659 {a_variable.format:("Y-m-d")} - call a method on the variable
13660 {a_variable:raw} - unencoded output
13661 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
13662 {a_variable:this.method_on_template(...)} - call a method on the template object.
13667 <div roo-for="a_variable or condition.."></div>
13668 <div roo-if="a_variable or condition"></div>
13669 <div roo-exec="some javascript"></div>
13670 <div roo-name="named_template"></div>
13675 Roo.DomTemplate = function()
13677 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
13684 Roo.extend(Roo.DomTemplate, Roo.Template, {
13686 * id counter for sub templates.
13690 * flag to indicate if dom parser is inside a pre,
13691 * it will strip whitespace if not.
13696 * The various sub templates
13704 * basic tag replacing syntax
13707 * // you can fake an object call by doing this
13711 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
13712 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
13714 iterChild : function (node, method) {
13716 var oldPre = this.inPre;
13717 if (node.tagName == 'PRE') {
13720 for( var i = 0; i < node.childNodes.length; i++) {
13721 method.call(this, node.childNodes[i]);
13723 this.inPre = oldPre;
13729 * compile the template
13731 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
13734 compile: function()
13738 // covert the html into DOM...
13742 doc = document.implementation.createHTMLDocument("");
13743 doc.documentElement.innerHTML = this.html ;
13744 div = doc.documentElement;
13746 // old IE... - nasty -- it causes all sorts of issues.. with
13747 // images getting pulled from server..
13748 div = document.createElement('div');
13749 div.innerHTML = this.html;
13751 //doc.documentElement.innerHTML = htmlBody
13757 this.iterChild(div, function(n) {_t.compileNode(n, true); });
13759 var tpls = this.tpls;
13761 // create a top level template from the snippet..
13763 //Roo.log(div.innerHTML);
13770 body : div.innerHTML,
13783 Roo.each(tpls, function(tp){
13784 this.compileTpl(tp);
13785 this.tpls[tp.id] = tp;
13788 this.master = tpls[0];
13794 compileNode : function(node, istop) {
13799 // skip anything not a tag..
13800 if (node.nodeType != 1) {
13801 if (node.nodeType == 3 && !this.inPre) {
13802 // reduce white space..
13803 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
13826 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
13827 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
13828 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
13829 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
13835 // just itterate children..
13836 this.iterChild(node,this.compileNode);
13839 tpl.uid = this.id++;
13840 tpl.value = node.getAttribute('roo-' + tpl.attr);
13841 node.removeAttribute('roo-'+ tpl.attr);
13842 if (tpl.attr != 'name') {
13843 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
13844 node.parentNode.replaceChild(placeholder, node);
13847 var placeholder = document.createElement('span');
13848 placeholder.className = 'roo-tpl-' + tpl.value;
13849 node.parentNode.replaceChild(placeholder, node);
13852 // parent now sees '{domtplXXXX}
13853 this.iterChild(node,this.compileNode);
13855 // we should now have node body...
13856 var div = document.createElement('div');
13857 div.appendChild(node);
13859 // this has the unfortunate side effect of converting tagged attributes
13860 // eg. href="{...}" into %7C...%7D
13861 // this has been fixed by searching for those combo's although it's a bit hacky..
13864 tpl.body = div.innerHTML;
13871 switch (tpl.value) {
13872 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
13873 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
13874 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
13879 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13883 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13887 tpl.id = tpl.value; // replace non characters???
13893 this.tpls.push(tpl);
13903 * Compile a segment of the template into a 'sub-template'
13909 compileTpl : function(tpl)
13911 var fm = Roo.util.Format;
13912 var useF = this.disableFormats !== true;
13914 var sep = Roo.isGecko ? "+\n" : ",\n";
13916 var undef = function(str) {
13917 Roo.debug && Roo.log("Property not found :" + str);
13921 //Roo.log(tpl.body);
13925 var fn = function(m, lbrace, name, format, args)
13928 //Roo.log(arguments);
13929 args = args ? args.replace(/\\'/g,"'") : args;
13930 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
13931 if (typeof(format) == 'undefined') {
13932 format = 'htmlEncode';
13934 if (format == 'raw' ) {
13938 if(name.substr(0, 6) == 'domtpl'){
13939 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
13942 // build an array of options to determine if value is undefined..
13944 // basically get 'xxxx.yyyy' then do
13945 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
13946 // (function () { Roo.log("Property not found"); return ''; })() :
13951 Roo.each(name.split('.'), function(st) {
13952 lookfor += (lookfor.length ? '.': '') + st;
13953 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
13956 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
13959 if(format && useF){
13961 args = args ? ',' + args : "";
13963 if(format.substr(0, 5) != "this."){
13964 format = "fm." + format + '(';
13966 format = 'this.call("'+ format.substr(5) + '", ';
13970 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
13973 if (args && args.length) {
13974 // called with xxyx.yuu:(test,test)
13976 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
13978 // raw.. - :raw modifier..
13979 return "'"+ sep + udef_st + name + ")"+sep+"'";
13983 // branched to use + in gecko and [].join() in others
13985 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
13986 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
13989 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
13990 body.push(tpl.body.replace(/(\r\n|\n)/g,
13991 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
13992 body.push("'].join('');};};");
13993 body = body.join('');
13996 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
13998 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
14005 * same as applyTemplate, except it's done to one of the subTemplates
14006 * when using named templates, you can do:
14008 * var str = pl.applySubTemplate('your-name', values);
14011 * @param {Number} id of the template
14012 * @param {Object} values to apply to template
14013 * @param {Object} parent (normaly the instance of this object)
14015 applySubTemplate : function(id, values, parent)
14019 var t = this.tpls[id];
14023 if(t.ifCall && !t.ifCall.call(this, values, parent)){
14024 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
14028 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
14035 if(t.execCall && t.execCall.call(this, values, parent)){
14039 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
14045 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
14046 parent = t.target ? values : parent;
14047 if(t.forCall && vs instanceof Array){
14049 for(var i = 0, len = vs.length; i < len; i++){
14051 buf[buf.length] = t.compiled.call(this, vs[i], parent);
14053 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
14055 //Roo.log(t.compiled);
14059 return buf.join('');
14062 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
14067 return t.compiled.call(this, vs, parent);
14069 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
14071 //Roo.log(t.compiled);
14079 applyTemplate : function(values){
14080 return this.master.compiled.call(this, values, {});
14081 //var s = this.subs;
14084 apply : function(){
14085 return this.applyTemplate.apply(this, arguments);
14090 Roo.DomTemplate.from = function(el){
14091 el = Roo.getDom(el);
14092 return new Roo.Domtemplate(el.value || el.innerHTML);
14095 * Ext JS Library 1.1.1
14096 * Copyright(c) 2006-2007, Ext JS, LLC.
14098 * Originally Released Under LGPL - original licence link has changed is not relivant.
14101 * <script type="text/javascript">
14105 * @class Roo.util.DelayedTask
14106 * Provides a convenient method of performing setTimeout where a new
14107 * timeout cancels the old timeout. An example would be performing validation on a keypress.
14108 * You can use this class to buffer
14109 * the keypress events for a certain number of milliseconds, and perform only if they stop
14110 * for that amount of time.
14111 * @constructor The parameters to this constructor serve as defaults and are not required.
14112 * @param {Function} fn (optional) The default function to timeout
14113 * @param {Object} scope (optional) The default scope of that timeout
14114 * @param {Array} args (optional) The default Array of arguments
14116 Roo.util.DelayedTask = function(fn, scope, args){
14117 var id = null, d, t;
14119 var call = function(){
14120 var now = new Date().getTime();
14124 fn.apply(scope, args || []);
14128 * Cancels any pending timeout and queues a new one
14129 * @param {Number} delay The milliseconds to delay
14130 * @param {Function} newFn (optional) Overrides function passed to constructor
14131 * @param {Object} newScope (optional) Overrides scope passed to constructor
14132 * @param {Array} newArgs (optional) Overrides args passed to constructor
14134 this.delay = function(delay, newFn, newScope, newArgs){
14135 if(id && delay != d){
14139 t = new Date().getTime();
14141 scope = newScope || scope;
14142 args = newArgs || args;
14144 id = setInterval(call, d);
14149 * Cancel the last queued timeout
14151 this.cancel = function(){
14159 * Ext JS Library 1.1.1
14160 * Copyright(c) 2006-2007, Ext JS, LLC.
14162 * Originally Released Under LGPL - original licence link has changed is not relivant.
14165 * <script type="text/javascript">
14168 * @class Roo.util.TaskRunner
14169 * Manage background tasks - not sure why this is better that setInterval?
14174 Roo.util.TaskRunner = function(interval){
14175 interval = interval || 10;
14176 var tasks = [], removeQueue = [];
14178 var running = false;
14180 var stopThread = function(){
14186 var startThread = function(){
14189 id = setInterval(runTasks, interval);
14193 var removeTask = function(task){
14194 removeQueue.push(task);
14200 var runTasks = function(){
14201 if(removeQueue.length > 0){
14202 for(var i = 0, len = removeQueue.length; i < len; i++){
14203 tasks.remove(removeQueue[i]);
14206 if(tasks.length < 1){
14211 var now = new Date().getTime();
14212 for(var i = 0, len = tasks.length; i < len; ++i){
14214 var itime = now - t.taskRunTime;
14215 if(t.interval <= itime){
14216 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
14217 t.taskRunTime = now;
14218 if(rt === false || t.taskRunCount === t.repeat){
14223 if(t.duration && t.duration <= (now - t.taskStartTime)){
14230 * Queues a new task.
14231 * @param {Object} task
14233 * Task property : interval = how frequent to run.
14234 * Task object should implement
14236 * Task object may implement
14237 * function onStop()
14239 this.start = function(task){
14241 task.taskStartTime = new Date().getTime();
14242 task.taskRunTime = 0;
14243 task.taskRunCount = 0;
14249 * @param {Object} task
14251 this.stop = function(task){
14258 this.stopAll = function(){
14260 for(var i = 0, len = tasks.length; i < len; i++){
14261 if(tasks[i].onStop){
14270 Roo.TaskMgr = new Roo.util.TaskRunner();/*
14272 * Ext JS Library 1.1.1
14273 * Copyright(c) 2006-2007, Ext JS, LLC.
14275 * Originally Released Under LGPL - original licence link has changed is not relivant.
14278 * <script type="text/javascript">
14283 * @class Roo.util.MixedCollection
14284 * @extends Roo.util.Observable
14285 * A Collection class that maintains both numeric indexes and keys and exposes events.
14287 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
14288 * collection (defaults to false)
14289 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
14290 * and return the key value for that item. This is used when available to look up the key on items that
14291 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
14292 * equivalent to providing an implementation for the {@link #getKey} method.
14294 Roo.util.MixedCollection = function(allowFunctions, keyFn){
14302 * Fires when the collection is cleared.
14307 * Fires when an item is added to the collection.
14308 * @param {Number} index The index at which the item was added.
14309 * @param {Object} o The item added.
14310 * @param {String} key The key associated with the added item.
14315 * Fires when an item is replaced in the collection.
14316 * @param {String} key he key associated with the new added.
14317 * @param {Object} old The item being replaced.
14318 * @param {Object} new The new item.
14323 * Fires when an item is removed from the collection.
14324 * @param {Object} o The item being removed.
14325 * @param {String} key (optional) The key associated with the removed item.
14330 this.allowFunctions = allowFunctions === true;
14332 this.getKey = keyFn;
14334 Roo.util.MixedCollection.superclass.constructor.call(this);
14337 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
14338 allowFunctions : false,
14341 * Adds an item to the collection.
14342 * @param {String} key The key to associate with the item
14343 * @param {Object} o The item to add.
14344 * @return {Object} The item added.
14346 add : function(key, o){
14347 if(arguments.length == 1){
14349 key = this.getKey(o);
14351 if(typeof key == "undefined" || key === null){
14353 this.items.push(o);
14354 this.keys.push(null);
14356 var old = this.map[key];
14358 return this.replace(key, o);
14361 this.items.push(o);
14363 this.keys.push(key);
14365 this.fireEvent("add", this.length-1, o, key);
14370 * MixedCollection has a generic way to fetch keys if you implement getKey.
14373 var mc = new Roo.util.MixedCollection();
14374 mc.add(someEl.dom.id, someEl);
14375 mc.add(otherEl.dom.id, otherEl);
14379 var mc = new Roo.util.MixedCollection();
14380 mc.getKey = function(el){
14386 // or via the constructor
14387 var mc = new Roo.util.MixedCollection(false, function(el){
14393 * @param o {Object} The item for which to find the key.
14394 * @return {Object} The key for the passed item.
14396 getKey : function(o){
14401 * Replaces an item in the collection.
14402 * @param {String} key The key associated with the item to replace, or the item to replace.
14403 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
14404 * @return {Object} The new item.
14406 replace : function(key, o){
14407 if(arguments.length == 1){
14409 key = this.getKey(o);
14411 var old = this.item(key);
14412 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
14413 return this.add(key, o);
14415 var index = this.indexOfKey(key);
14416 this.items[index] = o;
14418 this.fireEvent("replace", key, old, o);
14423 * Adds all elements of an Array or an Object to the collection.
14424 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
14425 * an Array of values, each of which are added to the collection.
14427 addAll : function(objs){
14428 if(arguments.length > 1 || objs instanceof Array){
14429 var args = arguments.length > 1 ? arguments : objs;
14430 for(var i = 0, len = args.length; i < len; i++){
14434 for(var key in objs){
14435 if(this.allowFunctions || typeof objs[key] != "function"){
14436 this.add(key, objs[key]);
14443 * Executes the specified function once for every item in the collection, passing each
14444 * item as the first and only parameter. returning false from the function will stop the iteration.
14445 * @param {Function} fn The function to execute for each item.
14446 * @param {Object} scope (optional) The scope in which to execute the function.
14448 each : function(fn, scope){
14449 var items = [].concat(this.items); // each safe for removal
14450 for(var i = 0, len = items.length; i < len; i++){
14451 if(fn.call(scope || items[i], items[i], i, len) === false){
14458 * Executes the specified function once for every key in the collection, passing each
14459 * key, and its associated item as the first two parameters.
14460 * @param {Function} fn The function to execute for each item.
14461 * @param {Object} scope (optional) The scope in which to execute the function.
14463 eachKey : function(fn, scope){
14464 for(var i = 0, len = this.keys.length; i < len; i++){
14465 fn.call(scope || window, this.keys[i], this.items[i], i, len);
14470 * Returns the first item in the collection which elicits a true return value from the
14471 * passed selection function.
14472 * @param {Function} fn The selection function to execute for each item.
14473 * @param {Object} scope (optional) The scope in which to execute the function.
14474 * @return {Object} The first item in the collection which returned true from the selection function.
14476 find : function(fn, scope){
14477 for(var i = 0, len = this.items.length; i < len; i++){
14478 if(fn.call(scope || window, this.items[i], this.keys[i])){
14479 return this.items[i];
14486 * Inserts an item at the specified index in the collection.
14487 * @param {Number} index The index to insert the item at.
14488 * @param {String} key The key to associate with the new item, or the item itself.
14489 * @param {Object} o (optional) If the second parameter was a key, the new item.
14490 * @return {Object} The item inserted.
14492 insert : function(index, key, o){
14493 if(arguments.length == 2){
14495 key = this.getKey(o);
14497 if(index >= this.length){
14498 return this.add(key, o);
14501 this.items.splice(index, 0, o);
14502 if(typeof key != "undefined" && key != null){
14505 this.keys.splice(index, 0, key);
14506 this.fireEvent("add", index, o, key);
14511 * Removed an item from the collection.
14512 * @param {Object} o The item to remove.
14513 * @return {Object} The item removed.
14515 remove : function(o){
14516 return this.removeAt(this.indexOf(o));
14520 * Remove an item from a specified index in the collection.
14521 * @param {Number} index The index within the collection of the item to remove.
14523 removeAt : function(index){
14524 if(index < this.length && index >= 0){
14526 var o = this.items[index];
14527 this.items.splice(index, 1);
14528 var key = this.keys[index];
14529 if(typeof key != "undefined"){
14530 delete this.map[key];
14532 this.keys.splice(index, 1);
14533 this.fireEvent("remove", o, key);
14538 * Removed an item associated with the passed key fom the collection.
14539 * @param {String} key The key of the item to remove.
14541 removeKey : function(key){
14542 return this.removeAt(this.indexOfKey(key));
14546 * Returns the number of items in the collection.
14547 * @return {Number} the number of items in the collection.
14549 getCount : function(){
14550 return this.length;
14554 * Returns index within the collection of the passed Object.
14555 * @param {Object} o The item to find the index of.
14556 * @return {Number} index of the item.
14558 indexOf : function(o){
14559 if(!this.items.indexOf){
14560 for(var i = 0, len = this.items.length; i < len; i++){
14561 if(this.items[i] == o) {
14567 return this.items.indexOf(o);
14572 * Returns index within the collection of the passed key.
14573 * @param {String} key The key to find the index of.
14574 * @return {Number} index of the key.
14576 indexOfKey : function(key){
14577 if(!this.keys.indexOf){
14578 for(var i = 0, len = this.keys.length; i < len; i++){
14579 if(this.keys[i] == key) {
14585 return this.keys.indexOf(key);
14590 * Returns the item associated with the passed key OR index. Key has priority over index.
14591 * @param {String/Number} key The key or index of the item.
14592 * @return {Object} The item associated with the passed key.
14594 item : function(key){
14595 if (key === 'length') {
14598 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
14599 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
14603 * Returns the item at the specified index.
14604 * @param {Number} index The index of the item.
14607 itemAt : function(index){
14608 return this.items[index];
14612 * Returns the item associated with the passed key.
14613 * @param {String/Number} key The key of the item.
14614 * @return {Object} The item associated with the passed key.
14616 key : function(key){
14617 return this.map[key];
14621 * Returns true if the collection contains the passed Object as an item.
14622 * @param {Object} o The Object to look for in the collection.
14623 * @return {Boolean} True if the collection contains the Object as an item.
14625 contains : function(o){
14626 return this.indexOf(o) != -1;
14630 * Returns true if the collection contains the passed Object as a key.
14631 * @param {String} key The key to look for in the collection.
14632 * @return {Boolean} True if the collection contains the Object as a key.
14634 containsKey : function(key){
14635 return typeof this.map[key] != "undefined";
14639 * Removes all items from the collection.
14641 clear : function(){
14646 this.fireEvent("clear");
14650 * Returns the first item in the collection.
14651 * @return {Object} the first item in the collection..
14653 first : function(){
14654 return this.items[0];
14658 * Returns the last item in the collection.
14659 * @return {Object} the last item in the collection..
14662 return this.items[this.length-1];
14665 _sort : function(property, dir, fn){
14666 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
14667 fn = fn || function(a, b){
14670 var c = [], k = this.keys, items = this.items;
14671 for(var i = 0, len = items.length; i < len; i++){
14672 c[c.length] = {key: k[i], value: items[i], index: i};
14674 c.sort(function(a, b){
14675 var v = fn(a[property], b[property]) * dsc;
14677 v = (a.index < b.index ? -1 : 1);
14681 for(var i = 0, len = c.length; i < len; i++){
14682 items[i] = c[i].value;
14685 this.fireEvent("sort", this);
14689 * Sorts this collection with the passed comparison function
14690 * @param {String} direction (optional) "ASC" or "DESC"
14691 * @param {Function} fn (optional) comparison function
14693 sort : function(dir, fn){
14694 this._sort("value", dir, fn);
14698 * Sorts this collection by keys
14699 * @param {String} direction (optional) "ASC" or "DESC"
14700 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
14702 keySort : function(dir, fn){
14703 this._sort("key", dir, fn || function(a, b){
14704 return String(a).toUpperCase()-String(b).toUpperCase();
14709 * Returns a range of items in this collection
14710 * @param {Number} startIndex (optional) defaults to 0
14711 * @param {Number} endIndex (optional) default to the last item
14712 * @return {Array} An array of items
14714 getRange : function(start, end){
14715 var items = this.items;
14716 if(items.length < 1){
14719 start = start || 0;
14720 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
14723 for(var i = start; i <= end; i++) {
14724 r[r.length] = items[i];
14727 for(var i = start; i >= end; i--) {
14728 r[r.length] = items[i];
14735 * Filter the <i>objects</i> in this collection by a specific property.
14736 * Returns a new collection that has been filtered.
14737 * @param {String} property A property on your objects
14738 * @param {String/RegExp} value Either string that the property values
14739 * should start with or a RegExp to test against the property
14740 * @return {MixedCollection} The new filtered collection
14742 filter : function(property, value){
14743 if(!value.exec){ // not a regex
14744 value = String(value);
14745 if(value.length == 0){
14746 return this.clone();
14748 value = new RegExp("^" + Roo.escapeRe(value), "i");
14750 return this.filterBy(function(o){
14751 return o && value.test(o[property]);
14756 * Filter by a function. * Returns a new collection that has been filtered.
14757 * The passed function will be called with each
14758 * object in the collection. If the function returns true, the value is included
14759 * otherwise it is filtered.
14760 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
14761 * @param {Object} scope (optional) The scope of the function (defaults to this)
14762 * @return {MixedCollection} The new filtered collection
14764 filterBy : function(fn, scope){
14765 var r = new Roo.util.MixedCollection();
14766 r.getKey = this.getKey;
14767 var k = this.keys, it = this.items;
14768 for(var i = 0, len = it.length; i < len; i++){
14769 if(fn.call(scope||this, it[i], k[i])){
14770 r.add(k[i], it[i]);
14777 * Creates a duplicate of this collection
14778 * @return {MixedCollection}
14780 clone : function(){
14781 var r = new Roo.util.MixedCollection();
14782 var k = this.keys, it = this.items;
14783 for(var i = 0, len = it.length; i < len; i++){
14784 r.add(k[i], it[i]);
14786 r.getKey = this.getKey;
14791 * Returns the item associated with the passed key or index.
14793 * @param {String/Number} key The key or index of the item.
14794 * @return {Object} The item associated with the passed key.
14796 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
14798 * Ext JS Library 1.1.1
14799 * Copyright(c) 2006-2007, Ext JS, LLC.
14801 * Originally Released Under LGPL - original licence link has changed is not relivant.
14804 * <script type="text/javascript">
14807 * @class Roo.util.JSON
14808 * Modified version of Douglas Crockford"s json.js that doesn"t
14809 * mess with the Object prototype
14810 * http://www.json.org/js.html
14813 Roo.util.JSON = new (function(){
14814 var useHasOwn = {}.hasOwnProperty ? true : false;
14816 // crashes Safari in some instances
14817 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
14819 var pad = function(n) {
14820 return n < 10 ? "0" + n : n;
14833 var encodeString = function(s){
14834 if (/["\\\x00-\x1f]/.test(s)) {
14835 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
14840 c = b.charCodeAt();
14842 Math.floor(c / 16).toString(16) +
14843 (c % 16).toString(16);
14846 return '"' + s + '"';
14849 var encodeArray = function(o){
14850 var a = ["["], b, i, l = o.length, v;
14851 for (i = 0; i < l; i += 1) {
14853 switch (typeof v) {
14862 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
14870 var encodeDate = function(o){
14871 return '"' + o.getFullYear() + "-" +
14872 pad(o.getMonth() + 1) + "-" +
14873 pad(o.getDate()) + "T" +
14874 pad(o.getHours()) + ":" +
14875 pad(o.getMinutes()) + ":" +
14876 pad(o.getSeconds()) + '"';
14880 * Encodes an Object, Array or other value
14881 * @param {Mixed} o The variable to encode
14882 * @return {String} The JSON string
14884 this.encode = function(o)
14886 // should this be extended to fully wrap stringify..
14888 if(typeof o == "undefined" || o === null){
14890 }else if(o instanceof Array){
14891 return encodeArray(o);
14892 }else if(o instanceof Date){
14893 return encodeDate(o);
14894 }else if(typeof o == "string"){
14895 return encodeString(o);
14896 }else if(typeof o == "number"){
14897 return isFinite(o) ? String(o) : "null";
14898 }else if(typeof o == "boolean"){
14901 var a = ["{"], b, i, v;
14903 if(!useHasOwn || o.hasOwnProperty(i)) {
14905 switch (typeof v) {
14914 a.push(this.encode(i), ":",
14915 v === null ? "null" : this.encode(v));
14926 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
14927 * @param {String} json The JSON string
14928 * @return {Object} The resulting object
14930 this.decode = function(json){
14932 return /** eval:var:json */ eval("(" + json + ')');
14936 * Shorthand for {@link Roo.util.JSON#encode}
14937 * @member Roo encode
14939 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
14941 * Shorthand for {@link Roo.util.JSON#decode}
14942 * @member Roo decode
14944 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
14947 * Ext JS Library 1.1.1
14948 * Copyright(c) 2006-2007, Ext JS, LLC.
14950 * Originally Released Under LGPL - original licence link has changed is not relivant.
14953 * <script type="text/javascript">
14957 * @class Roo.util.Format
14958 * Reusable data formatting functions
14961 Roo.util.Format = function(){
14962 var trimRe = /^\s+|\s+$/g;
14965 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
14966 * @param {String} value The string to truncate
14967 * @param {Number} length The maximum length to allow before truncating
14968 * @return {String} The converted text
14970 ellipsis : function(value, len){
14971 if(value && value.length > len){
14972 return value.substr(0, len-3)+"...";
14978 * Checks a reference and converts it to empty string if it is undefined
14979 * @param {Mixed} value Reference to check
14980 * @return {Mixed} Empty string if converted, otherwise the original value
14982 undef : function(value){
14983 return typeof value != "undefined" ? value : "";
14987 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
14988 * @param {String} value The string to encode
14989 * @return {String} The encoded text
14991 htmlEncode : function(value){
14992 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
14996 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
14997 * @param {String} value The string to decode
14998 * @return {String} The decoded text
15000 htmlDecode : function(value){
15001 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
15005 * Trims any whitespace from either side of a string
15006 * @param {String} value The text to trim
15007 * @return {String} The trimmed text
15009 trim : function(value){
15010 return String(value).replace(trimRe, "");
15014 * Returns a substring from within an original string
15015 * @param {String} value The original text
15016 * @param {Number} start The start index of the substring
15017 * @param {Number} length The length of the substring
15018 * @return {String} The substring
15020 substr : function(value, start, length){
15021 return String(value).substr(start, length);
15025 * Converts a string to all lower case letters
15026 * @param {String} value The text to convert
15027 * @return {String} The converted text
15029 lowercase : function(value){
15030 return String(value).toLowerCase();
15034 * Converts a string to all upper case letters
15035 * @param {String} value The text to convert
15036 * @return {String} The converted text
15038 uppercase : function(value){
15039 return String(value).toUpperCase();
15043 * Converts the first character only of a string to upper case
15044 * @param {String} value The text to convert
15045 * @return {String} The converted text
15047 capitalize : function(value){
15048 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
15052 call : function(value, fn){
15053 if(arguments.length > 2){
15054 var args = Array.prototype.slice.call(arguments, 2);
15055 args.unshift(value);
15057 return /** eval:var:value */ eval(fn).apply(window, args);
15059 /** eval:var:value */
15060 return /** eval:var:value */ eval(fn).call(window, value);
15066 * safer version of Math.toFixed..??/
15067 * @param {Number/String} value The numeric value to format
15068 * @param {Number/String} value Decimal places
15069 * @return {String} The formatted currency string
15071 toFixed : function(v, n)
15073 // why not use to fixed - precision is buggered???
15075 return Math.round(v-0);
15077 var fact = Math.pow(10,n+1);
15078 v = (Math.round((v-0)*fact))/fact;
15079 var z = (''+fact).substring(2);
15080 if (v == Math.floor(v)) {
15081 return Math.floor(v) + '.' + z;
15084 // now just padd decimals..
15085 var ps = String(v).split('.');
15086 var fd = (ps[1] + z);
15087 var r = fd.substring(0,n);
15088 var rm = fd.substring(n);
15090 return ps[0] + '.' + r;
15092 r*=1; // turn it into a number;
15094 if (String(r).length != n) {
15097 r = String(r).substring(1); // chop the end off.
15100 return ps[0] + '.' + r;
15105 * Format a number as US currency
15106 * @param {Number/String} value The numeric value to format
15107 * @return {String} The formatted currency string
15109 usMoney : function(v){
15110 return '$' + Roo.util.Format.number(v);
15115 * eventually this should probably emulate php's number_format
15116 * @param {Number/String} value The numeric value to format
15117 * @param {Number} decimals number of decimal places
15118 * @param {String} delimiter for thousands (default comma)
15119 * @return {String} The formatted currency string
15121 number : function(v, decimals, thousandsDelimiter)
15123 // multiply and round.
15124 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
15125 thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
15127 var mul = Math.pow(10, decimals);
15128 var zero = String(mul).substring(1);
15129 v = (Math.round((v-0)*mul))/mul;
15131 // if it's '0' number.. then
15133 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
15135 var ps = v.split('.');
15138 var r = /(\d+)(\d{3})/;
15141 if(thousandsDelimiter.length != 0) {
15142 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
15147 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
15148 // does not have decimals
15149 (decimals ? ('.' + zero) : '');
15152 return whole + sub ;
15156 * Parse a value into a formatted date using the specified format pattern.
15157 * @param {Mixed} value The value to format
15158 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
15159 * @return {String} The formatted date string
15161 date : function(v, format){
15165 if(!(v instanceof Date)){
15166 v = new Date(Date.parse(v));
15168 return v.dateFormat(format || Roo.util.Format.defaults.date);
15172 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
15173 * @param {String} format Any valid date format string
15174 * @return {Function} The date formatting function
15176 dateRenderer : function(format){
15177 return function(v){
15178 return Roo.util.Format.date(v, format);
15183 stripTagsRE : /<\/?[^>]+>/gi,
15186 * Strips all HTML tags
15187 * @param {Mixed} value The text from which to strip tags
15188 * @return {String} The stripped text
15190 stripTags : function(v){
15191 return !v ? v : String(v).replace(this.stripTagsRE, "");
15195 * Size in Mb,Gb etc.
15196 * @param {Number} value The number to be formated
15197 * @param {number} decimals how many decimal places
15198 * @return {String} the formated string
15200 size : function(value, decimals)
15202 var sizes = ['b', 'k', 'M', 'G', 'T'];
15206 var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
15207 return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals) + sizes[i];
15214 Roo.util.Format.defaults = {
15218 * Ext JS Library 1.1.1
15219 * Copyright(c) 2006-2007, Ext JS, LLC.
15221 * Originally Released Under LGPL - original licence link has changed is not relivant.
15224 * <script type="text/javascript">
15231 * @class Roo.MasterTemplate
15232 * @extends Roo.Template
15233 * Provides a template that can have child templates. The syntax is:
15235 var t = new Roo.MasterTemplate(
15236 '<select name="{name}">',
15237 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
15240 t.add('options', {value: 'foo', text: 'bar'});
15241 // or you can add multiple child elements in one shot
15242 t.addAll('options', [
15243 {value: 'foo', text: 'bar'},
15244 {value: 'foo2', text: 'bar2'},
15245 {value: 'foo3', text: 'bar3'}
15247 // then append, applying the master template values
15248 t.append('my-form', {name: 'my-select'});
15250 * A name attribute for the child template is not required if you have only one child
15251 * template or you want to refer to them by index.
15253 Roo.MasterTemplate = function(){
15254 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
15255 this.originalHtml = this.html;
15257 var m, re = this.subTemplateRe;
15260 while(m = re.exec(this.html)){
15261 var name = m[1], content = m[2];
15266 tpl : new Roo.Template(content)
15269 st[name] = st[subIndex];
15271 st[subIndex].tpl.compile();
15272 st[subIndex].tpl.call = this.call.createDelegate(this);
15275 this.subCount = subIndex;
15278 Roo.extend(Roo.MasterTemplate, Roo.Template, {
15280 * The regular expression used to match sub templates
15284 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
15287 * Applies the passed values to a child template.
15288 * @param {String/Number} name (optional) The name or index of the child template
15289 * @param {Array/Object} values The values to be applied to the template
15290 * @return {MasterTemplate} this
15292 add : function(name, values){
15293 if(arguments.length == 1){
15294 values = arguments[0];
15297 var s = this.subs[name];
15298 s.buffer[s.buffer.length] = s.tpl.apply(values);
15303 * Applies all the passed values to a child template.
15304 * @param {String/Number} name (optional) The name or index of the child template
15305 * @param {Array} values The values to be applied to the template, this should be an array of objects.
15306 * @param {Boolean} reset (optional) True to reset the template first
15307 * @return {MasterTemplate} this
15309 fill : function(name, values, reset){
15311 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
15319 for(var i = 0, len = values.length; i < len; i++){
15320 this.add(name, values[i]);
15326 * Resets the template for reuse
15327 * @return {MasterTemplate} this
15329 reset : function(){
15331 for(var i = 0; i < this.subCount; i++){
15337 applyTemplate : function(values){
15339 var replaceIndex = -1;
15340 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
15341 return s[++replaceIndex].buffer.join("");
15343 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
15346 apply : function(){
15347 return this.applyTemplate.apply(this, arguments);
15350 compile : function(){return this;}
15354 * Alias for fill().
15357 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
15359 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
15360 * var tpl = Roo.MasterTemplate.from('element-id');
15361 * @param {String/HTMLElement} el
15362 * @param {Object} config
15365 Roo.MasterTemplate.from = function(el, config){
15366 el = Roo.getDom(el);
15367 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
15370 * Ext JS Library 1.1.1
15371 * Copyright(c) 2006-2007, Ext JS, LLC.
15373 * Originally Released Under LGPL - original licence link has changed is not relivant.
15376 * <script type="text/javascript">
15381 * @class Roo.util.CSS
15382 * Utility class for manipulating CSS rules
15386 Roo.util.CSS = function(){
15388 var doc = document;
15390 var camelRe = /(-[a-z])/gi;
15391 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
15395 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
15396 * tag and appended to the HEAD of the document.
15397 * @param {String|Object} cssText The text containing the css rules
15398 * @param {String} id An id to add to the stylesheet for later removal
15399 * @return {StyleSheet}
15401 createStyleSheet : function(cssText, id){
15403 var head = doc.getElementsByTagName("head")[0];
15404 var nrules = doc.createElement("style");
15405 nrules.setAttribute("type", "text/css");
15407 nrules.setAttribute("id", id);
15409 if (typeof(cssText) != 'string') {
15410 // support object maps..
15411 // not sure if this a good idea..
15412 // perhaps it should be merged with the general css handling
15413 // and handle js style props.
15414 var cssTextNew = [];
15415 for(var n in cssText) {
15417 for(var k in cssText[n]) {
15418 citems.push( k + ' : ' +cssText[n][k] + ';' );
15420 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
15423 cssText = cssTextNew.join("\n");
15429 head.appendChild(nrules);
15430 ss = nrules.styleSheet;
15431 ss.cssText = cssText;
15434 nrules.appendChild(doc.createTextNode(cssText));
15436 nrules.cssText = cssText;
15438 head.appendChild(nrules);
15439 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
15441 this.cacheStyleSheet(ss);
15446 * Removes a style or link tag by id
15447 * @param {String} id The id of the tag
15449 removeStyleSheet : function(id){
15450 var existing = doc.getElementById(id);
15452 existing.parentNode.removeChild(existing);
15457 * Dynamically swaps an existing stylesheet reference for a new one
15458 * @param {String} id The id of an existing link tag to remove
15459 * @param {String} url The href of the new stylesheet to include
15461 swapStyleSheet : function(id, url){
15462 this.removeStyleSheet(id);
15463 var ss = doc.createElement("link");
15464 ss.setAttribute("rel", "stylesheet");
15465 ss.setAttribute("type", "text/css");
15466 ss.setAttribute("id", id);
15467 ss.setAttribute("href", url);
15468 doc.getElementsByTagName("head")[0].appendChild(ss);
15472 * Refresh the rule cache if you have dynamically added stylesheets
15473 * @return {Object} An object (hash) of rules indexed by selector
15475 refreshCache : function(){
15476 return this.getRules(true);
15480 cacheStyleSheet : function(stylesheet){
15484 try{// try catch for cross domain access issue
15485 var ssRules = stylesheet.cssRules || stylesheet.rules;
15486 for(var j = ssRules.length-1; j >= 0; --j){
15487 rules[ssRules[j].selectorText] = ssRules[j];
15493 * Gets all css rules for the document
15494 * @param {Boolean} refreshCache true to refresh the internal cache
15495 * @return {Object} An object (hash) of rules indexed by selector
15497 getRules : function(refreshCache){
15498 if(rules == null || refreshCache){
15500 var ds = doc.styleSheets;
15501 for(var i =0, len = ds.length; i < len; i++){
15503 this.cacheStyleSheet(ds[i]);
15511 * Gets an an individual CSS rule by selector(s)
15512 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
15513 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
15514 * @return {CSSRule} The CSS rule or null if one is not found
15516 getRule : function(selector, refreshCache){
15517 var rs = this.getRules(refreshCache);
15518 if(!(selector instanceof Array)){
15519 return rs[selector];
15521 for(var i = 0; i < selector.length; i++){
15522 if(rs[selector[i]]){
15523 return rs[selector[i]];
15531 * Updates a rule property
15532 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
15533 * @param {String} property The css property
15534 * @param {String} value The new value for the property
15535 * @return {Boolean} true If a rule was found and updated
15537 updateRule : function(selector, property, value){
15538 if(!(selector instanceof Array)){
15539 var rule = this.getRule(selector);
15541 rule.style[property.replace(camelRe, camelFn)] = value;
15545 for(var i = 0; i < selector.length; i++){
15546 if(this.updateRule(selector[i], property, value)){
15556 * Ext JS Library 1.1.1
15557 * Copyright(c) 2006-2007, Ext JS, LLC.
15559 * Originally Released Under LGPL - original licence link has changed is not relivant.
15562 * <script type="text/javascript">
15568 * @class Roo.util.ClickRepeater
15569 * @extends Roo.util.Observable
15571 * A wrapper class which can be applied to any element. Fires a "click" event while the
15572 * mouse is pressed. The interval between firings may be specified in the config but
15573 * defaults to 10 milliseconds.
15575 * Optionally, a CSS class may be applied to the element during the time it is pressed.
15577 * @cfg {String/HTMLElement/Element} el The element to act as a button.
15578 * @cfg {Number} delay The initial delay before the repeating event begins firing.
15579 * Similar to an autorepeat key delay.
15580 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
15581 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
15582 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
15583 * "interval" and "delay" are ignored. "immediate" is honored.
15584 * @cfg {Boolean} preventDefault True to prevent the default click event
15585 * @cfg {Boolean} stopDefault True to stop the default click event
15588 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
15589 * 2007-02-02 jvs Renamed to ClickRepeater
15590 * 2007-02-03 jvs Modifications for FF Mac and Safari
15593 * @param {String/HTMLElement/Element} el The element to listen on
15594 * @param {Object} config
15596 Roo.util.ClickRepeater = function(el, config)
15598 this.el = Roo.get(el);
15599 this.el.unselectable();
15601 Roo.apply(this, config);
15606 * Fires when the mouse button is depressed.
15607 * @param {Roo.util.ClickRepeater} this
15609 "mousedown" : true,
15612 * Fires on a specified interval during the time the element is pressed.
15613 * @param {Roo.util.ClickRepeater} this
15618 * Fires when the mouse key is released.
15619 * @param {Roo.util.ClickRepeater} this
15624 this.el.on("mousedown", this.handleMouseDown, this);
15625 if(this.preventDefault || this.stopDefault){
15626 this.el.on("click", function(e){
15627 if(this.preventDefault){
15628 e.preventDefault();
15630 if(this.stopDefault){
15636 // allow inline handler
15638 this.on("click", this.handler, this.scope || this);
15641 Roo.util.ClickRepeater.superclass.constructor.call(this);
15644 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
15647 preventDefault : true,
15648 stopDefault : false,
15652 handleMouseDown : function(){
15653 clearTimeout(this.timer);
15655 if(this.pressClass){
15656 this.el.addClass(this.pressClass);
15658 this.mousedownTime = new Date();
15660 Roo.get(document).on("mouseup", this.handleMouseUp, this);
15661 this.el.on("mouseout", this.handleMouseOut, this);
15663 this.fireEvent("mousedown", this);
15664 this.fireEvent("click", this);
15666 this.timer = this.click.defer(this.delay || this.interval, this);
15670 click : function(){
15671 this.fireEvent("click", this);
15672 this.timer = this.click.defer(this.getInterval(), this);
15676 getInterval: function(){
15677 if(!this.accelerate){
15678 return this.interval;
15680 var pressTime = this.mousedownTime.getElapsed();
15681 if(pressTime < 500){
15683 }else if(pressTime < 1700){
15685 }else if(pressTime < 2600){
15687 }else if(pressTime < 3500){
15689 }else if(pressTime < 4400){
15691 }else if(pressTime < 5300){
15693 }else if(pressTime < 6200){
15701 handleMouseOut : function(){
15702 clearTimeout(this.timer);
15703 if(this.pressClass){
15704 this.el.removeClass(this.pressClass);
15706 this.el.on("mouseover", this.handleMouseReturn, this);
15710 handleMouseReturn : function(){
15711 this.el.un("mouseover", this.handleMouseReturn);
15712 if(this.pressClass){
15713 this.el.addClass(this.pressClass);
15719 handleMouseUp : function(){
15720 clearTimeout(this.timer);
15721 this.el.un("mouseover", this.handleMouseReturn);
15722 this.el.un("mouseout", this.handleMouseOut);
15723 Roo.get(document).un("mouseup", this.handleMouseUp);
15724 this.el.removeClass(this.pressClass);
15725 this.fireEvent("mouseup", this);
15728 * @class Roo.util.Clipboard
15734 Roo.util.Clipboard = {
15736 * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
15737 * @param {String} text to copy to clipboard
15739 write : function(text) {
15740 // navigator clipboard api needs a secure context (https)
15741 if (navigator.clipboard && window.isSecureContext) {
15742 // navigator clipboard api method'
15743 navigator.clipboard.writeText(text);
15746 // text area method
15747 var ta = document.createElement("textarea");
15749 // make the textarea out of viewport
15750 ta.style.position = "fixed";
15751 ta.style.left = "-999999px";
15752 ta.style.top = "-999999px";
15753 document.body.appendChild(ta);
15756 document.execCommand('copy');
15766 * Ext JS Library 1.1.1
15767 * Copyright(c) 2006-2007, Ext JS, LLC.
15769 * Originally Released Under LGPL - original licence link has changed is not relivant.
15772 * <script type="text/javascript">
15777 * @class Roo.KeyNav
15778 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
15779 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
15780 * way to implement custom navigation schemes for any UI component.</p>
15781 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
15782 * pageUp, pageDown, del, home, end. Usage:</p>
15784 var nav = new Roo.KeyNav("my-element", {
15785 "left" : function(e){
15786 this.moveLeft(e.ctrlKey);
15788 "right" : function(e){
15789 this.moveRight(e.ctrlKey);
15791 "enter" : function(e){
15798 * @param {String/HTMLElement/Roo.Element} el The element to bind to
15799 * @param {Object} config The config
15801 Roo.KeyNav = function(el, config){
15802 this.el = Roo.get(el);
15803 Roo.apply(this, config);
15804 if(!this.disabled){
15805 this.disabled = true;
15810 Roo.KeyNav.prototype = {
15812 * @cfg {Boolean} disabled
15813 * True to disable this KeyNav instance (defaults to false)
15817 * @cfg {String} defaultEventAction
15818 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
15819 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
15820 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
15822 defaultEventAction: "stopEvent",
15824 * @cfg {Boolean} forceKeyDown
15825 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
15826 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
15827 * handle keydown instead of keypress.
15829 forceKeyDown : false,
15832 prepareEvent : function(e){
15833 var k = e.getKey();
15834 var h = this.keyToHandler[k];
15835 //if(h && this[h]){
15836 // e.stopPropagation();
15838 if(Roo.isSafari && h && k >= 37 && k <= 40){
15844 relay : function(e){
15845 var k = e.getKey();
15846 var h = this.keyToHandler[k];
15848 if(this.doRelay(e, this[h], h) !== true){
15849 e[this.defaultEventAction]();
15855 doRelay : function(e, h, hname){
15856 return h.call(this.scope || this, e);
15859 // possible handlers
15873 // quick lookup hash
15890 * Enable this KeyNav
15892 enable: function(){
15894 // ie won't do special keys on keypress, no one else will repeat keys with keydown
15895 // the EventObject will normalize Safari automatically
15896 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15897 this.el.on("keydown", this.relay, this);
15899 this.el.on("keydown", this.prepareEvent, this);
15900 this.el.on("keypress", this.relay, this);
15902 this.disabled = false;
15907 * Disable this KeyNav
15909 disable: function(){
15910 if(!this.disabled){
15911 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15912 this.el.un("keydown", this.relay);
15914 this.el.un("keydown", this.prepareEvent);
15915 this.el.un("keypress", this.relay);
15917 this.disabled = true;
15922 * Ext JS Library 1.1.1
15923 * Copyright(c) 2006-2007, Ext JS, LLC.
15925 * Originally Released Under LGPL - original licence link has changed is not relivant.
15928 * <script type="text/javascript">
15933 * @class Roo.KeyMap
15934 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
15935 * The constructor accepts the same config object as defined by {@link #addBinding}.
15936 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
15937 * combination it will call the function with this signature (if the match is a multi-key
15938 * combination the callback will still be called only once): (String key, Roo.EventObject e)
15939 * A KeyMap can also handle a string representation of keys.<br />
15942 // map one key by key code
15943 var map = new Roo.KeyMap("my-element", {
15944 key: 13, // or Roo.EventObject.ENTER
15949 // map multiple keys to one action by string
15950 var map = new Roo.KeyMap("my-element", {
15956 // map multiple keys to multiple actions by strings and array of codes
15957 var map = new Roo.KeyMap("my-element", [
15960 fn: function(){ alert("Return was pressed"); }
15963 fn: function(){ alert('a, b or c was pressed'); }
15968 fn: function(){ alert('Control + shift + tab was pressed.'); }
15972 * <b>Note: A KeyMap starts enabled</b>
15974 * @param {String/HTMLElement/Roo.Element} el The element to bind to
15975 * @param {Object} config The config (see {@link #addBinding})
15976 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
15978 Roo.KeyMap = function(el, config, eventName){
15979 this.el = Roo.get(el);
15980 this.eventName = eventName || "keydown";
15981 this.bindings = [];
15983 this.addBinding(config);
15988 Roo.KeyMap.prototype = {
15990 * True to stop the event from bubbling and prevent the default browser action if the
15991 * key was handled by the KeyMap (defaults to false)
15997 * Add a new binding to this KeyMap. The following config object properties are supported:
15999 Property Type Description
16000 ---------- --------------- ----------------------------------------------------------------------
16001 key String/Array A single keycode or an array of keycodes to handle
16002 shift Boolean True to handle key only when shift is pressed (defaults to false)
16003 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
16004 alt Boolean True to handle key only when alt is pressed (defaults to false)
16005 fn Function The function to call when KeyMap finds the expected key combination
16006 scope Object The scope of the callback function
16012 var map = new Roo.KeyMap(document, {
16013 key: Roo.EventObject.ENTER,
16018 //Add a new binding to the existing KeyMap later
16026 * @param {Object/Array} config A single KeyMap config or an array of configs
16028 addBinding : function(config){
16029 if(config instanceof Array){
16030 for(var i = 0, len = config.length; i < len; i++){
16031 this.addBinding(config[i]);
16035 var keyCode = config.key,
16036 shift = config.shift,
16037 ctrl = config.ctrl,
16040 scope = config.scope;
16041 if(typeof keyCode == "string"){
16043 var keyString = keyCode.toUpperCase();
16044 for(var j = 0, len = keyString.length; j < len; j++){
16045 ks.push(keyString.charCodeAt(j));
16049 var keyArray = keyCode instanceof Array;
16050 var handler = function(e){
16051 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
16052 var k = e.getKey();
16054 for(var i = 0, len = keyCode.length; i < len; i++){
16055 if(keyCode[i] == k){
16056 if(this.stopEvent){
16059 fn.call(scope || window, k, e);
16065 if(this.stopEvent){
16068 fn.call(scope || window, k, e);
16073 this.bindings.push(handler);
16077 * Shorthand for adding a single key listener
16078 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
16079 * following options:
16080 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
16081 * @param {Function} fn The function to call
16082 * @param {Object} scope (optional) The scope of the function
16084 on : function(key, fn, scope){
16085 var keyCode, shift, ctrl, alt;
16086 if(typeof key == "object" && !(key instanceof Array)){
16105 handleKeyDown : function(e){
16106 if(this.enabled){ //just in case
16107 var b = this.bindings;
16108 for(var i = 0, len = b.length; i < len; i++){
16109 b[i].call(this, e);
16115 * Returns true if this KeyMap is enabled
16116 * @return {Boolean}
16118 isEnabled : function(){
16119 return this.enabled;
16123 * Enables this KeyMap
16125 enable: function(){
16127 this.el.on(this.eventName, this.handleKeyDown, this);
16128 this.enabled = true;
16133 * Disable this KeyMap
16135 disable: function(){
16137 this.el.removeListener(this.eventName, this.handleKeyDown, this);
16138 this.enabled = false;
16143 * Ext JS Library 1.1.1
16144 * Copyright(c) 2006-2007, Ext JS, LLC.
16146 * Originally Released Under LGPL - original licence link has changed is not relivant.
16149 * <script type="text/javascript">
16154 * @class Roo.util.TextMetrics
16155 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
16156 * wide, in pixels, a given block of text will be.
16159 Roo.util.TextMetrics = function(){
16163 * Measures the size of the specified text
16164 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
16165 * that can affect the size of the rendered text
16166 * @param {String} text The text to measure
16167 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
16168 * in order to accurately measure the text height
16169 * @return {Object} An object containing the text's size {width: (width), height: (height)}
16171 measure : function(el, text, fixedWidth){
16173 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
16176 shared.setFixedWidth(fixedWidth || 'auto');
16177 return shared.getSize(text);
16181 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
16182 * the overhead of multiple calls to initialize the style properties on each measurement.
16183 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
16184 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
16185 * in order to accurately measure the text height
16186 * @return {Roo.util.TextMetrics.Instance} instance The new instance
16188 createInstance : function(el, fixedWidth){
16189 return Roo.util.TextMetrics.Instance(el, fixedWidth);
16195 * @class Roo.util.TextMetrics.Instance
16196 * Instance of TextMetrics Calcuation
16198 * Create a new TextMetrics Instance
16199 * @param {Object} bindto
16200 * @param {Boolean} fixedWidth
16203 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth)
16205 var ml = new Roo.Element(document.createElement('div'));
16206 document.body.appendChild(ml.dom);
16207 ml.position('absolute');
16208 ml.setLeftTop(-1000, -1000);
16212 ml.setWidth(fixedWidth);
16217 * Returns the size of the specified text based on the internal element's style and width properties
16218 * @param {String} text The text to measure
16219 * @return {Object} An object containing the text's size {width: (width), height: (height)}
16221 getSize : function(text){
16223 var s = ml.getSize();
16229 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
16230 * that can affect the size of the rendered text
16231 * @param {String/HTMLElement} el The element, dom node or id
16233 bind : function(el){
16235 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
16240 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
16241 * to set a fixed width in order to accurately measure the text height.
16242 * @param {Number} width The width to set on the element
16244 setFixedWidth : function(width){
16245 ml.setWidth(width);
16249 * Returns the measured width of the specified text
16250 * @param {String} text The text to measure
16251 * @return {Number} width The width in pixels
16253 getWidth : function(text){
16254 ml.dom.style.width = 'auto';
16255 return this.getSize(text).width;
16259 * Returns the measured height of the specified text. For multiline text, be sure to call
16260 * {@link #setFixedWidth} if necessary.
16261 * @param {String} text The text to measure
16262 * @return {Number} height The height in pixels
16264 getHeight : function(text){
16265 return this.getSize(text).height;
16269 instance.bind(bindTo);
16274 // backwards compat
16275 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
16277 * Ext JS Library 1.1.1
16278 * Copyright(c) 2006-2007, Ext JS, LLC.
16280 * Originally Released Under LGPL - original licence link has changed is not relivant.
16283 * <script type="text/javascript">
16287 * @class Roo.state.Provider
16288 * Abstract base class for state provider implementations. This class provides methods
16289 * for encoding and decoding <b>typed</b> variables including dates and defines the
16290 * Provider interface.
16292 Roo.state.Provider = function(){
16294 * @event statechange
16295 * Fires when a state change occurs.
16296 * @param {Provider} this This state provider
16297 * @param {String} key The state key which was changed
16298 * @param {String} value The encoded value for the state
16301 "statechange": true
16304 Roo.state.Provider.superclass.constructor.call(this);
16306 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
16308 * Returns the current value for a key
16309 * @param {String} name The key name
16310 * @param {Mixed} defaultValue A default value to return if the key's value is not found
16311 * @return {Mixed} The state data
16313 get : function(name, defaultValue){
16314 return typeof this.state[name] == "undefined" ?
16315 defaultValue : this.state[name];
16319 * Clears a value from the state
16320 * @param {String} name The key name
16322 clear : function(name){
16323 delete this.state[name];
16324 this.fireEvent("statechange", this, name, null);
16328 * Sets the value for a key
16329 * @param {String} name The key name
16330 * @param {Mixed} value The value to set
16332 set : function(name, value){
16333 this.state[name] = value;
16334 this.fireEvent("statechange", this, name, value);
16338 * Decodes a string previously encoded with {@link #encodeValue}.
16339 * @param {String} value The value to decode
16340 * @return {Mixed} The decoded value
16342 decodeValue : function(cookie){
16343 var re = /^(a|n|d|b|s|o)\:(.*)$/;
16344 var matches = re.exec(unescape(cookie));
16345 if(!matches || !matches[1]) {
16346 return; // non state cookie
16348 var type = matches[1];
16349 var v = matches[2];
16352 return parseFloat(v);
16354 return new Date(Date.parse(v));
16359 var values = v.split("^");
16360 for(var i = 0, len = values.length; i < len; i++){
16361 all.push(this.decodeValue(values[i]));
16366 var values = v.split("^");
16367 for(var i = 0, len = values.length; i < len; i++){
16368 var kv = values[i].split("=");
16369 all[kv[0]] = this.decodeValue(kv[1]);
16378 * Encodes a value including type information. Decode with {@link #decodeValue}.
16379 * @param {Mixed} value The value to encode
16380 * @return {String} The encoded value
16382 encodeValue : function(v){
16384 if(typeof v == "number"){
16386 }else if(typeof v == "boolean"){
16387 enc = "b:" + (v ? "1" : "0");
16388 }else if(v instanceof Date){
16389 enc = "d:" + v.toGMTString();
16390 }else if(v instanceof Array){
16392 for(var i = 0, len = v.length; i < len; i++){
16393 flat += this.encodeValue(v[i]);
16399 }else if(typeof v == "object"){
16402 if(typeof v[key] != "function"){
16403 flat += key + "=" + this.encodeValue(v[key]) + "^";
16406 enc = "o:" + flat.substring(0, flat.length-1);
16410 return escape(enc);
16416 * Ext JS Library 1.1.1
16417 * Copyright(c) 2006-2007, Ext JS, LLC.
16419 * Originally Released Under LGPL - original licence link has changed is not relivant.
16422 * <script type="text/javascript">
16425 * @class Roo.state.Manager
16426 * This is the global state manager. By default all components that are "state aware" check this class
16427 * for state information if you don't pass them a custom state provider. In order for this class
16428 * to be useful, it must be initialized with a provider when your application initializes.
16430 // in your initialization function
16432 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
16434 // supposed you have a {@link Roo.BorderLayout}
16435 var layout = new Roo.BorderLayout(...);
16436 layout.restoreState();
16437 // or a {Roo.BasicDialog}
16438 var dialog = new Roo.BasicDialog(...);
16439 dialog.restoreState();
16443 Roo.state.Manager = function(){
16444 var provider = new Roo.state.Provider();
16448 * Configures the default state provider for your application
16449 * @param {Provider} stateProvider The state provider to set
16451 setProvider : function(stateProvider){
16452 provider = stateProvider;
16456 * Returns the current value for a key
16457 * @param {String} name The key name
16458 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
16459 * @return {Mixed} The state data
16461 get : function(key, defaultValue){
16462 return provider.get(key, defaultValue);
16466 * Sets the value for a key
16467 * @param {String} name The key name
16468 * @param {Mixed} value The state data
16470 set : function(key, value){
16471 provider.set(key, value);
16475 * Clears a value from the state
16476 * @param {String} name The key name
16478 clear : function(key){
16479 provider.clear(key);
16483 * Gets the currently configured state provider
16484 * @return {Provider} The state provider
16486 getProvider : function(){
16493 * Ext JS Library 1.1.1
16494 * Copyright(c) 2006-2007, Ext JS, LLC.
16496 * Originally Released Under LGPL - original licence link has changed is not relivant.
16499 * <script type="text/javascript">
16502 * @class Roo.state.CookieProvider
16503 * @extends Roo.state.Provider
16504 * The default Provider implementation which saves state via cookies.
16507 var cp = new Roo.state.CookieProvider({
16509 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
16510 domain: "roojs.com"
16512 Roo.state.Manager.setProvider(cp);
16514 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
16515 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
16516 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
16517 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
16518 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
16519 * domain the page is running on including the 'www' like 'www.roojs.com')
16520 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
16522 * Create a new CookieProvider
16523 * @param {Object} config The configuration object
16525 Roo.state.CookieProvider = function(config){
16526 Roo.state.CookieProvider.superclass.constructor.call(this);
16528 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
16529 this.domain = null;
16530 this.secure = false;
16531 Roo.apply(this, config);
16532 this.state = this.readCookies();
16535 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
16537 set : function(name, value){
16538 if(typeof value == "undefined" || value === null){
16542 this.setCookie(name, value);
16543 Roo.state.CookieProvider.superclass.set.call(this, name, value);
16547 clear : function(name){
16548 this.clearCookie(name);
16549 Roo.state.CookieProvider.superclass.clear.call(this, name);
16553 readCookies : function(){
16555 var c = document.cookie + ";";
16556 var re = /\s?(.*?)=(.*?);/g;
16558 while((matches = re.exec(c)) != null){
16559 var name = matches[1];
16560 var value = matches[2];
16561 if(name && name.substring(0,3) == "ys-"){
16562 cookies[name.substr(3)] = this.decodeValue(value);
16569 setCookie : function(name, value){
16570 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
16571 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
16572 ((this.path == null) ? "" : ("; path=" + this.path)) +
16573 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16574 ((this.secure == true) ? "; secure" : "");
16578 clearCookie : function(name){
16579 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
16580 ((this.path == null) ? "" : ("; path=" + this.path)) +
16581 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16582 ((this.secure == true) ? "; secure" : "");
16586 * Ext JS Library 1.1.1
16587 * Copyright(c) 2006-2007, Ext JS, LLC.
16589 * Originally Released Under LGPL - original licence link has changed is not relivant.
16592 * <script type="text/javascript">
16597 * @class Roo.ComponentMgr
16598 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
16601 Roo.ComponentMgr = function(){
16602 var all = new Roo.util.MixedCollection();
16606 * Registers a component.
16607 * @param {Roo.Component} c The component
16609 register : function(c){
16614 * Unregisters a component.
16615 * @param {Roo.Component} c The component
16617 unregister : function(c){
16622 * Returns a component by id
16623 * @param {String} id The component id
16625 get : function(id){
16626 return all.get(id);
16630 * Registers a function that will be called when a specified component is added to ComponentMgr
16631 * @param {String} id The component id
16632 * @param {Funtction} fn The callback function
16633 * @param {Object} scope The scope of the callback
16635 onAvailable : function(id, fn, scope){
16636 all.on("add", function(index, o){
16638 fn.call(scope || o, o);
16639 all.un("add", fn, scope);
16646 * Ext JS Library 1.1.1
16647 * Copyright(c) 2006-2007, Ext JS, LLC.
16649 * Originally Released Under LGPL - original licence link has changed is not relivant.
16652 * <script type="text/javascript">
16656 * @class Roo.Component
16657 * @extends Roo.util.Observable
16658 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
16659 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
16660 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
16661 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
16662 * All visual components (widgets) that require rendering into a layout should subclass Component.
16664 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
16665 * 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
16666 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
16668 Roo.Component = function(config){
16669 config = config || {};
16670 if(config.tagName || config.dom || typeof config == "string"){ // element object
16671 config = {el: config, id: config.id || config};
16673 this.initialConfig = config;
16675 Roo.apply(this, config);
16679 * Fires after the component is disabled.
16680 * @param {Roo.Component} this
16685 * Fires after the component is enabled.
16686 * @param {Roo.Component} this
16690 * @event beforeshow
16691 * Fires before the component is shown. Return false to stop the show.
16692 * @param {Roo.Component} this
16697 * Fires after the component is shown.
16698 * @param {Roo.Component} this
16702 * @event beforehide
16703 * Fires before the component is hidden. Return false to stop the hide.
16704 * @param {Roo.Component} this
16709 * Fires after the component is hidden.
16710 * @param {Roo.Component} this
16714 * @event beforerender
16715 * Fires before the component is rendered. Return false to stop the render.
16716 * @param {Roo.Component} this
16718 beforerender : true,
16721 * Fires after the component is rendered.
16722 * @param {Roo.Component} this
16726 * @event beforedestroy
16727 * Fires before the component is destroyed. Return false to stop the destroy.
16728 * @param {Roo.Component} this
16730 beforedestroy : true,
16733 * Fires after the component is destroyed.
16734 * @param {Roo.Component} this
16739 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
16741 Roo.ComponentMgr.register(this);
16742 Roo.Component.superclass.constructor.call(this);
16743 this.initComponent();
16744 if(this.renderTo){ // not supported by all components yet. use at your own risk!
16745 this.render(this.renderTo);
16746 delete this.renderTo;
16751 Roo.Component.AUTO_ID = 1000;
16753 Roo.extend(Roo.Component, Roo.util.Observable, {
16755 * @scope Roo.Component.prototype
16757 * true if this component is hidden. Read-only.
16762 * true if this component is disabled. Read-only.
16767 * true if this component has been rendered. Read-only.
16771 /** @cfg {String} disableClass
16772 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
16774 disabledClass : "x-item-disabled",
16775 /** @cfg {Boolean} allowDomMove
16776 * Whether the component can move the Dom node when rendering (defaults to true).
16778 allowDomMove : true,
16779 /** @cfg {String} hideMode (display|visibility)
16780 * How this component should hidden. Supported values are
16781 * "visibility" (css visibility), "offsets" (negative offset position) and
16782 * "display" (css display) - defaults to "display".
16784 hideMode: 'display',
16787 ctype : "Roo.Component",
16790 * @cfg {String} actionMode
16791 * which property holds the element that used for hide() / show() / disable() / enable()
16792 * default is 'el' for forms you probably want to set this to fieldEl
16797 getActionEl : function(){
16798 return this[this.actionMode];
16801 initComponent : Roo.emptyFn,
16803 * If this is a lazy rendering component, render it to its container element.
16804 * @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.
16806 render : function(container, position){
16812 if(this.fireEvent("beforerender", this) === false){
16816 if(!container && this.el){
16817 this.el = Roo.get(this.el);
16818 container = this.el.dom.parentNode;
16819 this.allowDomMove = false;
16821 this.container = Roo.get(container);
16822 this.rendered = true;
16823 if(position !== undefined){
16824 if(typeof position == 'number'){
16825 position = this.container.dom.childNodes[position];
16827 position = Roo.getDom(position);
16830 this.onRender(this.container, position || null);
16832 this.el.addClass(this.cls);
16836 this.el.applyStyles(this.style);
16839 this.fireEvent("render", this);
16840 this.afterRender(this.container);
16853 // default function is not really useful
16854 onRender : function(ct, position){
16856 this.el = Roo.get(this.el);
16857 if(this.allowDomMove !== false){
16858 ct.dom.insertBefore(this.el.dom, position);
16864 getAutoCreate : function(){
16865 var cfg = typeof this.autoCreate == "object" ?
16866 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
16867 if(this.id && !cfg.id){
16874 afterRender : Roo.emptyFn,
16877 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
16878 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
16880 destroy : function(){
16881 if(this.fireEvent("beforedestroy", this) !== false){
16882 this.purgeListeners();
16883 this.beforeDestroy();
16885 this.el.removeAllListeners();
16887 if(this.actionMode == "container"){
16888 this.container.remove();
16892 Roo.ComponentMgr.unregister(this);
16893 this.fireEvent("destroy", this);
16898 beforeDestroy : function(){
16903 onDestroy : function(){
16908 * Returns the underlying {@link Roo.Element}.
16909 * @return {Roo.Element} The element
16911 getEl : function(){
16916 * Returns the id of this component.
16919 getId : function(){
16924 * Try to focus this component.
16925 * @param {Boolean} selectText True to also select the text in this component (if applicable)
16926 * @return {Roo.Component} this
16928 focus : function(selectText){
16931 if(selectText === true){
16932 this.el.dom.select();
16947 * Disable this component.
16948 * @return {Roo.Component} this
16950 disable : function(){
16954 this.disabled = true;
16955 this.fireEvent("disable", this);
16960 onDisable : function(){
16961 this.getActionEl().addClass(this.disabledClass);
16962 this.el.dom.disabled = true;
16966 * Enable this component.
16967 * @return {Roo.Component} this
16969 enable : function(){
16973 this.disabled = false;
16974 this.fireEvent("enable", this);
16979 onEnable : function(){
16980 this.getActionEl().removeClass(this.disabledClass);
16981 this.el.dom.disabled = false;
16985 * Convenience function for setting disabled/enabled by boolean.
16986 * @param {Boolean} disabled
16988 setDisabled : function(disabled){
16989 this[disabled ? "disable" : "enable"]();
16993 * Show this component.
16994 * @return {Roo.Component} this
16997 if(this.fireEvent("beforeshow", this) !== false){
16998 this.hidden = false;
17002 this.fireEvent("show", this);
17008 onShow : function(){
17009 var ae = this.getActionEl();
17010 if(this.hideMode == 'visibility'){
17011 ae.dom.style.visibility = "visible";
17012 }else if(this.hideMode == 'offsets'){
17013 ae.removeClass('x-hidden');
17015 ae.dom.style.display = "";
17020 * Hide this component.
17021 * @return {Roo.Component} this
17024 if(this.fireEvent("beforehide", this) !== false){
17025 this.hidden = true;
17029 this.fireEvent("hide", this);
17035 onHide : function(){
17036 var ae = this.getActionEl();
17037 if(this.hideMode == 'visibility'){
17038 ae.dom.style.visibility = "hidden";
17039 }else if(this.hideMode == 'offsets'){
17040 ae.addClass('x-hidden');
17042 ae.dom.style.display = "none";
17047 * Convenience function to hide or show this component by boolean.
17048 * @param {Boolean} visible True to show, false to hide
17049 * @return {Roo.Component} this
17051 setVisible: function(visible){
17061 * Returns true if this component is visible.
17063 isVisible : function(){
17064 return this.getActionEl().isVisible();
17067 cloneConfig : function(overrides){
17068 overrides = overrides || {};
17069 var id = overrides.id || Roo.id();
17070 var cfg = Roo.applyIf(overrides, this.initialConfig);
17071 cfg.id = id; // prevent dup id
17072 return new this.constructor(cfg);
17076 * Ext JS Library 1.1.1
17077 * Copyright(c) 2006-2007, Ext JS, LLC.
17079 * Originally Released Under LGPL - original licence link has changed is not relivant.
17082 * <script type="text/javascript">
17086 * @class Roo.BoxComponent
17087 * @extends Roo.Component
17088 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
17089 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
17090 * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
17091 * layout containers.
17093 * @param {Roo.Element/String/Object} config The configuration options.
17095 Roo.BoxComponent = function(config){
17096 Roo.Component.call(this, config);
17100 * Fires after the component is resized.
17101 * @param {Roo.Component} this
17102 * @param {Number} adjWidth The box-adjusted width that was set
17103 * @param {Number} adjHeight The box-adjusted height that was set
17104 * @param {Number} rawWidth The width that was originally specified
17105 * @param {Number} rawHeight The height that was originally specified
17110 * Fires after the component is moved.
17111 * @param {Roo.Component} this
17112 * @param {Number} x The new x position
17113 * @param {Number} y The new y position
17119 Roo.extend(Roo.BoxComponent, Roo.Component, {
17120 // private, set in afterRender to signify that the component has been rendered
17122 // private, used to defer height settings to subclasses
17123 deferHeight: false,
17124 /** @cfg {Number} width
17125 * width (optional) size of component
17127 /** @cfg {Number} height
17128 * height (optional) size of component
17132 * Sets the width and height of the component. This method fires the resize event. This method can accept
17133 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
17134 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
17135 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
17136 * @return {Roo.BoxComponent} this
17138 setSize : function(w, h){
17139 // support for standard size objects
17140 if(typeof w == 'object'){
17145 if(!this.boxReady){
17151 // prevent recalcs when not needed
17152 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
17155 this.lastSize = {width: w, height: h};
17157 var adj = this.adjustSize(w, h);
17158 var aw = adj.width, ah = adj.height;
17159 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
17160 var rz = this.getResizeEl();
17161 if(!this.deferHeight && aw !== undefined && ah !== undefined){
17162 rz.setSize(aw, ah);
17163 }else if(!this.deferHeight && ah !== undefined){
17165 }else if(aw !== undefined){
17168 this.onResize(aw, ah, w, h);
17169 this.fireEvent('resize', this, aw, ah, w, h);
17175 * Gets the current size of the component's underlying element.
17176 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
17178 getSize : function(){
17179 return this.el.getSize();
17183 * Gets the current XY position of the component's underlying element.
17184 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
17185 * @return {Array} The XY position of the element (e.g., [100, 200])
17187 getPosition : function(local){
17188 if(local === true){
17189 return [this.el.getLeft(true), this.el.getTop(true)];
17191 return this.xy || this.el.getXY();
17195 * Gets the current box measurements of the component's underlying element.
17196 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
17197 * @returns {Object} box An object in the format {x, y, width, height}
17199 getBox : function(local){
17200 var s = this.el.getSize();
17202 s.x = this.el.getLeft(true);
17203 s.y = this.el.getTop(true);
17205 var xy = this.xy || this.el.getXY();
17213 * Sets the current box measurements of the component's underlying element.
17214 * @param {Object} box An object in the format {x, y, width, height}
17215 * @returns {Roo.BoxComponent} this
17217 updateBox : function(box){
17218 this.setSize(box.width, box.height);
17219 this.setPagePosition(box.x, box.y);
17224 getResizeEl : function(){
17225 return this.resizeEl || this.el;
17229 getPositionEl : function(){
17230 return this.positionEl || this.el;
17234 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
17235 * This method fires the move event.
17236 * @param {Number} left The new left
17237 * @param {Number} top The new top
17238 * @returns {Roo.BoxComponent} this
17240 setPosition : function(x, y){
17243 if(!this.boxReady){
17246 var adj = this.adjustPosition(x, y);
17247 var ax = adj.x, ay = adj.y;
17249 var el = this.getPositionEl();
17250 if(ax !== undefined || ay !== undefined){
17251 if(ax !== undefined && ay !== undefined){
17252 el.setLeftTop(ax, ay);
17253 }else if(ax !== undefined){
17255 }else if(ay !== undefined){
17258 this.onPosition(ax, ay);
17259 this.fireEvent('move', this, ax, ay);
17265 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
17266 * This method fires the move event.
17267 * @param {Number} x The new x position
17268 * @param {Number} y The new y position
17269 * @returns {Roo.BoxComponent} this
17271 setPagePosition : function(x, y){
17274 if(!this.boxReady){
17277 if(x === undefined || y === undefined){ // cannot translate undefined points
17280 var p = this.el.translatePoints(x, y);
17281 this.setPosition(p.left, p.top);
17286 onRender : function(ct, position){
17287 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
17289 this.resizeEl = Roo.get(this.resizeEl);
17291 if(this.positionEl){
17292 this.positionEl = Roo.get(this.positionEl);
17297 afterRender : function(){
17298 Roo.BoxComponent.superclass.afterRender.call(this);
17299 this.boxReady = true;
17300 this.setSize(this.width, this.height);
17301 if(this.x || this.y){
17302 this.setPosition(this.x, this.y);
17304 if(this.pageX || this.pageY){
17305 this.setPagePosition(this.pageX, this.pageY);
17310 * Force the component's size to recalculate based on the underlying element's current height and width.
17311 * @returns {Roo.BoxComponent} this
17313 syncSize : function(){
17314 delete this.lastSize;
17315 this.setSize(this.el.getWidth(), this.el.getHeight());
17320 * Called after the component is resized, this method is empty by default but can be implemented by any
17321 * subclass that needs to perform custom logic after a resize occurs.
17322 * @param {Number} adjWidth The box-adjusted width that was set
17323 * @param {Number} adjHeight The box-adjusted height that was set
17324 * @param {Number} rawWidth The width that was originally specified
17325 * @param {Number} rawHeight The height that was originally specified
17327 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
17332 * Called after the component is moved, this method is empty by default but can be implemented by any
17333 * subclass that needs to perform custom logic after a move occurs.
17334 * @param {Number} x The new x position
17335 * @param {Number} y The new y position
17337 onPosition : function(x, y){
17342 adjustSize : function(w, h){
17343 if(this.autoWidth){
17346 if(this.autoHeight){
17349 return {width : w, height: h};
17353 adjustPosition : function(x, y){
17354 return {x : x, y: y};
17358 * Ext JS Library 1.1.1
17359 * Copyright(c) 2006-2007, Ext JS, LLC.
17361 * Originally Released Under LGPL - original licence link has changed is not relivant.
17364 * <script type="text/javascript">
17369 * @extends Roo.Element
17370 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
17371 * automatic maintaining of shadow/shim positions.
17372 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
17373 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
17374 * you can pass a string with a CSS class name. False turns off the shadow.
17375 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
17376 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
17377 * @cfg {String} cls CSS class to add to the element
17378 * @cfg {Number} zindex Starting z-index (defaults to 11000)
17379 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
17381 * @param {Object} config An object with config options.
17382 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
17385 Roo.Layer = function(config, existingEl){
17386 config = config || {};
17387 var dh = Roo.DomHelper;
17388 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
17390 this.dom = Roo.getDom(existingEl);
17393 var o = config.dh || {tag: "div", cls: "x-layer"};
17394 this.dom = dh.append(pel, o);
17397 this.addClass(config.cls);
17399 this.constrain = config.constrain !== false;
17400 this.visibilityMode = Roo.Element.VISIBILITY;
17402 this.id = this.dom.id = config.id;
17404 this.id = Roo.id(this.dom);
17406 this.zindex = config.zindex || this.getZIndex();
17407 this.position("absolute", this.zindex);
17409 this.shadowOffset = config.shadowOffset || 4;
17410 this.shadow = new Roo.Shadow({
17411 offset : this.shadowOffset,
17412 mode : config.shadow
17415 this.shadowOffset = 0;
17417 this.useShim = config.shim !== false && Roo.useShims;
17418 this.useDisplay = config.useDisplay;
17422 var supr = Roo.Element.prototype;
17424 // shims are shared among layer to keep from having 100 iframes
17427 Roo.extend(Roo.Layer, Roo.Element, {
17429 getZIndex : function(){
17430 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
17433 getShim : function(){
17440 var shim = shims.shift();
17442 shim = this.createShim();
17443 shim.enableDisplayMode('block');
17444 shim.dom.style.display = 'none';
17445 shim.dom.style.visibility = 'visible';
17447 var pn = this.dom.parentNode;
17448 if(shim.dom.parentNode != pn){
17449 pn.insertBefore(shim.dom, this.dom);
17451 shim.setStyle('z-index', this.getZIndex()-2);
17456 hideShim : function(){
17458 this.shim.setDisplayed(false);
17459 shims.push(this.shim);
17464 disableShadow : function(){
17466 this.shadowDisabled = true;
17467 this.shadow.hide();
17468 this.lastShadowOffset = this.shadowOffset;
17469 this.shadowOffset = 0;
17473 enableShadow : function(show){
17475 this.shadowDisabled = false;
17476 this.shadowOffset = this.lastShadowOffset;
17477 delete this.lastShadowOffset;
17485 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
17486 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
17487 sync : function(doShow){
17488 var sw = this.shadow;
17489 if(!this.updating && this.isVisible() && (sw || this.useShim)){
17490 var sh = this.getShim();
17492 var w = this.getWidth(),
17493 h = this.getHeight();
17495 var l = this.getLeft(true),
17496 t = this.getTop(true);
17498 if(sw && !this.shadowDisabled){
17499 if(doShow && !sw.isVisible()){
17502 sw.realign(l, t, w, h);
17508 // fit the shim behind the shadow, so it is shimmed too
17509 var a = sw.adjusts, s = sh.dom.style;
17510 s.left = (Math.min(l, l+a.l))+"px";
17511 s.top = (Math.min(t, t+a.t))+"px";
17512 s.width = (w+a.w)+"px";
17513 s.height = (h+a.h)+"px";
17520 sh.setLeftTop(l, t);
17527 destroy : function(){
17530 this.shadow.hide();
17532 this.removeAllListeners();
17533 var pn = this.dom.parentNode;
17535 pn.removeChild(this.dom);
17537 Roo.Element.uncache(this.id);
17540 remove : function(){
17545 beginUpdate : function(){
17546 this.updating = true;
17550 endUpdate : function(){
17551 this.updating = false;
17556 hideUnders : function(negOffset){
17558 this.shadow.hide();
17564 constrainXY : function(){
17565 if(this.constrain){
17566 var vw = Roo.lib.Dom.getViewWidth(),
17567 vh = Roo.lib.Dom.getViewHeight();
17568 var s = Roo.get(document).getScroll();
17570 var xy = this.getXY();
17571 var x = xy[0], y = xy[1];
17572 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
17573 // only move it if it needs it
17575 // first validate right/bottom
17576 if((x + w) > vw+s.left){
17577 x = vw - w - this.shadowOffset;
17580 if((y + h) > vh+s.top){
17581 y = vh - h - this.shadowOffset;
17584 // then make sure top/left isn't negative
17595 var ay = this.avoidY;
17596 if(y <= ay && (y+h) >= ay){
17602 supr.setXY.call(this, xy);
17608 isVisible : function(){
17609 return this.visible;
17613 showAction : function(){
17614 this.visible = true; // track visibility to prevent getStyle calls
17615 if(this.useDisplay === true){
17616 this.setDisplayed("");
17617 }else if(this.lastXY){
17618 supr.setXY.call(this, this.lastXY);
17619 }else if(this.lastLT){
17620 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
17625 hideAction : function(){
17626 this.visible = false;
17627 if(this.useDisplay === true){
17628 this.setDisplayed(false);
17630 this.setLeftTop(-10000,-10000);
17634 // overridden Element method
17635 setVisible : function(v, a, d, c, e){
17640 var cb = function(){
17645 }.createDelegate(this);
17646 supr.setVisible.call(this, true, true, d, cb, e);
17649 this.hideUnders(true);
17658 }.createDelegate(this);
17660 supr.setVisible.call(this, v, a, d, cb, e);
17669 storeXY : function(xy){
17670 delete this.lastLT;
17674 storeLeftTop : function(left, top){
17675 delete this.lastXY;
17676 this.lastLT = [left, top];
17680 beforeFx : function(){
17681 this.beforeAction();
17682 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
17686 afterFx : function(){
17687 Roo.Layer.superclass.afterFx.apply(this, arguments);
17688 this.sync(this.isVisible());
17692 beforeAction : function(){
17693 if(!this.updating && this.shadow){
17694 this.shadow.hide();
17698 // overridden Element method
17699 setLeft : function(left){
17700 this.storeLeftTop(left, this.getTop(true));
17701 supr.setLeft.apply(this, arguments);
17705 setTop : function(top){
17706 this.storeLeftTop(this.getLeft(true), top);
17707 supr.setTop.apply(this, arguments);
17711 setLeftTop : function(left, top){
17712 this.storeLeftTop(left, top);
17713 supr.setLeftTop.apply(this, arguments);
17717 setXY : function(xy, a, d, c, e){
17719 this.beforeAction();
17721 var cb = this.createCB(c);
17722 supr.setXY.call(this, xy, a, d, cb, e);
17729 createCB : function(c){
17740 // overridden Element method
17741 setX : function(x, a, d, c, e){
17742 this.setXY([x, this.getY()], a, d, c, e);
17745 // overridden Element method
17746 setY : function(y, a, d, c, e){
17747 this.setXY([this.getX(), y], a, d, c, e);
17750 // overridden Element method
17751 setSize : function(w, h, a, d, c, e){
17752 this.beforeAction();
17753 var cb = this.createCB(c);
17754 supr.setSize.call(this, w, h, a, d, cb, e);
17760 // overridden Element method
17761 setWidth : function(w, a, d, c, e){
17762 this.beforeAction();
17763 var cb = this.createCB(c);
17764 supr.setWidth.call(this, w, a, d, cb, e);
17770 // overridden Element method
17771 setHeight : function(h, a, d, c, e){
17772 this.beforeAction();
17773 var cb = this.createCB(c);
17774 supr.setHeight.call(this, h, a, d, cb, e);
17780 // overridden Element method
17781 setBounds : function(x, y, w, h, a, d, c, e){
17782 this.beforeAction();
17783 var cb = this.createCB(c);
17785 this.storeXY([x, y]);
17786 supr.setXY.call(this, [x, y]);
17787 supr.setSize.call(this, w, h, a, d, cb, e);
17790 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
17796 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
17797 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
17798 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
17799 * @param {Number} zindex The new z-index to set
17800 * @return {this} The Layer
17802 setZIndex : function(zindex){
17803 this.zindex = zindex;
17804 this.setStyle("z-index", zindex + 2);
17806 this.shadow.setZIndex(zindex + 1);
17809 this.shim.setStyle("z-index", zindex);
17814 * Original code for Roojs - LGPL
17815 * <script type="text/javascript">
17819 * @class Roo.XComponent
17820 * A delayed Element creator...
17821 * Or a way to group chunks of interface together.
17822 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
17823 * used in conjunction with XComponent.build() it will create an instance of each element,
17824 * then call addxtype() to build the User interface.
17826 * Mypart.xyx = new Roo.XComponent({
17828 parent : 'Mypart.xyz', // empty == document.element.!!
17832 disabled : function() {}
17834 tree : function() { // return an tree of xtype declared components
17838 xtype : 'NestedLayoutPanel',
17845 * It can be used to build a big heiracy, with parent etc.
17846 * or you can just use this to render a single compoent to a dom element
17847 * MYPART.render(Roo.Element | String(id) | dom_element )
17854 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
17855 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
17857 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
17859 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
17860 * - if mulitple topModules exist, the last one is defined as the top module.
17864 * When the top level or multiple modules are to embedded into a existing HTML page,
17865 * the parent element can container '#id' of the element where the module will be drawn.
17869 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
17870 * it relies more on a include mechanism, where sub modules are included into an outer page.
17871 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
17873 * Bootstrap Roo Included elements
17875 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
17876 * hence confusing the component builder as it thinks there are multiple top level elements.
17878 * String Over-ride & Translations
17880 * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
17881 * and also the 'overlaying of string values - needed when different versions of the same application with different text content
17882 * are needed. @see Roo.XComponent.overlayString
17886 * @extends Roo.util.Observable
17888 * @param cfg {Object} configuration of component
17891 Roo.XComponent = function(cfg) {
17892 Roo.apply(this, cfg);
17896 * Fires when this the componnt is built
17897 * @param {Roo.XComponent} c the component
17902 this.region = this.region || 'center'; // default..
17903 Roo.XComponent.register(this);
17904 this.modules = false;
17905 this.el = false; // where the layout goes..
17909 Roo.extend(Roo.XComponent, Roo.util.Observable, {
17912 * The created element (with Roo.factory())
17913 * @type {Roo.Layout}
17919 * for BC - use el in new code
17920 * @type {Roo.Layout}
17926 * for BC - use el in new code
17927 * @type {Roo.Layout}
17932 * @cfg {Function|boolean} disabled
17933 * If this module is disabled by some rule, return true from the funtion
17938 * @cfg {String} parent
17939 * Name of parent element which it get xtype added to..
17944 * @cfg {String} order
17945 * Used to set the order in which elements are created (usefull for multiple tabs)
17950 * @cfg {String} name
17951 * String to display while loading.
17955 * @cfg {String} region
17956 * Region to render component to (defaults to center)
17961 * @cfg {Array} items
17962 * A single item array - the first element is the root of the tree..
17963 * It's done this way to stay compatible with the Xtype system...
17969 * The method that retuns the tree of parts that make up this compoennt
17976 * render element to dom or tree
17977 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
17980 render : function(el)
17984 var hp = this.parent ? 1 : 0;
17985 Roo.debug && Roo.log(this);
17987 var tree = this._tree ? this._tree() : this.tree();
17990 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
17991 // if parent is a '#.....' string, then let's use that..
17992 var ename = this.parent.substr(1);
17993 this.parent = false;
17994 Roo.debug && Roo.log(ename);
17996 case 'bootstrap-body':
17997 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
17998 // this is the BorderLayout standard?
17999 this.parent = { el : true };
18002 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
18003 // need to insert stuff...
18005 el : new Roo.bootstrap.layout.Border({
18006 el : document.body,
18012 tabPosition: 'top',
18013 //resizeTabs: true,
18014 alwaysShowTabs: true,
18024 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
18025 this.parent = { el : new Roo.bootstrap.Body() };
18026 Roo.debug && Roo.log("setting el to doc body");
18029 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
18033 this.parent = { el : true};
18036 el = Roo.get(ename);
18037 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
18038 this.parent = { el : true};
18045 if (!el && !this.parent) {
18046 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
18051 Roo.debug && Roo.log("EL:");
18052 Roo.debug && Roo.log(el);
18053 Roo.debug && Roo.log("this.parent.el:");
18054 Roo.debug && Roo.log(this.parent.el);
18057 // altertive root elements ??? - we need a better way to indicate these.
18058 var is_alt = Roo.XComponent.is_alt ||
18059 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
18060 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
18061 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
18065 if (!this.parent && is_alt) {
18066 //el = Roo.get(document.body);
18067 this.parent = { el : true };
18072 if (!this.parent) {
18074 Roo.debug && Roo.log("no parent - creating one");
18076 el = el ? Roo.get(el) : false;
18078 if (typeof(Roo.BorderLayout) == 'undefined' ) {
18081 el : new Roo.bootstrap.layout.Border({
18082 el: el || document.body,
18088 tabPosition: 'top',
18089 //resizeTabs: true,
18090 alwaysShowTabs: false,
18093 overflow: 'visible'
18099 // it's a top level one..
18101 el : new Roo.BorderLayout(el || document.body, {
18106 tabPosition: 'top',
18107 //resizeTabs: true,
18108 alwaysShowTabs: el && hp? false : true,
18109 hideTabs: el || !hp ? true : false,
18117 if (!this.parent.el) {
18118 // probably an old style ctor, which has been disabled.
18122 // The 'tree' method is '_tree now'
18124 tree.region = tree.region || this.region;
18125 var is_body = false;
18126 if (this.parent.el === true) {
18127 // bootstrap... - body..
18131 this.parent.el = Roo.factory(tree);
18135 this.el = this.parent.el.addxtype(tree, undefined, is_body);
18136 this.fireEvent('built', this);
18138 this.panel = this.el;
18139 this.layout = this.panel.layout;
18140 this.parentLayout = this.parent.layout || false;
18146 Roo.apply(Roo.XComponent, {
18148 * @property hideProgress
18149 * true to disable the building progress bar.. usefull on single page renders.
18152 hideProgress : false,
18154 * @property buildCompleted
18155 * True when the builder has completed building the interface.
18158 buildCompleted : false,
18161 * @property topModule
18162 * the upper most module - uses document.element as it's constructor.
18169 * @property modules
18170 * array of modules to be created by registration system.
18171 * @type {Array} of Roo.XComponent
18176 * @property elmodules
18177 * array of modules to be created by which use #ID
18178 * @type {Array} of Roo.XComponent
18185 * Is an alternative Root - normally used by bootstrap or other systems,
18186 * where the top element in the tree can wrap 'body'
18187 * @type {boolean} (default false)
18192 * @property build_from_html
18193 * Build elements from html - used by bootstrap HTML stuff
18194 * - this is cleared after build is completed
18195 * @type {boolean} (default false)
18198 build_from_html : false,
18200 * Register components to be built later.
18202 * This solves the following issues
18203 * - Building is not done on page load, but after an authentication process has occured.
18204 * - Interface elements are registered on page load
18205 * - Parent Interface elements may not be loaded before child, so this handles that..
18212 module : 'Pman.Tab.projectMgr',
18214 parent : 'Pman.layout',
18215 disabled : false, // or use a function..
18218 * * @param {Object} details about module
18220 register : function(obj) {
18222 Roo.XComponent.event.fireEvent('register', obj);
18223 switch(typeof(obj.disabled) ) {
18229 if ( obj.disabled() ) {
18235 if (obj.disabled || obj.region == '#disabled') {
18241 this.modules.push(obj);
18245 * convert a string to an object..
18246 * eg. 'AAA.BBB' -> finds AAA.BBB
18250 toObject : function(str)
18252 if (!str || typeof(str) == 'object') {
18255 if (str.substring(0,1) == '#') {
18259 var ar = str.split('.');
18264 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
18266 throw "Module not found : " + str;
18270 throw "Module not found : " + str;
18272 Roo.each(ar, function(e) {
18273 if (typeof(o[e]) == 'undefined') {
18274 throw "Module not found : " + str;
18285 * move modules into their correct place in the tree..
18288 preBuild : function ()
18291 Roo.each(this.modules , function (obj)
18293 Roo.XComponent.event.fireEvent('beforebuild', obj);
18295 var opar = obj.parent;
18297 obj.parent = this.toObject(opar);
18299 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
18304 Roo.debug && Roo.log("GOT top level module");
18305 Roo.debug && Roo.log(obj);
18306 obj.modules = new Roo.util.MixedCollection(false,
18307 function(o) { return o.order + '' }
18309 this.topModule = obj;
18312 // parent is a string (usually a dom element name..)
18313 if (typeof(obj.parent) == 'string') {
18314 this.elmodules.push(obj);
18317 if (obj.parent.constructor != Roo.XComponent) {
18318 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
18320 if (!obj.parent.modules) {
18321 obj.parent.modules = new Roo.util.MixedCollection(false,
18322 function(o) { return o.order + '' }
18325 if (obj.parent.disabled) {
18326 obj.disabled = true;
18328 obj.parent.modules.add(obj);
18333 * make a list of modules to build.
18334 * @return {Array} list of modules.
18337 buildOrder : function()
18340 var cmp = function(a,b) {
18341 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
18343 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
18344 throw "No top level modules to build";
18347 // make a flat list in order of modules to build.
18348 var mods = this.topModule ? [ this.topModule ] : [];
18351 // elmodules (is a list of DOM based modules )
18352 Roo.each(this.elmodules, function(e) {
18354 if (!this.topModule &&
18355 typeof(e.parent) == 'string' &&
18356 e.parent.substring(0,1) == '#' &&
18357 Roo.get(e.parent.substr(1))
18360 _this.topModule = e;
18366 // add modules to their parents..
18367 var addMod = function(m) {
18368 Roo.debug && Roo.log("build Order: add: " + m.name);
18371 if (m.modules && !m.disabled) {
18372 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
18373 m.modules.keySort('ASC', cmp );
18374 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
18376 m.modules.each(addMod);
18378 Roo.debug && Roo.log("build Order: no child modules");
18380 // not sure if this is used any more..
18382 m.finalize.name = m.name + " (clean up) ";
18383 mods.push(m.finalize);
18387 if (this.topModule && this.topModule.modules) {
18388 this.topModule.modules.keySort('ASC', cmp );
18389 this.topModule.modules.each(addMod);
18395 * Build the registered modules.
18396 * @param {Object} parent element.
18397 * @param {Function} optional method to call after module has been added.
18401 build : function(opts)
18404 if (typeof(opts) != 'undefined') {
18405 Roo.apply(this,opts);
18409 var mods = this.buildOrder();
18411 //this.allmods = mods;
18412 //Roo.debug && Roo.log(mods);
18414 if (!mods.length) { // should not happen
18415 throw "NO modules!!!";
18419 var msg = "Building Interface...";
18420 // flash it up as modal - so we store the mask!?
18421 if (!this.hideProgress && Roo.MessageBox) {
18422 Roo.MessageBox.show({ title: 'loading' });
18423 Roo.MessageBox.show({
18424 title: "Please wait...",
18434 var total = mods.length;
18437 var progressRun = function() {
18438 if (!mods.length) {
18439 Roo.debug && Roo.log('hide?');
18440 if (!this.hideProgress && Roo.MessageBox) {
18441 Roo.MessageBox.hide();
18443 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
18445 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
18451 var m = mods.shift();
18454 Roo.debug && Roo.log(m);
18455 // not sure if this is supported any more.. - modules that are are just function
18456 if (typeof(m) == 'function') {
18458 return progressRun.defer(10, _this);
18462 msg = "Building Interface " + (total - mods.length) +
18464 (m.name ? (' - ' + m.name) : '');
18465 Roo.debug && Roo.log(msg);
18466 if (!_this.hideProgress && Roo.MessageBox) {
18467 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
18471 // is the module disabled?
18472 var disabled = (typeof(m.disabled) == 'function') ?
18473 m.disabled.call(m.module.disabled) : m.disabled;
18477 return progressRun(); // we do not update the display!
18485 // it's 10 on top level, and 1 on others??? why...
18486 return progressRun.defer(10, _this);
18489 progressRun.defer(1, _this);
18495 * Overlay a set of modified strings onto a component
18496 * This is dependant on our builder exporting the strings and 'named strings' elements.
18498 * @param {Object} element to overlay on - eg. Pman.Dialog.Login
18499 * @param {Object} associative array of 'named' string and it's new value.
18502 overlayStrings : function( component, strings )
18504 if (typeof(component['_named_strings']) == 'undefined') {
18505 throw "ERROR: component does not have _named_strings";
18507 for ( var k in strings ) {
18508 var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
18509 if (md !== false) {
18510 component['_strings'][md] = strings[k];
18512 Roo.log('could not find named string: ' + k + ' in');
18513 Roo.log(component);
18528 * wrapper for event.on - aliased later..
18529 * Typically use to register a event handler for register:
18531 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
18540 Roo.XComponent.event = new Roo.util.Observable({
18544 * Fires when an Component is registered,
18545 * set the disable property on the Component to stop registration.
18546 * @param {Roo.XComponent} c the component being registerd.
18551 * @event beforebuild
18552 * Fires before each Component is built
18553 * can be used to apply permissions.
18554 * @param {Roo.XComponent} c the component being registerd.
18557 'beforebuild' : true,
18559 * @event buildcomplete
18560 * Fires on the top level element when all elements have been built
18561 * @param {Roo.XComponent} the top level component.
18563 'buildcomplete' : true
18568 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
18571 * marked - a markdown parser
18572 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
18573 * https://github.com/chjj/marked
18579 * Roo.Markdown - is a very crude wrapper around marked..
18583 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
18585 * Note: move the sample code to the bottom of this
18586 * file before uncommenting it.
18591 Roo.Markdown.toHtml = function(text) {
18593 var c = new Roo.Markdown.marked.setOptions({
18594 renderer: new Roo.Markdown.marked.Renderer(),
18605 text = text.replace(/\\\n/g,' ');
18606 return Roo.Markdown.marked(text);
18611 // Wraps all "globals" so that the only thing
18612 // exposed is makeHtml().
18618 * eval:var:unescape
18626 var escape = function (html, encode) {
18628 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
18629 .replace(/</g, '<')
18630 .replace(/>/g, '>')
18631 .replace(/"/g, '"')
18632 .replace(/'/g, ''');
18635 var unescape = function (html) {
18636 // explicitly match decimal, hex, and named HTML entities
18637 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
18638 n = n.toLowerCase();
18639 if (n === 'colon') { return ':'; }
18640 if (n.charAt(0) === '#') {
18641 return n.charAt(1) === 'x'
18642 ? String.fromCharCode(parseInt(n.substring(2), 16))
18643 : String.fromCharCode(+n.substring(1));
18649 var replace = function (regex, opt) {
18650 regex = regex.source;
18652 return function self(name, val) {
18653 if (!name) { return new RegExp(regex, opt); }
18654 val = val.source || val;
18655 val = val.replace(/(^|[^\[])\^/g, '$1');
18656 regex = regex.replace(name, val);
18665 var noop = function () {}
18671 var merge = function (obj) {
18676 for (; i < arguments.length; i++) {
18677 target = arguments[i];
18678 for (key in target) {
18679 if (Object.prototype.hasOwnProperty.call(target, key)) {
18680 obj[key] = target[key];
18690 * Block-Level Grammar
18698 code: /^( {4}[^\n]+\n*)+/,
18700 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
18701 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
18703 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
18704 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
18705 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
18706 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
18707 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
18709 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
18713 block.bullet = /(?:[*+-]|\d+\.)/;
18714 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
18715 block.item = replace(block.item, 'gm')
18716 (/bull/g, block.bullet)
18719 block.list = replace(block.list)
18720 (/bull/g, block.bullet)
18721 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
18722 ('def', '\\n+(?=' + block.def.source + ')')
18725 block.blockquote = replace(block.blockquote)
18729 block._tag = '(?!(?:'
18730 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
18731 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
18732 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
18734 block.html = replace(block.html)
18735 ('comment', /<!--[\s\S]*?-->/)
18736 ('closed', /<(tag)[\s\S]+?<\/\1>/)
18737 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
18738 (/tag/g, block._tag)
18741 block.paragraph = replace(block.paragraph)
18743 ('heading', block.heading)
18744 ('lheading', block.lheading)
18745 ('blockquote', block.blockquote)
18746 ('tag', '<' + block._tag)
18751 * Normal Block Grammar
18754 block.normal = merge({}, block);
18757 * GFM Block Grammar
18760 block.gfm = merge({}, block.normal, {
18761 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
18763 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
18766 block.gfm.paragraph = replace(block.paragraph)
18768 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
18769 + block.list.source.replace('\\1', '\\3') + '|')
18773 * GFM + Tables Block Grammar
18776 block.tables = merge({}, block.gfm, {
18777 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
18778 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
18785 var Lexer = function (options) {
18787 this.tokens.links = {};
18788 this.options = options || marked.defaults;
18789 this.rules = block.normal;
18791 if (this.options.gfm) {
18792 if (this.options.tables) {
18793 this.rules = block.tables;
18795 this.rules = block.gfm;
18801 * Expose Block Rules
18804 Lexer.rules = block;
18807 * Static Lex Method
18810 Lexer.lex = function(src, options) {
18811 var lexer = new Lexer(options);
18812 return lexer.lex(src);
18819 Lexer.prototype.lex = function(src) {
18821 .replace(/\r\n|\r/g, '\n')
18822 .replace(/\t/g, ' ')
18823 .replace(/\u00a0/g, ' ')
18824 .replace(/\u2424/g, '\n');
18826 return this.token(src, true);
18833 Lexer.prototype.token = function(src, top, bq) {
18834 var src = src.replace(/^ +$/gm, '')
18847 if (cap = this.rules.newline.exec(src)) {
18848 src = src.substring(cap[0].length);
18849 if (cap[0].length > 1) {
18857 if (cap = this.rules.code.exec(src)) {
18858 src = src.substring(cap[0].length);
18859 cap = cap[0].replace(/^ {4}/gm, '');
18862 text: !this.options.pedantic
18863 ? cap.replace(/\n+$/, '')
18870 if (cap = this.rules.fences.exec(src)) {
18871 src = src.substring(cap[0].length);
18881 if (cap = this.rules.heading.exec(src)) {
18882 src = src.substring(cap[0].length);
18885 depth: cap[1].length,
18891 // table no leading pipe (gfm)
18892 if (top && (cap = this.rules.nptable.exec(src))) {
18893 src = src.substring(cap[0].length);
18897 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18898 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18899 cells: cap[3].replace(/\n$/, '').split('\n')
18902 for (i = 0; i < item.align.length; i++) {
18903 if (/^ *-+: *$/.test(item.align[i])) {
18904 item.align[i] = 'right';
18905 } else if (/^ *:-+: *$/.test(item.align[i])) {
18906 item.align[i] = 'center';
18907 } else if (/^ *:-+ *$/.test(item.align[i])) {
18908 item.align[i] = 'left';
18910 item.align[i] = null;
18914 for (i = 0; i < item.cells.length; i++) {
18915 item.cells[i] = item.cells[i].split(/ *\| */);
18918 this.tokens.push(item);
18924 if (cap = this.rules.lheading.exec(src)) {
18925 src = src.substring(cap[0].length);
18928 depth: cap[2] === '=' ? 1 : 2,
18935 if (cap = this.rules.hr.exec(src)) {
18936 src = src.substring(cap[0].length);
18944 if (cap = this.rules.blockquote.exec(src)) {
18945 src = src.substring(cap[0].length);
18948 type: 'blockquote_start'
18951 cap = cap[0].replace(/^ *> ?/gm, '');
18953 // Pass `top` to keep the current
18954 // "toplevel" state. This is exactly
18955 // how markdown.pl works.
18956 this.token(cap, top, true);
18959 type: 'blockquote_end'
18966 if (cap = this.rules.list.exec(src)) {
18967 src = src.substring(cap[0].length);
18971 type: 'list_start',
18972 ordered: bull.length > 1
18975 // Get each top-level item.
18976 cap = cap[0].match(this.rules.item);
18982 for (; i < l; i++) {
18985 // Remove the list item's bullet
18986 // so it is seen as the next token.
18987 space = item.length;
18988 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
18990 // Outdent whatever the
18991 // list item contains. Hacky.
18992 if (~item.indexOf('\n ')) {
18993 space -= item.length;
18994 item = !this.options.pedantic
18995 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
18996 : item.replace(/^ {1,4}/gm, '');
18999 // Determine whether the next list item belongs here.
19000 // Backpedal if it does not belong in this list.
19001 if (this.options.smartLists && i !== l - 1) {
19002 b = block.bullet.exec(cap[i + 1])[0];
19003 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
19004 src = cap.slice(i + 1).join('\n') + src;
19009 // Determine whether item is loose or not.
19010 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
19011 // for discount behavior.
19012 loose = next || /\n\n(?!\s*$)/.test(item);
19014 next = item.charAt(item.length - 1) === '\n';
19015 if (!loose) { loose = next; }
19020 ? 'loose_item_start'
19021 : 'list_item_start'
19025 this.token(item, false, bq);
19028 type: 'list_item_end'
19040 if (cap = this.rules.html.exec(src)) {
19041 src = src.substring(cap[0].length);
19043 type: this.options.sanitize
19046 pre: !this.options.sanitizer
19047 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
19054 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
19055 src = src.substring(cap[0].length);
19056 this.tokens.links[cap[1].toLowerCase()] = {
19064 if (top && (cap = this.rules.table.exec(src))) {
19065 src = src.substring(cap[0].length);
19069 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
19070 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
19071 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
19074 for (i = 0; i < item.align.length; i++) {
19075 if (/^ *-+: *$/.test(item.align[i])) {
19076 item.align[i] = 'right';
19077 } else if (/^ *:-+: *$/.test(item.align[i])) {
19078 item.align[i] = 'center';
19079 } else if (/^ *:-+ *$/.test(item.align[i])) {
19080 item.align[i] = 'left';
19082 item.align[i] = null;
19086 for (i = 0; i < item.cells.length; i++) {
19087 item.cells[i] = item.cells[i]
19088 .replace(/^ *\| *| *\| *$/g, '')
19092 this.tokens.push(item);
19097 // top-level paragraph
19098 if (top && (cap = this.rules.paragraph.exec(src))) {
19099 src = src.substring(cap[0].length);
19102 text: cap[1].charAt(cap[1].length - 1) === '\n'
19103 ? cap[1].slice(0, -1)
19110 if (cap = this.rules.text.exec(src)) {
19111 // Top-level should never reach here.
19112 src = src.substring(cap[0].length);
19122 Error('Infinite loop on byte: ' + src.charCodeAt(0));
19126 return this.tokens;
19130 * Inline-Level Grammar
19134 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
19135 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
19137 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
19138 link: /^!?\[(inside)\]\(href\)/,
19139 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
19140 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
19141 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
19142 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
19143 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
19144 br: /^ {2,}\n(?!\s*$)/,
19146 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
19149 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
19150 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
19152 inline.link = replace(inline.link)
19153 ('inside', inline._inside)
19154 ('href', inline._href)
19157 inline.reflink = replace(inline.reflink)
19158 ('inside', inline._inside)
19162 * Normal Inline Grammar
19165 inline.normal = merge({}, inline);
19168 * Pedantic Inline Grammar
19171 inline.pedantic = merge({}, inline.normal, {
19172 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
19173 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
19177 * GFM Inline Grammar
19180 inline.gfm = merge({}, inline.normal, {
19181 escape: replace(inline.escape)('])', '~|])')(),
19182 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
19183 del: /^~~(?=\S)([\s\S]*?\S)~~/,
19184 text: replace(inline.text)
19186 ('|', '|https?://|')
19191 * GFM + Line Breaks Inline Grammar
19194 inline.breaks = merge({}, inline.gfm, {
19195 br: replace(inline.br)('{2,}', '*')(),
19196 text: replace(inline.gfm.text)('{2,}', '*')()
19200 * Inline Lexer & Compiler
19203 var InlineLexer = function (links, options) {
19204 this.options = options || marked.defaults;
19205 this.links = links;
19206 this.rules = inline.normal;
19207 this.renderer = this.options.renderer || new Renderer;
19208 this.renderer.options = this.options;
19212 Error('Tokens array requires a `links` property.');
19215 if (this.options.gfm) {
19216 if (this.options.breaks) {
19217 this.rules = inline.breaks;
19219 this.rules = inline.gfm;
19221 } else if (this.options.pedantic) {
19222 this.rules = inline.pedantic;
19227 * Expose Inline Rules
19230 InlineLexer.rules = inline;
19233 * Static Lexing/Compiling Method
19236 InlineLexer.output = function(src, links, options) {
19237 var inline = new InlineLexer(links, options);
19238 return inline.output(src);
19245 InlineLexer.prototype.output = function(src) {
19254 if (cap = this.rules.escape.exec(src)) {
19255 src = src.substring(cap[0].length);
19261 if (cap = this.rules.autolink.exec(src)) {
19262 src = src.substring(cap[0].length);
19263 if (cap[2] === '@') {
19264 text = cap[1].charAt(6) === ':'
19265 ? this.mangle(cap[1].substring(7))
19266 : this.mangle(cap[1]);
19267 href = this.mangle('mailto:') + text;
19269 text = escape(cap[1]);
19272 out += this.renderer.link(href, null, text);
19277 if (!this.inLink && (cap = this.rules.url.exec(src))) {
19278 src = src.substring(cap[0].length);
19279 text = escape(cap[1]);
19281 out += this.renderer.link(href, null, text);
19286 if (cap = this.rules.tag.exec(src)) {
19287 if (!this.inLink && /^<a /i.test(cap[0])) {
19288 this.inLink = true;
19289 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
19290 this.inLink = false;
19292 src = src.substring(cap[0].length);
19293 out += this.options.sanitize
19294 ? this.options.sanitizer
19295 ? this.options.sanitizer(cap[0])
19302 if (cap = this.rules.link.exec(src)) {
19303 src = src.substring(cap[0].length);
19304 this.inLink = true;
19305 out += this.outputLink(cap, {
19309 this.inLink = false;
19314 if ((cap = this.rules.reflink.exec(src))
19315 || (cap = this.rules.nolink.exec(src))) {
19316 src = src.substring(cap[0].length);
19317 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
19318 link = this.links[link.toLowerCase()];
19319 if (!link || !link.href) {
19320 out += cap[0].charAt(0);
19321 src = cap[0].substring(1) + src;
19324 this.inLink = true;
19325 out += this.outputLink(cap, link);
19326 this.inLink = false;
19331 if (cap = this.rules.strong.exec(src)) {
19332 src = src.substring(cap[0].length);
19333 out += this.renderer.strong(this.output(cap[2] || cap[1]));
19338 if (cap = this.rules.em.exec(src)) {
19339 src = src.substring(cap[0].length);
19340 out += this.renderer.em(this.output(cap[2] || cap[1]));
19345 if (cap = this.rules.code.exec(src)) {
19346 src = src.substring(cap[0].length);
19347 out += this.renderer.codespan(escape(cap[2], true));
19352 if (cap = this.rules.br.exec(src)) {
19353 src = src.substring(cap[0].length);
19354 out += this.renderer.br();
19359 if (cap = this.rules.del.exec(src)) {
19360 src = src.substring(cap[0].length);
19361 out += this.renderer.del(this.output(cap[1]));
19366 if (cap = this.rules.text.exec(src)) {
19367 src = src.substring(cap[0].length);
19368 out += this.renderer.text(escape(this.smartypants(cap[0])));
19374 Error('Infinite loop on byte: ' + src.charCodeAt(0));
19385 InlineLexer.prototype.outputLink = function(cap, link) {
19386 var href = escape(link.href)
19387 , title = link.title ? escape(link.title) : null;
19389 return cap[0].charAt(0) !== '!'
19390 ? this.renderer.link(href, title, this.output(cap[1]))
19391 : this.renderer.image(href, title, escape(cap[1]));
19395 * Smartypants Transformations
19398 InlineLexer.prototype.smartypants = function(text) {
19399 if (!this.options.smartypants) { return text; }
19402 .replace(/---/g, '\u2014')
19404 .replace(/--/g, '\u2013')
19406 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
19407 // closing singles & apostrophes
19408 .replace(/'/g, '\u2019')
19410 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
19412 .replace(/"/g, '\u201d')
19414 .replace(/\.{3}/g, '\u2026');
19421 InlineLexer.prototype.mangle = function(text) {
19422 if (!this.options.mangle) { return text; }
19428 for (; i < l; i++) {
19429 ch = text.charCodeAt(i);
19430 if (Math.random() > 0.5) {
19431 ch = 'x' + ch.toString(16);
19433 out += '&#' + ch + ';';
19444 * eval:var:Renderer
19447 var Renderer = function (options) {
19448 this.options = options || {};
19451 Renderer.prototype.code = function(code, lang, escaped) {
19452 if (this.options.highlight) {
19453 var out = this.options.highlight(code, lang);
19454 if (out != null && out !== code) {
19459 // hack!!! - it's already escapeD?
19464 return '<pre><code>'
19465 + (escaped ? code : escape(code, true))
19466 + '\n</code></pre>';
19469 return '<pre><code class="'
19470 + this.options.langPrefix
19471 + escape(lang, true)
19473 + (escaped ? code : escape(code, true))
19474 + '\n</code></pre>\n';
19477 Renderer.prototype.blockquote = function(quote) {
19478 return '<blockquote>\n' + quote + '</blockquote>\n';
19481 Renderer.prototype.html = function(html) {
19485 Renderer.prototype.heading = function(text, level, raw) {
19489 + this.options.headerPrefix
19490 + raw.toLowerCase().replace(/[^\w]+/g, '-')
19498 Renderer.prototype.hr = function() {
19499 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
19502 Renderer.prototype.list = function(body, ordered) {
19503 var type = ordered ? 'ol' : 'ul';
19504 return '<' + type + '>\n' + body + '</' + type + '>\n';
19507 Renderer.prototype.listitem = function(text) {
19508 return '<li>' + text + '</li>\n';
19511 Renderer.prototype.paragraph = function(text) {
19512 return '<p>' + text + '</p>\n';
19515 Renderer.prototype.table = function(header, body) {
19516 return '<table class="table table-striped">\n'
19526 Renderer.prototype.tablerow = function(content) {
19527 return '<tr>\n' + content + '</tr>\n';
19530 Renderer.prototype.tablecell = function(content, flags) {
19531 var type = flags.header ? 'th' : 'td';
19532 var tag = flags.align
19533 ? '<' + type + ' style="text-align:' + flags.align + '">'
19534 : '<' + type + '>';
19535 return tag + content + '</' + type + '>\n';
19538 // span level renderer
19539 Renderer.prototype.strong = function(text) {
19540 return '<strong>' + text + '</strong>';
19543 Renderer.prototype.em = function(text) {
19544 return '<em>' + text + '</em>';
19547 Renderer.prototype.codespan = function(text) {
19548 return '<code>' + text + '</code>';
19551 Renderer.prototype.br = function() {
19552 return this.options.xhtml ? '<br/>' : '<br>';
19555 Renderer.prototype.del = function(text) {
19556 return '<del>' + text + '</del>';
19559 Renderer.prototype.link = function(href, title, text) {
19560 if (this.options.sanitize) {
19562 var prot = decodeURIComponent(unescape(href))
19563 .replace(/[^\w:]/g, '')
19568 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
19572 var out = '<a href="' + href + '"';
19574 out += ' title="' + title + '"';
19576 out += '>' + text + '</a>';
19580 Renderer.prototype.image = function(href, title, text) {
19581 var out = '<img src="' + href + '" alt="' + text + '"';
19583 out += ' title="' + title + '"';
19585 out += this.options.xhtml ? '/>' : '>';
19589 Renderer.prototype.text = function(text) {
19594 * Parsing & Compiling
19600 var Parser= function (options) {
19603 this.options = options || marked.defaults;
19604 this.options.renderer = this.options.renderer || new Renderer;
19605 this.renderer = this.options.renderer;
19606 this.renderer.options = this.options;
19610 * Static Parse Method
19613 Parser.parse = function(src, options, renderer) {
19614 var parser = new Parser(options, renderer);
19615 return parser.parse(src);
19622 Parser.prototype.parse = function(src) {
19623 this.inline = new InlineLexer(src.links, this.options, this.renderer);
19624 this.tokens = src.reverse();
19627 while (this.next()) {
19638 Parser.prototype.next = function() {
19639 return this.token = this.tokens.pop();
19643 * Preview Next Token
19646 Parser.prototype.peek = function() {
19647 return this.tokens[this.tokens.length - 1] || 0;
19651 * Parse Text Tokens
19654 Parser.prototype.parseText = function() {
19655 var body = this.token.text;
19657 while (this.peek().type === 'text') {
19658 body += '\n' + this.next().text;
19661 return this.inline.output(body);
19665 * Parse Current Token
19668 Parser.prototype.tok = function() {
19669 switch (this.token.type) {
19674 return this.renderer.hr();
19677 return this.renderer.heading(
19678 this.inline.output(this.token.text),
19683 return this.renderer.code(this.token.text,
19685 this.token.escaped);
19698 for (i = 0; i < this.token.header.length; i++) {
19699 flags = { header: true, align: this.token.align[i] };
19700 cell += this.renderer.tablecell(
19701 this.inline.output(this.token.header[i]),
19702 { header: true, align: this.token.align[i] }
19705 header += this.renderer.tablerow(cell);
19707 for (i = 0; i < this.token.cells.length; i++) {
19708 row = this.token.cells[i];
19711 for (j = 0; j < row.length; j++) {
19712 cell += this.renderer.tablecell(
19713 this.inline.output(row[j]),
19714 { header: false, align: this.token.align[j] }
19718 body += this.renderer.tablerow(cell);
19720 return this.renderer.table(header, body);
19722 case 'blockquote_start': {
19725 while (this.next().type !== 'blockquote_end') {
19726 body += this.tok();
19729 return this.renderer.blockquote(body);
19731 case 'list_start': {
19733 , ordered = this.token.ordered;
19735 while (this.next().type !== 'list_end') {
19736 body += this.tok();
19739 return this.renderer.list(body, ordered);
19741 case 'list_item_start': {
19744 while (this.next().type !== 'list_item_end') {
19745 body += this.token.type === 'text'
19750 return this.renderer.listitem(body);
19752 case 'loose_item_start': {
19755 while (this.next().type !== 'list_item_end') {
19756 body += this.tok();
19759 return this.renderer.listitem(body);
19762 var html = !this.token.pre && !this.options.pedantic
19763 ? this.inline.output(this.token.text)
19765 return this.renderer.html(html);
19767 case 'paragraph': {
19768 return this.renderer.paragraph(this.inline.output(this.token.text));
19771 return this.renderer.paragraph(this.parseText());
19783 var marked = function (src, opt, callback) {
19784 if (callback || typeof opt === 'function') {
19790 opt = merge({}, marked.defaults, opt || {});
19792 var highlight = opt.highlight
19798 tokens = Lexer.lex(src, opt)
19800 return callback(e);
19803 pending = tokens.length;
19807 var done = function(err) {
19809 opt.highlight = highlight;
19810 return callback(err);
19816 out = Parser.parse(tokens, opt);
19821 opt.highlight = highlight;
19825 : callback(null, out);
19828 if (!highlight || highlight.length < 3) {
19832 delete opt.highlight;
19834 if (!pending) { return done(); }
19836 for (; i < tokens.length; i++) {
19838 if (token.type !== 'code') {
19839 return --pending || done();
19841 return highlight(token.text, token.lang, function(err, code) {
19842 if (err) { return done(err); }
19843 if (code == null || code === token.text) {
19844 return --pending || done();
19847 token.escaped = true;
19848 --pending || done();
19856 if (opt) { opt = merge({}, marked.defaults, opt); }
19857 return Parser.parse(Lexer.lex(src, opt), opt);
19859 e.message += '\nPlease report this to https://github.com/chjj/marked.';
19860 if ((opt || marked.defaults).silent) {
19861 return '<p>An error occured:</p><pre>'
19862 + escape(e.message + '', true)
19874 marked.setOptions = function(opt) {
19875 merge(marked.defaults, opt);
19879 marked.defaults = {
19890 langPrefix: 'lang-',
19891 smartypants: false,
19893 renderer: new Renderer,
19901 marked.Parser = Parser;
19902 marked.parser = Parser.parse;
19904 marked.Renderer = Renderer;
19906 marked.Lexer = Lexer;
19907 marked.lexer = Lexer.lex;
19909 marked.InlineLexer = InlineLexer;
19910 marked.inlineLexer = InlineLexer.output;
19912 marked.parse = marked;
19914 Roo.Markdown.marked = marked;
19918 * Ext JS Library 1.1.1
19919 * Copyright(c) 2006-2007, Ext JS, LLC.
19921 * Originally Released Under LGPL - original licence link has changed is not relivant.
19924 * <script type="text/javascript">
19930 * These classes are derivatives of the similarly named classes in the YUI Library.
19931 * The original license:
19932 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
19933 * Code licensed under the BSD License:
19934 * http://developer.yahoo.net/yui/license.txt
19939 var Event=Roo.EventManager;
19940 var Dom=Roo.lib.Dom;
19943 * @class Roo.dd.DragDrop
19944 * @extends Roo.util.Observable
19945 * Defines the interface and base operation of items that that can be
19946 * dragged or can be drop targets. It was designed to be extended, overriding
19947 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
19948 * Up to three html elements can be associated with a DragDrop instance:
19950 * <li>linked element: the element that is passed into the constructor.
19951 * This is the element which defines the boundaries for interaction with
19952 * other DragDrop objects.</li>
19953 * <li>handle element(s): The drag operation only occurs if the element that
19954 * was clicked matches a handle element. By default this is the linked
19955 * element, but there are times that you will want only a portion of the
19956 * linked element to initiate the drag operation, and the setHandleElId()
19957 * method provides a way to define this.</li>
19958 * <li>drag element: this represents the element that would be moved along
19959 * with the cursor during a drag operation. By default, this is the linked
19960 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
19961 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
19964 * This class should not be instantiated until the onload event to ensure that
19965 * the associated elements are available.
19966 * The following would define a DragDrop obj that would interact with any
19967 * other DragDrop obj in the "group1" group:
19969 * dd = new Roo.dd.DragDrop("div1", "group1");
19971 * Since none of the event handlers have been implemented, nothing would
19972 * actually happen if you were to run the code above. Normally you would
19973 * override this class or one of the default implementations, but you can
19974 * also override the methods you want on an instance of the class...
19976 * dd.onDragDrop = function(e, id) {
19977 * alert("dd was dropped on " + id);
19981 * @param {String} id of the element that is linked to this instance
19982 * @param {String} sGroup the group of related DragDrop objects
19983 * @param {object} config an object containing configurable attributes
19984 * Valid properties for DragDrop:
19985 * padding, isTarget, maintainOffset, primaryButtonOnly
19987 Roo.dd.DragDrop = function(id, sGroup, config) {
19989 this.init(id, sGroup, config);
19994 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
19997 * The id of the element associated with this object. This is what we
19998 * refer to as the "linked element" because the size and position of
19999 * this element is used to determine when the drag and drop objects have
20007 * Configuration attributes passed into the constructor
20014 * The id of the element that will be dragged. By default this is same
20015 * as the linked element , but could be changed to another element. Ex:
20017 * @property dragElId
20024 * the id of the element that initiates the drag operation. By default
20025 * this is the linked element, but could be changed to be a child of this
20026 * element. This lets us do things like only starting the drag when the
20027 * header element within the linked html element is clicked.
20028 * @property handleElId
20035 * An associative array of HTML tags that will be ignored if clicked.
20036 * @property invalidHandleTypes
20037 * @type {string: string}
20039 invalidHandleTypes: null,
20042 * An associative array of ids for elements that will be ignored if clicked
20043 * @property invalidHandleIds
20044 * @type {string: string}
20046 invalidHandleIds: null,
20049 * An indexted array of css class names for elements that will be ignored
20051 * @property invalidHandleClasses
20054 invalidHandleClasses: null,
20057 * The linked element's absolute X position at the time the drag was
20059 * @property startPageX
20066 * The linked element's absolute X position at the time the drag was
20068 * @property startPageY
20075 * The group defines a logical collection of DragDrop objects that are
20076 * related. Instances only get events when interacting with other
20077 * DragDrop object in the same group. This lets us define multiple
20078 * groups using a single DragDrop subclass if we want.
20080 * @type {string: string}
20085 * Individual drag/drop instances can be locked. This will prevent
20086 * onmousedown start drag.
20094 * Lock this instance
20097 lock: function() { this.locked = true; },
20100 * Unlock this instace
20103 unlock: function() { this.locked = false; },
20106 * By default, all insances can be a drop target. This can be disabled by
20107 * setting isTarget to false.
20114 * The padding configured for this drag and drop object for calculating
20115 * the drop zone intersection with this object.
20122 * Cached reference to the linked element
20123 * @property _domRef
20129 * Internal typeof flag
20130 * @property __ygDragDrop
20133 __ygDragDrop: true,
20136 * Set to true when horizontal contraints are applied
20137 * @property constrainX
20144 * Set to true when vertical contraints are applied
20145 * @property constrainY
20152 * The left constraint
20160 * The right constraint
20168 * The up constraint
20177 * The down constraint
20185 * Maintain offsets when we resetconstraints. Set to true when you want
20186 * the position of the element relative to its parent to stay the same
20187 * when the page changes
20189 * @property maintainOffset
20192 maintainOffset: false,
20195 * Array of pixel locations the element will snap to if we specified a
20196 * horizontal graduation/interval. This array is generated automatically
20197 * when you define a tick interval.
20204 * Array of pixel locations the element will snap to if we specified a
20205 * vertical graduation/interval. This array is generated automatically
20206 * when you define a tick interval.
20213 * By default the drag and drop instance will only respond to the primary
20214 * button click (left button for a right-handed mouse). Set to true to
20215 * allow drag and drop to start with any mouse click that is propogated
20217 * @property primaryButtonOnly
20220 primaryButtonOnly: true,
20223 * The availabe property is false until the linked dom element is accessible.
20224 * @property available
20230 * By default, drags can only be initiated if the mousedown occurs in the
20231 * region the linked element is. This is done in part to work around a
20232 * bug in some browsers that mis-report the mousedown if the previous
20233 * mouseup happened outside of the window. This property is set to true
20234 * if outer handles are defined.
20236 * @property hasOuterHandles
20240 hasOuterHandles: false,
20243 * Code that executes immediately before the startDrag event
20244 * @method b4StartDrag
20247 b4StartDrag: function(x, y) { },
20250 * Abstract method called after a drag/drop object is clicked
20251 * and the drag or mousedown time thresholds have beeen met.
20252 * @method startDrag
20253 * @param {int} X click location
20254 * @param {int} Y click location
20256 startDrag: function(x, y) { /* override this */ },
20259 * Code that executes immediately before the onDrag event
20263 b4Drag: function(e) { },
20266 * Abstract method called during the onMouseMove event while dragging an
20269 * @param {Event} e the mousemove event
20271 onDrag: function(e) { /* override this */ },
20274 * Abstract method called when this element fist begins hovering over
20275 * another DragDrop obj
20276 * @method onDragEnter
20277 * @param {Event} e the mousemove event
20278 * @param {String|DragDrop[]} id In POINT mode, the element
20279 * id this is hovering over. In INTERSECT mode, an array of one or more
20280 * dragdrop items being hovered over.
20282 onDragEnter: function(e, id) { /* override this */ },
20285 * Code that executes immediately before the onDragOver event
20286 * @method b4DragOver
20289 b4DragOver: function(e) { },
20292 * Abstract method called when this element is hovering over another
20294 * @method onDragOver
20295 * @param {Event} e the mousemove event
20296 * @param {String|DragDrop[]} id In POINT mode, the element
20297 * id this is hovering over. In INTERSECT mode, an array of dd items
20298 * being hovered over.
20300 onDragOver: function(e, id) { /* override this */ },
20303 * Code that executes immediately before the onDragOut event
20304 * @method b4DragOut
20307 b4DragOut: function(e) { },
20310 * Abstract method called when we are no longer hovering over an element
20311 * @method onDragOut
20312 * @param {Event} e the mousemove event
20313 * @param {String|DragDrop[]} id In POINT mode, the element
20314 * id this was hovering over. In INTERSECT mode, an array of dd items
20315 * that the mouse is no longer over.
20317 onDragOut: function(e, id) { /* override this */ },
20320 * Code that executes immediately before the onDragDrop event
20321 * @method b4DragDrop
20324 b4DragDrop: function(e) { },
20327 * Abstract method called when this item is dropped on another DragDrop
20329 * @method onDragDrop
20330 * @param {Event} e the mouseup event
20331 * @param {String|DragDrop[]} id In POINT mode, the element
20332 * id this was dropped on. In INTERSECT mode, an array of dd items this
20335 onDragDrop: function(e, id) { /* override this */ },
20338 * Abstract method called when this item is dropped on an area with no
20340 * @method onInvalidDrop
20341 * @param {Event} e the mouseup event
20343 onInvalidDrop: function(e) { /* override this */ },
20346 * Code that executes immediately before the endDrag event
20347 * @method b4EndDrag
20350 b4EndDrag: function(e) { },
20353 * Fired when we are done dragging the object
20355 * @param {Event} e the mouseup event
20357 endDrag: function(e) { /* override this */ },
20360 * Code executed immediately before the onMouseDown event
20361 * @method b4MouseDown
20362 * @param {Event} e the mousedown event
20365 b4MouseDown: function(e) { },
20368 * Event handler that fires when a drag/drop obj gets a mousedown
20369 * @method onMouseDown
20370 * @param {Event} e the mousedown event
20372 onMouseDown: function(e) { /* override this */ },
20375 * Event handler that fires when a drag/drop obj gets a mouseup
20376 * @method onMouseUp
20377 * @param {Event} e the mouseup event
20379 onMouseUp: function(e) { /* override this */ },
20382 * Override the onAvailable method to do what is needed after the initial
20383 * position was determined.
20384 * @method onAvailable
20386 onAvailable: function () {
20390 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
20393 defaultPadding : {left:0, right:0, top:0, bottom:0},
20396 * Initializes the drag drop object's constraints to restrict movement to a certain element.
20400 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
20401 { dragElId: "existingProxyDiv" });
20402 dd.startDrag = function(){
20403 this.constrainTo("parent-id");
20406 * Or you can initalize it using the {@link Roo.Element} object:
20408 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
20409 startDrag : function(){
20410 this.constrainTo("parent-id");
20414 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
20415 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
20416 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
20417 * an object containing the sides to pad. For example: {right:10, bottom:10}
20418 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
20420 constrainTo : function(constrainTo, pad, inContent){
20421 if(typeof pad == "number"){
20422 pad = {left: pad, right:pad, top:pad, bottom:pad};
20424 pad = pad || this.defaultPadding;
20425 var b = Roo.get(this.getEl()).getBox();
20426 var ce = Roo.get(constrainTo);
20427 var s = ce.getScroll();
20428 var c, cd = ce.dom;
20429 if(cd == document.body){
20430 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
20433 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
20437 var topSpace = b.y - c.y;
20438 var leftSpace = b.x - c.x;
20440 this.resetConstraints();
20441 this.setXConstraint(leftSpace - (pad.left||0), // left
20442 c.width - leftSpace - b.width - (pad.right||0) //right
20444 this.setYConstraint(topSpace - (pad.top||0), //top
20445 c.height - topSpace - b.height - (pad.bottom||0) //bottom
20450 * Returns a reference to the linked element
20452 * @return {HTMLElement} the html element
20454 getEl: function() {
20455 if (!this._domRef) {
20456 this._domRef = Roo.getDom(this.id);
20459 return this._domRef;
20463 * Returns a reference to the actual element to drag. By default this is
20464 * the same as the html element, but it can be assigned to another
20465 * element. An example of this can be found in Roo.dd.DDProxy
20466 * @method getDragEl
20467 * @return {HTMLElement} the html element
20469 getDragEl: function() {
20470 return Roo.getDom(this.dragElId);
20474 * Sets up the DragDrop object. Must be called in the constructor of any
20475 * Roo.dd.DragDrop subclass
20477 * @param id the id of the linked element
20478 * @param {String} sGroup the group of related items
20479 * @param {object} config configuration attributes
20481 init: function(id, sGroup, config) {
20482 this.initTarget(id, sGroup, config);
20483 if (!Roo.isTouch) {
20484 Event.on(this.id, "mousedown", this.handleMouseDown, this);
20486 Event.on(this.id, "touchstart", this.handleMouseDown, this);
20487 // Event.on(this.id, "selectstart", Event.preventDefault);
20491 * Initializes Targeting functionality only... the object does not
20492 * get a mousedown handler.
20493 * @method initTarget
20494 * @param id the id of the linked element
20495 * @param {String} sGroup the group of related items
20496 * @param {object} config configuration attributes
20498 initTarget: function(id, sGroup, config) {
20500 // configuration attributes
20501 this.config = config || {};
20503 // create a local reference to the drag and drop manager
20504 this.DDM = Roo.dd.DDM;
20505 // initialize the groups array
20508 // assume that we have an element reference instead of an id if the
20509 // parameter is not a string
20510 if (typeof id !== "string") {
20517 // add to an interaction group
20518 this.addToGroup((sGroup) ? sGroup : "default");
20520 // We don't want to register this as the handle with the manager
20521 // so we just set the id rather than calling the setter.
20522 this.handleElId = id;
20524 // the linked element is the element that gets dragged by default
20525 this.setDragElId(id);
20527 // by default, clicked anchors will not start drag operations.
20528 this.invalidHandleTypes = { A: "A" };
20529 this.invalidHandleIds = {};
20530 this.invalidHandleClasses = [];
20532 this.applyConfig();
20534 this.handleOnAvailable();
20538 * Applies the configuration parameters that were passed into the constructor.
20539 * This is supposed to happen at each level through the inheritance chain. So
20540 * a DDProxy implentation will execute apply config on DDProxy, DD, and
20541 * DragDrop in order to get all of the parameters that are available in
20543 * @method applyConfig
20545 applyConfig: function() {
20547 // configurable properties:
20548 // padding, isTarget, maintainOffset, primaryButtonOnly
20549 this.padding = this.config.padding || [0, 0, 0, 0];
20550 this.isTarget = (this.config.isTarget !== false);
20551 this.maintainOffset = (this.config.maintainOffset);
20552 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
20557 * Executed when the linked element is available
20558 * @method handleOnAvailable
20561 handleOnAvailable: function() {
20562 this.available = true;
20563 this.resetConstraints();
20564 this.onAvailable();
20568 * Configures the padding for the target zone in px. Effectively expands
20569 * (or reduces) the virtual object size for targeting calculations.
20570 * Supports css-style shorthand; if only one parameter is passed, all sides
20571 * will have that padding, and if only two are passed, the top and bottom
20572 * will have the first param, the left and right the second.
20573 * @method setPadding
20574 * @param {int} iTop Top pad
20575 * @param {int} iRight Right pad
20576 * @param {int} iBot Bot pad
20577 * @param {int} iLeft Left pad
20579 setPadding: function(iTop, iRight, iBot, iLeft) {
20580 // this.padding = [iLeft, iRight, iTop, iBot];
20581 if (!iRight && 0 !== iRight) {
20582 this.padding = [iTop, iTop, iTop, iTop];
20583 } else if (!iBot && 0 !== iBot) {
20584 this.padding = [iTop, iRight, iTop, iRight];
20586 this.padding = [iTop, iRight, iBot, iLeft];
20591 * Stores the initial placement of the linked element.
20592 * @method setInitialPosition
20593 * @param {int} diffX the X offset, default 0
20594 * @param {int} diffY the Y offset, default 0
20596 setInitPosition: function(diffX, diffY) {
20597 var el = this.getEl();
20599 if (!this.DDM.verifyEl(el)) {
20603 var dx = diffX || 0;
20604 var dy = diffY || 0;
20606 var p = Dom.getXY( el );
20608 this.initPageX = p[0] - dx;
20609 this.initPageY = p[1] - dy;
20611 this.lastPageX = p[0];
20612 this.lastPageY = p[1];
20615 this.setStartPosition(p);
20619 * Sets the start position of the element. This is set when the obj
20620 * is initialized, the reset when a drag is started.
20621 * @method setStartPosition
20622 * @param pos current position (from previous lookup)
20625 setStartPosition: function(pos) {
20626 var p = pos || Dom.getXY( this.getEl() );
20627 this.deltaSetXY = null;
20629 this.startPageX = p[0];
20630 this.startPageY = p[1];
20634 * Add this instance to a group of related drag/drop objects. All
20635 * instances belong to at least one group, and can belong to as many
20636 * groups as needed.
20637 * @method addToGroup
20638 * @param sGroup {string} the name of the group
20640 addToGroup: function(sGroup) {
20641 this.groups[sGroup] = true;
20642 this.DDM.regDragDrop(this, sGroup);
20646 * Remove's this instance from the supplied interaction group
20647 * @method removeFromGroup
20648 * @param {string} sGroup The group to drop
20650 removeFromGroup: function(sGroup) {
20651 if (this.groups[sGroup]) {
20652 delete this.groups[sGroup];
20655 this.DDM.removeDDFromGroup(this, sGroup);
20659 * Allows you to specify that an element other than the linked element
20660 * will be moved with the cursor during a drag
20661 * @method setDragElId
20662 * @param id {string} the id of the element that will be used to initiate the drag
20664 setDragElId: function(id) {
20665 this.dragElId = id;
20669 * Allows you to specify a child of the linked element that should be
20670 * used to initiate the drag operation. An example of this would be if
20671 * you have a content div with text and links. Clicking anywhere in the
20672 * content area would normally start the drag operation. Use this method
20673 * to specify that an element inside of the content div is the element
20674 * that starts the drag operation.
20675 * @method setHandleElId
20676 * @param id {string} the id of the element that will be used to
20677 * initiate the drag.
20679 setHandleElId: function(id) {
20680 if (typeof id !== "string") {
20683 this.handleElId = id;
20684 this.DDM.regHandle(this.id, id);
20688 * Allows you to set an element outside of the linked element as a drag
20690 * @method setOuterHandleElId
20691 * @param id the id of the element that will be used to initiate the drag
20693 setOuterHandleElId: function(id) {
20694 if (typeof id !== "string") {
20697 Event.on(id, "mousedown",
20698 this.handleMouseDown, this);
20699 this.setHandleElId(id);
20701 this.hasOuterHandles = true;
20705 * Remove all drag and drop hooks for this element
20708 unreg: function() {
20709 Event.un(this.id, "mousedown",
20710 this.handleMouseDown);
20711 Event.un(this.id, "touchstart",
20712 this.handleMouseDown);
20713 this._domRef = null;
20714 this.DDM._remove(this);
20717 destroy : function(){
20722 * Returns true if this instance is locked, or the drag drop mgr is locked
20723 * (meaning that all drag/drop is disabled on the page.)
20725 * @return {boolean} true if this obj or all drag/drop is locked, else
20728 isLocked: function() {
20729 return (this.DDM.isLocked() || this.locked);
20733 * Fired when this object is clicked
20734 * @method handleMouseDown
20736 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
20739 handleMouseDown: function(e, oDD){
20741 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
20742 //Roo.log('not touch/ button !=0');
20745 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
20746 return; // double touch..
20750 if (this.isLocked()) {
20751 //Roo.log('locked');
20755 this.DDM.refreshCache(this.groups);
20756 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
20757 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
20758 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
20759 //Roo.log('no outer handes or not over target');
20762 // Roo.log('check validator');
20763 if (this.clickValidator(e)) {
20764 // Roo.log('validate success');
20765 // set the initial element position
20766 this.setStartPosition();
20769 this.b4MouseDown(e);
20770 this.onMouseDown(e);
20772 this.DDM.handleMouseDown(e, this);
20774 this.DDM.stopEvent(e);
20782 clickValidator: function(e) {
20783 var target = e.getTarget();
20784 return ( this.isValidHandleChild(target) &&
20785 (this.id == this.handleElId ||
20786 this.DDM.handleWasClicked(target, this.id)) );
20790 * Allows you to specify a tag name that should not start a drag operation
20791 * when clicked. This is designed to facilitate embedding links within a
20792 * drag handle that do something other than start the drag.
20793 * @method addInvalidHandleType
20794 * @param {string} tagName the type of element to exclude
20796 addInvalidHandleType: function(tagName) {
20797 var type = tagName.toUpperCase();
20798 this.invalidHandleTypes[type] = type;
20802 * Lets you to specify an element id for a child of a drag handle
20803 * that should not initiate a drag
20804 * @method addInvalidHandleId
20805 * @param {string} id the element id of the element you wish to ignore
20807 addInvalidHandleId: function(id) {
20808 if (typeof id !== "string") {
20811 this.invalidHandleIds[id] = id;
20815 * Lets you specify a css class of elements that will not initiate a drag
20816 * @method addInvalidHandleClass
20817 * @param {string} cssClass the class of the elements you wish to ignore
20819 addInvalidHandleClass: function(cssClass) {
20820 this.invalidHandleClasses.push(cssClass);
20824 * Unsets an excluded tag name set by addInvalidHandleType
20825 * @method removeInvalidHandleType
20826 * @param {string} tagName the type of element to unexclude
20828 removeInvalidHandleType: function(tagName) {
20829 var type = tagName.toUpperCase();
20830 // this.invalidHandleTypes[type] = null;
20831 delete this.invalidHandleTypes[type];
20835 * Unsets an invalid handle id
20836 * @method removeInvalidHandleId
20837 * @param {string} id the id of the element to re-enable
20839 removeInvalidHandleId: function(id) {
20840 if (typeof id !== "string") {
20843 delete this.invalidHandleIds[id];
20847 * Unsets an invalid css class
20848 * @method removeInvalidHandleClass
20849 * @param {string} cssClass the class of the element(s) you wish to
20852 removeInvalidHandleClass: function(cssClass) {
20853 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
20854 if (this.invalidHandleClasses[i] == cssClass) {
20855 delete this.invalidHandleClasses[i];
20861 * Checks the tag exclusion list to see if this click should be ignored
20862 * @method isValidHandleChild
20863 * @param {HTMLElement} node the HTMLElement to evaluate
20864 * @return {boolean} true if this is a valid tag type, false if not
20866 isValidHandleChild: function(node) {
20869 // var n = (node.nodeName == "#text") ? node.parentNode : node;
20872 nodeName = node.nodeName.toUpperCase();
20874 nodeName = node.nodeName;
20876 valid = valid && !this.invalidHandleTypes[nodeName];
20877 valid = valid && !this.invalidHandleIds[node.id];
20879 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
20880 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
20889 * Create the array of horizontal tick marks if an interval was specified
20890 * in setXConstraint().
20891 * @method setXTicks
20894 setXTicks: function(iStartX, iTickSize) {
20896 this.xTickSize = iTickSize;
20900 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
20902 this.xTicks[this.xTicks.length] = i;
20907 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
20909 this.xTicks[this.xTicks.length] = i;
20914 this.xTicks.sort(this.DDM.numericSort) ;
20918 * Create the array of vertical tick marks if an interval was specified in
20919 * setYConstraint().
20920 * @method setYTicks
20923 setYTicks: function(iStartY, iTickSize) {
20925 this.yTickSize = iTickSize;
20929 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
20931 this.yTicks[this.yTicks.length] = i;
20936 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
20938 this.yTicks[this.yTicks.length] = i;
20943 this.yTicks.sort(this.DDM.numericSort) ;
20947 * By default, the element can be dragged any place on the screen. Use
20948 * this method to limit the horizontal travel of the element. Pass in
20949 * 0,0 for the parameters if you want to lock the drag to the y axis.
20950 * @method setXConstraint
20951 * @param {int} iLeft the number of pixels the element can move to the left
20952 * @param {int} iRight the number of pixels the element can move to the
20954 * @param {int} iTickSize optional parameter for specifying that the
20956 * should move iTickSize pixels at a time.
20958 setXConstraint: function(iLeft, iRight, iTickSize) {
20959 this.leftConstraint = iLeft;
20960 this.rightConstraint = iRight;
20962 this.minX = this.initPageX - iLeft;
20963 this.maxX = this.initPageX + iRight;
20964 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
20966 this.constrainX = true;
20970 * Clears any constraints applied to this instance. Also clears ticks
20971 * since they can't exist independent of a constraint at this time.
20972 * @method clearConstraints
20974 clearConstraints: function() {
20975 this.constrainX = false;
20976 this.constrainY = false;
20981 * Clears any tick interval defined for this instance
20982 * @method clearTicks
20984 clearTicks: function() {
20985 this.xTicks = null;
20986 this.yTicks = null;
20987 this.xTickSize = 0;
20988 this.yTickSize = 0;
20992 * By default, the element can be dragged any place on the screen. Set
20993 * this to limit the vertical travel of the element. Pass in 0,0 for the
20994 * parameters if you want to lock the drag to the x axis.
20995 * @method setYConstraint
20996 * @param {int} iUp the number of pixels the element can move up
20997 * @param {int} iDown the number of pixels the element can move down
20998 * @param {int} iTickSize optional parameter for specifying that the
20999 * element should move iTickSize pixels at a time.
21001 setYConstraint: function(iUp, iDown, iTickSize) {
21002 this.topConstraint = iUp;
21003 this.bottomConstraint = iDown;
21005 this.minY = this.initPageY - iUp;
21006 this.maxY = this.initPageY + iDown;
21007 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
21009 this.constrainY = true;
21014 * resetConstraints must be called if you manually reposition a dd element.
21015 * @method resetConstraints
21016 * @param {boolean} maintainOffset
21018 resetConstraints: function() {
21021 // Maintain offsets if necessary
21022 if (this.initPageX || this.initPageX === 0) {
21023 // figure out how much this thing has moved
21024 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
21025 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
21027 this.setInitPosition(dx, dy);
21029 // This is the first time we have detected the element's position
21031 this.setInitPosition();
21034 if (this.constrainX) {
21035 this.setXConstraint( this.leftConstraint,
21036 this.rightConstraint,
21040 if (this.constrainY) {
21041 this.setYConstraint( this.topConstraint,
21042 this.bottomConstraint,
21048 * Normally the drag element is moved pixel by pixel, but we can specify
21049 * that it move a number of pixels at a time. This method resolves the
21050 * location when we have it set up like this.
21052 * @param {int} val where we want to place the object
21053 * @param {int[]} tickArray sorted array of valid points
21054 * @return {int} the closest tick
21057 getTick: function(val, tickArray) {
21060 // If tick interval is not defined, it is effectively 1 pixel,
21061 // so we return the value passed to us.
21063 } else if (tickArray[0] >= val) {
21064 // The value is lower than the first tick, so we return the first
21066 return tickArray[0];
21068 for (var i=0, len=tickArray.length; i<len; ++i) {
21070 if (tickArray[next] && tickArray[next] >= val) {
21071 var diff1 = val - tickArray[i];
21072 var diff2 = tickArray[next] - val;
21073 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
21077 // The value is larger than the last tick, so we return the last
21079 return tickArray[tickArray.length - 1];
21086 * @return {string} string representation of the dd obj
21088 toString: function() {
21089 return ("DragDrop " + this.id);
21097 * Ext JS Library 1.1.1
21098 * Copyright(c) 2006-2007, Ext JS, LLC.
21100 * Originally Released Under LGPL - original licence link has changed is not relivant.
21103 * <script type="text/javascript">
21108 * The drag and drop utility provides a framework for building drag and drop
21109 * applications. In addition to enabling drag and drop for specific elements,
21110 * the drag and drop elements are tracked by the manager class, and the
21111 * interactions between the various elements are tracked during the drag and
21112 * the implementing code is notified about these important moments.
21115 // Only load the library once. Rewriting the manager class would orphan
21116 // existing drag and drop instances.
21117 if (!Roo.dd.DragDropMgr) {
21120 * @class Roo.dd.DragDropMgr
21121 * DragDropMgr is a singleton that tracks the element interaction for
21122 * all DragDrop items in the window. Generally, you will not call
21123 * this class directly, but it does have helper methods that could
21124 * be useful in your DragDrop implementations.
21127 Roo.dd.DragDropMgr = function() {
21129 var Event = Roo.EventManager;
21134 * Two dimensional Array of registered DragDrop objects. The first
21135 * dimension is the DragDrop item group, the second the DragDrop
21138 * @type {string: string}
21145 * Array of element ids defined as drag handles. Used to determine
21146 * if the element that generated the mousedown event is actually the
21147 * handle and not the html element itself.
21148 * @property handleIds
21149 * @type {string: string}
21156 * the DragDrop object that is currently being dragged
21157 * @property dragCurrent
21165 * the DragDrop object(s) that are being hovered over
21166 * @property dragOvers
21174 * the X distance between the cursor and the object being dragged
21183 * the Y distance between the cursor and the object being dragged
21192 * Flag to determine if we should prevent the default behavior of the
21193 * events we define. By default this is true, but this can be set to
21194 * false if you need the default behavior (not recommended)
21195 * @property preventDefault
21199 preventDefault: true,
21202 * Flag to determine if we should stop the propagation of the events
21203 * we generate. This is true by default but you may want to set it to
21204 * false if the html element contains other features that require the
21206 * @property stopPropagation
21210 stopPropagation: true,
21213 * Internal flag that is set to true when drag and drop has been
21215 * @property initialized
21222 * All drag and drop can be disabled.
21230 * Called the first time an element is registered.
21236 this.initialized = true;
21240 * In point mode, drag and drop interaction is defined by the
21241 * location of the cursor during the drag/drop
21249 * In intersect mode, drag and drop interactio nis defined by the
21250 * overlap of two or more drag and drop objects.
21251 * @property INTERSECT
21258 * The current drag and drop mode. Default: POINT
21266 * Runs method on all drag and drop objects
21267 * @method _execOnAll
21271 _execOnAll: function(sMethod, args) {
21272 for (var i in this.ids) {
21273 for (var j in this.ids[i]) {
21274 var oDD = this.ids[i][j];
21275 if (! this.isTypeOfDD(oDD)) {
21278 oDD[sMethod].apply(oDD, args);
21284 * Drag and drop initialization. Sets up the global event handlers
21289 _onLoad: function() {
21293 if (!Roo.isTouch) {
21294 Event.on(document, "mouseup", this.handleMouseUp, this, true);
21295 Event.on(document, "mousemove", this.handleMouseMove, this, true);
21297 Event.on(document, "touchend", this.handleMouseUp, this, true);
21298 Event.on(document, "touchmove", this.handleMouseMove, this, true);
21300 Event.on(window, "unload", this._onUnload, this, true);
21301 Event.on(window, "resize", this._onResize, this, true);
21302 // Event.on(window, "mouseout", this._test);
21307 * Reset constraints on all drag and drop objs
21308 * @method _onResize
21312 _onResize: function(e) {
21313 this._execOnAll("resetConstraints", []);
21317 * Lock all drag and drop functionality
21321 lock: function() { this.locked = true; },
21324 * Unlock all drag and drop functionality
21328 unlock: function() { this.locked = false; },
21331 * Is drag and drop locked?
21333 * @return {boolean} True if drag and drop is locked, false otherwise.
21336 isLocked: function() { return this.locked; },
21339 * Location cache that is set for all drag drop objects when a drag is
21340 * initiated, cleared when the drag is finished.
21341 * @property locationCache
21348 * Set useCache to false if you want to force object the lookup of each
21349 * drag and drop linked element constantly during a drag.
21350 * @property useCache
21357 * The number of pixels that the mouse needs to move after the
21358 * mousedown before the drag is initiated. Default=3;
21359 * @property clickPixelThresh
21363 clickPixelThresh: 3,
21366 * The number of milliseconds after the mousedown event to initiate the
21367 * drag if we don't get a mouseup event. Default=1000
21368 * @property clickTimeThresh
21372 clickTimeThresh: 350,
21375 * Flag that indicates that either the drag pixel threshold or the
21376 * mousdown time threshold has been met
21377 * @property dragThreshMet
21382 dragThreshMet: false,
21385 * Timeout used for the click time threshold
21386 * @property clickTimeout
21391 clickTimeout: null,
21394 * The X position of the mousedown event stored for later use when a
21395 * drag threshold is met.
21404 * The Y position of the mousedown event stored for later use when a
21405 * drag threshold is met.
21414 * Each DragDrop instance must be registered with the DragDropMgr.
21415 * This is executed in DragDrop.init()
21416 * @method regDragDrop
21417 * @param {DragDrop} oDD the DragDrop object to register
21418 * @param {String} sGroup the name of the group this element belongs to
21421 regDragDrop: function(oDD, sGroup) {
21422 if (!this.initialized) { this.init(); }
21424 if (!this.ids[sGroup]) {
21425 this.ids[sGroup] = {};
21427 this.ids[sGroup][oDD.id] = oDD;
21431 * Removes the supplied dd instance from the supplied group. Executed
21432 * by DragDrop.removeFromGroup, so don't call this function directly.
21433 * @method removeDDFromGroup
21437 removeDDFromGroup: function(oDD, sGroup) {
21438 if (!this.ids[sGroup]) {
21439 this.ids[sGroup] = {};
21442 var obj = this.ids[sGroup];
21443 if (obj && obj[oDD.id]) {
21444 delete obj[oDD.id];
21449 * Unregisters a drag and drop item. This is executed in
21450 * DragDrop.unreg, use that method instead of calling this directly.
21455 _remove: function(oDD) {
21456 for (var g in oDD.groups) {
21457 if (g && this.ids[g][oDD.id]) {
21458 delete this.ids[g][oDD.id];
21461 delete this.handleIds[oDD.id];
21465 * Each DragDrop handle element must be registered. This is done
21466 * automatically when executing DragDrop.setHandleElId()
21467 * @method regHandle
21468 * @param {String} sDDId the DragDrop id this element is a handle for
21469 * @param {String} sHandleId the id of the element that is the drag
21473 regHandle: function(sDDId, sHandleId) {
21474 if (!this.handleIds[sDDId]) {
21475 this.handleIds[sDDId] = {};
21477 this.handleIds[sDDId][sHandleId] = sHandleId;
21481 * Utility function to determine if a given element has been
21482 * registered as a drag drop item.
21483 * @method isDragDrop
21484 * @param {String} id the element id to check
21485 * @return {boolean} true if this element is a DragDrop item,
21489 isDragDrop: function(id) {
21490 return ( this.getDDById(id) ) ? true : false;
21494 * Returns the drag and drop instances that are in all groups the
21495 * passed in instance belongs to.
21496 * @method getRelated
21497 * @param {DragDrop} p_oDD the obj to get related data for
21498 * @param {boolean} bTargetsOnly if true, only return targetable objs
21499 * @return {DragDrop[]} the related instances
21502 getRelated: function(p_oDD, bTargetsOnly) {
21504 for (var i in p_oDD.groups) {
21505 for (j in this.ids[i]) {
21506 var dd = this.ids[i][j];
21507 if (! this.isTypeOfDD(dd)) {
21510 if (!bTargetsOnly || dd.isTarget) {
21511 oDDs[oDDs.length] = dd;
21520 * Returns true if the specified dd target is a legal target for
21521 * the specifice drag obj
21522 * @method isLegalTarget
21523 * @param {DragDrop} the drag obj
21524 * @param {DragDrop} the target
21525 * @return {boolean} true if the target is a legal target for the
21529 isLegalTarget: function (oDD, oTargetDD) {
21530 var targets = this.getRelated(oDD, true);
21531 for (var i=0, len=targets.length;i<len;++i) {
21532 if (targets[i].id == oTargetDD.id) {
21541 * My goal is to be able to transparently determine if an object is
21542 * typeof DragDrop, and the exact subclass of DragDrop. typeof
21543 * returns "object", oDD.constructor.toString() always returns
21544 * "DragDrop" and not the name of the subclass. So for now it just
21545 * evaluates a well-known variable in DragDrop.
21546 * @method isTypeOfDD
21547 * @param {Object} the object to evaluate
21548 * @return {boolean} true if typeof oDD = DragDrop
21551 isTypeOfDD: function (oDD) {
21552 return (oDD && oDD.__ygDragDrop);
21556 * Utility function to determine if a given element has been
21557 * registered as a drag drop handle for the given Drag Drop object.
21559 * @param {String} id the element id to check
21560 * @return {boolean} true if this element is a DragDrop handle, false
21564 isHandle: function(sDDId, sHandleId) {
21565 return ( this.handleIds[sDDId] &&
21566 this.handleIds[sDDId][sHandleId] );
21570 * Returns the DragDrop instance for a given id
21571 * @method getDDById
21572 * @param {String} id the id of the DragDrop object
21573 * @return {DragDrop} the drag drop object, null if it is not found
21576 getDDById: function(id) {
21577 for (var i in this.ids) {
21578 if (this.ids[i][id]) {
21579 return this.ids[i][id];
21586 * Fired after a registered DragDrop object gets the mousedown event.
21587 * Sets up the events required to track the object being dragged
21588 * @method handleMouseDown
21589 * @param {Event} e the event
21590 * @param oDD the DragDrop object being dragged
21594 handleMouseDown: function(e, oDD) {
21596 Roo.QuickTips.disable();
21598 this.currentTarget = e.getTarget();
21600 this.dragCurrent = oDD;
21602 var el = oDD.getEl();
21604 // track start position
21605 this.startX = e.getPageX();
21606 this.startY = e.getPageY();
21608 this.deltaX = this.startX - el.offsetLeft;
21609 this.deltaY = this.startY - el.offsetTop;
21611 this.dragThreshMet = false;
21613 this.clickTimeout = setTimeout(
21615 var DDM = Roo.dd.DDM;
21616 DDM.startDrag(DDM.startX, DDM.startY);
21618 this.clickTimeThresh );
21622 * Fired when either the drag pixel threshol or the mousedown hold
21623 * time threshold has been met.
21624 * @method startDrag
21625 * @param x {int} the X position of the original mousedown
21626 * @param y {int} the Y position of the original mousedown
21629 startDrag: function(x, y) {
21630 clearTimeout(this.clickTimeout);
21631 if (this.dragCurrent) {
21632 this.dragCurrent.b4StartDrag(x, y);
21633 this.dragCurrent.startDrag(x, y);
21635 this.dragThreshMet = true;
21639 * Internal function to handle the mouseup event. Will be invoked
21640 * from the context of the document.
21641 * @method handleMouseUp
21642 * @param {Event} e the event
21646 handleMouseUp: function(e) {
21649 Roo.QuickTips.enable();
21651 if (! this.dragCurrent) {
21655 clearTimeout(this.clickTimeout);
21657 if (this.dragThreshMet) {
21658 this.fireEvents(e, true);
21668 * Utility to stop event propagation and event default, if these
21669 * features are turned on.
21670 * @method stopEvent
21671 * @param {Event} e the event as returned by this.getEvent()
21674 stopEvent: function(e){
21675 if(this.stopPropagation) {
21676 e.stopPropagation();
21679 if (this.preventDefault) {
21680 e.preventDefault();
21685 * Internal function to clean up event handlers after the drag
21686 * operation is complete
21688 * @param {Event} e the event
21692 stopDrag: function(e) {
21693 // Fire the drag end event for the item that was dragged
21694 if (this.dragCurrent) {
21695 if (this.dragThreshMet) {
21696 this.dragCurrent.b4EndDrag(e);
21697 this.dragCurrent.endDrag(e);
21700 this.dragCurrent.onMouseUp(e);
21703 this.dragCurrent = null;
21704 this.dragOvers = {};
21708 * Internal function to handle the mousemove event. Will be invoked
21709 * from the context of the html element.
21711 * @TODO figure out what we can do about mouse events lost when the
21712 * user drags objects beyond the window boundary. Currently we can
21713 * detect this in internet explorer by verifying that the mouse is
21714 * down during the mousemove event. Firefox doesn't give us the
21715 * button state on the mousemove event.
21716 * @method handleMouseMove
21717 * @param {Event} e the event
21721 handleMouseMove: function(e) {
21722 if (! this.dragCurrent) {
21726 // var button = e.which || e.button;
21728 // check for IE mouseup outside of page boundary
21729 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
21731 return this.handleMouseUp(e);
21734 if (!this.dragThreshMet) {
21735 var diffX = Math.abs(this.startX - e.getPageX());
21736 var diffY = Math.abs(this.startY - e.getPageY());
21737 if (diffX > this.clickPixelThresh ||
21738 diffY > this.clickPixelThresh) {
21739 this.startDrag(this.startX, this.startY);
21743 if (this.dragThreshMet) {
21744 this.dragCurrent.b4Drag(e);
21745 this.dragCurrent.onDrag(e);
21746 if(!this.dragCurrent.moveOnly){
21747 this.fireEvents(e, false);
21757 * Iterates over all of the DragDrop elements to find ones we are
21758 * hovering over or dropping on
21759 * @method fireEvents
21760 * @param {Event} e the event
21761 * @param {boolean} isDrop is this a drop op or a mouseover op?
21765 fireEvents: function(e, isDrop) {
21766 var dc = this.dragCurrent;
21768 // If the user did the mouse up outside of the window, we could
21769 // get here even though we have ended the drag.
21770 if (!dc || dc.isLocked()) {
21774 var pt = e.getPoint();
21776 // cache the previous dragOver array
21782 var enterEvts = [];
21784 // Check to see if the object(s) we were hovering over is no longer
21785 // being hovered over so we can fire the onDragOut event
21786 for (var i in this.dragOvers) {
21788 var ddo = this.dragOvers[i];
21790 if (! this.isTypeOfDD(ddo)) {
21794 if (! this.isOverTarget(pt, ddo, this.mode)) {
21795 outEvts.push( ddo );
21798 oldOvers[i] = true;
21799 delete this.dragOvers[i];
21802 for (var sGroup in dc.groups) {
21804 if ("string" != typeof sGroup) {
21808 for (i in this.ids[sGroup]) {
21809 var oDD = this.ids[sGroup][i];
21810 if (! this.isTypeOfDD(oDD)) {
21814 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
21815 if (this.isOverTarget(pt, oDD, this.mode)) {
21816 // look for drop interactions
21818 dropEvts.push( oDD );
21819 // look for drag enter and drag over interactions
21822 // initial drag over: dragEnter fires
21823 if (!oldOvers[oDD.id]) {
21824 enterEvts.push( oDD );
21825 // subsequent drag overs: dragOver fires
21827 overEvts.push( oDD );
21830 this.dragOvers[oDD.id] = oDD;
21838 if (outEvts.length) {
21839 dc.b4DragOut(e, outEvts);
21840 dc.onDragOut(e, outEvts);
21843 if (enterEvts.length) {
21844 dc.onDragEnter(e, enterEvts);
21847 if (overEvts.length) {
21848 dc.b4DragOver(e, overEvts);
21849 dc.onDragOver(e, overEvts);
21852 if (dropEvts.length) {
21853 dc.b4DragDrop(e, dropEvts);
21854 dc.onDragDrop(e, dropEvts);
21858 // fire dragout events
21860 for (i=0, len=outEvts.length; i<len; ++i) {
21861 dc.b4DragOut(e, outEvts[i].id);
21862 dc.onDragOut(e, outEvts[i].id);
21865 // fire enter events
21866 for (i=0,len=enterEvts.length; i<len; ++i) {
21867 // dc.b4DragEnter(e, oDD.id);
21868 dc.onDragEnter(e, enterEvts[i].id);
21871 // fire over events
21872 for (i=0,len=overEvts.length; i<len; ++i) {
21873 dc.b4DragOver(e, overEvts[i].id);
21874 dc.onDragOver(e, overEvts[i].id);
21877 // fire drop events
21878 for (i=0, len=dropEvts.length; i<len; ++i) {
21879 dc.b4DragDrop(e, dropEvts[i].id);
21880 dc.onDragDrop(e, dropEvts[i].id);
21885 // notify about a drop that did not find a target
21886 if (isDrop && !dropEvts.length) {
21887 dc.onInvalidDrop(e);
21893 * Helper function for getting the best match from the list of drag
21894 * and drop objects returned by the drag and drop events when we are
21895 * in INTERSECT mode. It returns either the first object that the
21896 * cursor is over, or the object that has the greatest overlap with
21897 * the dragged element.
21898 * @method getBestMatch
21899 * @param {DragDrop[]} dds The array of drag and drop objects
21901 * @return {DragDrop} The best single match
21904 getBestMatch: function(dds) {
21906 // Return null if the input is not what we expect
21907 //if (!dds || !dds.length || dds.length == 0) {
21909 // If there is only one item, it wins
21910 //} else if (dds.length == 1) {
21912 var len = dds.length;
21917 // Loop through the targeted items
21918 for (var i=0; i<len; ++i) {
21920 // If the cursor is over the object, it wins. If the
21921 // cursor is over multiple matches, the first one we come
21923 if (dd.cursorIsOver) {
21926 // Otherwise the object with the most overlap wins
21929 winner.overlap.getArea() < dd.overlap.getArea()) {
21940 * Refreshes the cache of the top-left and bottom-right points of the
21941 * drag and drop objects in the specified group(s). This is in the
21942 * format that is stored in the drag and drop instance, so typical
21945 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
21949 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
21951 * @TODO this really should be an indexed array. Alternatively this
21952 * method could accept both.
21953 * @method refreshCache
21954 * @param {Object} groups an associative array of groups to refresh
21957 refreshCache: function(groups) {
21958 for (var sGroup in groups) {
21959 if ("string" != typeof sGroup) {
21962 for (var i in this.ids[sGroup]) {
21963 var oDD = this.ids[sGroup][i];
21965 if (this.isTypeOfDD(oDD)) {
21966 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
21967 var loc = this.getLocation(oDD);
21969 this.locationCache[oDD.id] = loc;
21971 delete this.locationCache[oDD.id];
21972 // this will unregister the drag and drop object if
21973 // the element is not in a usable state
21982 * This checks to make sure an element exists and is in the DOM. The
21983 * main purpose is to handle cases where innerHTML is used to remove
21984 * drag and drop objects from the DOM. IE provides an 'unspecified
21985 * error' when trying to access the offsetParent of such an element
21987 * @param {HTMLElement} el the element to check
21988 * @return {boolean} true if the element looks usable
21991 verifyEl: function(el) {
21996 parent = el.offsetParent;
21999 parent = el.offsetParent;
22010 * Returns a Region object containing the drag and drop element's position
22011 * and size, including the padding configured for it
22012 * @method getLocation
22013 * @param {DragDrop} oDD the drag and drop object to get the
22015 * @return {Roo.lib.Region} a Region object representing the total area
22016 * the element occupies, including any padding
22017 * the instance is configured for.
22020 getLocation: function(oDD) {
22021 if (! this.isTypeOfDD(oDD)) {
22025 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
22028 pos= Roo.lib.Dom.getXY(el);
22036 x2 = x1 + el.offsetWidth;
22038 y2 = y1 + el.offsetHeight;
22040 t = y1 - oDD.padding[0];
22041 r = x2 + oDD.padding[1];
22042 b = y2 + oDD.padding[2];
22043 l = x1 - oDD.padding[3];
22045 return new Roo.lib.Region( t, r, b, l );
22049 * Checks the cursor location to see if it over the target
22050 * @method isOverTarget
22051 * @param {Roo.lib.Point} pt The point to evaluate
22052 * @param {DragDrop} oTarget the DragDrop object we are inspecting
22053 * @return {boolean} true if the mouse is over the target
22057 isOverTarget: function(pt, oTarget, intersect) {
22058 // use cache if available
22059 var loc = this.locationCache[oTarget.id];
22060 if (!loc || !this.useCache) {
22061 loc = this.getLocation(oTarget);
22062 this.locationCache[oTarget.id] = loc;
22070 oTarget.cursorIsOver = loc.contains( pt );
22072 // DragDrop is using this as a sanity check for the initial mousedown
22073 // in this case we are done. In POINT mode, if the drag obj has no
22074 // contraints, we are also done. Otherwise we need to evaluate the
22075 // location of the target as related to the actual location of the
22076 // dragged element.
22077 var dc = this.dragCurrent;
22078 if (!dc || !dc.getTargetCoord ||
22079 (!intersect && !dc.constrainX && !dc.constrainY)) {
22080 return oTarget.cursorIsOver;
22083 oTarget.overlap = null;
22085 // Get the current location of the drag element, this is the
22086 // location of the mouse event less the delta that represents
22087 // where the original mousedown happened on the element. We
22088 // need to consider constraints and ticks as well.
22089 var pos = dc.getTargetCoord(pt.x, pt.y);
22091 var el = dc.getDragEl();
22092 var curRegion = new Roo.lib.Region( pos.y,
22093 pos.x + el.offsetWidth,
22094 pos.y + el.offsetHeight,
22097 var overlap = curRegion.intersect(loc);
22100 oTarget.overlap = overlap;
22101 return (intersect) ? true : oTarget.cursorIsOver;
22108 * unload event handler
22109 * @method _onUnload
22113 _onUnload: function(e, me) {
22114 Roo.dd.DragDropMgr.unregAll();
22118 * Cleans up the drag and drop events and objects.
22123 unregAll: function() {
22125 if (this.dragCurrent) {
22127 this.dragCurrent = null;
22130 this._execOnAll("unreg", []);
22132 for (i in this.elementCache) {
22133 delete this.elementCache[i];
22136 this.elementCache = {};
22141 * A cache of DOM elements
22142 * @property elementCache
22149 * Get the wrapper for the DOM element specified
22150 * @method getElWrapper
22151 * @param {String} id the id of the element to get
22152 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
22154 * @deprecated This wrapper isn't that useful
22157 getElWrapper: function(id) {
22158 var oWrapper = this.elementCache[id];
22159 if (!oWrapper || !oWrapper.el) {
22160 oWrapper = this.elementCache[id] =
22161 new this.ElementWrapper(Roo.getDom(id));
22167 * Returns the actual DOM element
22168 * @method getElement
22169 * @param {String} id the id of the elment to get
22170 * @return {Object} The element
22171 * @deprecated use Roo.getDom instead
22174 getElement: function(id) {
22175 return Roo.getDom(id);
22179 * Returns the style property for the DOM element (i.e.,
22180 * document.getElById(id).style)
22182 * @param {String} id the id of the elment to get
22183 * @return {Object} The style property of the element
22184 * @deprecated use Roo.getDom instead
22187 getCss: function(id) {
22188 var el = Roo.getDom(id);
22189 return (el) ? el.style : null;
22193 * Inner class for cached elements
22194 * @class DragDropMgr.ElementWrapper
22199 ElementWrapper: function(el) {
22204 this.el = el || null;
22209 this.id = this.el && el.id;
22211 * A reference to the style property
22214 this.css = this.el && el.style;
22218 * Returns the X position of an html element
22220 * @param el the element for which to get the position
22221 * @return {int} the X coordinate
22223 * @deprecated use Roo.lib.Dom.getX instead
22226 getPosX: function(el) {
22227 return Roo.lib.Dom.getX(el);
22231 * Returns the Y position of an html element
22233 * @param el the element for which to get the position
22234 * @return {int} the Y coordinate
22235 * @deprecated use Roo.lib.Dom.getY instead
22238 getPosY: function(el) {
22239 return Roo.lib.Dom.getY(el);
22243 * Swap two nodes. In IE, we use the native method, for others we
22244 * emulate the IE behavior
22246 * @param n1 the first node to swap
22247 * @param n2 the other node to swap
22250 swapNode: function(n1, n2) {
22254 var p = n2.parentNode;
22255 var s = n2.nextSibling;
22258 p.insertBefore(n1, n2);
22259 } else if (n2 == n1.nextSibling) {
22260 p.insertBefore(n2, n1);
22262 n1.parentNode.replaceChild(n2, n1);
22263 p.insertBefore(n1, s);
22269 * Returns the current scroll position
22270 * @method getScroll
22274 getScroll: function () {
22275 var t, l, dde=document.documentElement, db=document.body;
22276 if (dde && (dde.scrollTop || dde.scrollLeft)) {
22278 l = dde.scrollLeft;
22285 return { top: t, left: l };
22289 * Returns the specified element style property
22291 * @param {HTMLElement} el the element
22292 * @param {string} styleProp the style property
22293 * @return {string} The value of the style property
22294 * @deprecated use Roo.lib.Dom.getStyle
22297 getStyle: function(el, styleProp) {
22298 return Roo.fly(el).getStyle(styleProp);
22302 * Gets the scrollTop
22303 * @method getScrollTop
22304 * @return {int} the document's scrollTop
22307 getScrollTop: function () { return this.getScroll().top; },
22310 * Gets the scrollLeft
22311 * @method getScrollLeft
22312 * @return {int} the document's scrollTop
22315 getScrollLeft: function () { return this.getScroll().left; },
22318 * Sets the x/y position of an element to the location of the
22321 * @param {HTMLElement} moveEl The element to move
22322 * @param {HTMLElement} targetEl The position reference element
22325 moveToEl: function (moveEl, targetEl) {
22326 var aCoord = Roo.lib.Dom.getXY(targetEl);
22327 Roo.lib.Dom.setXY(moveEl, aCoord);
22331 * Numeric array sort function
22332 * @method numericSort
22335 numericSort: function(a, b) { return (a - b); },
22339 * @property _timeoutCount
22346 * Trying to make the load order less important. Without this we get
22347 * an error if this file is loaded before the Event Utility.
22348 * @method _addListeners
22352 _addListeners: function() {
22353 var DDM = Roo.dd.DDM;
22354 if ( Roo.lib.Event && document ) {
22357 if (DDM._timeoutCount > 2000) {
22359 setTimeout(DDM._addListeners, 10);
22360 if (document && document.body) {
22361 DDM._timeoutCount += 1;
22368 * Recursively searches the immediate parent and all child nodes for
22369 * the handle element in order to determine wheter or not it was
22371 * @method handleWasClicked
22372 * @param node the html element to inspect
22375 handleWasClicked: function(node, id) {
22376 if (this.isHandle(id, node.id)) {
22379 // check to see if this is a text node child of the one we want
22380 var p = node.parentNode;
22383 if (this.isHandle(id, p.id)) {
22398 // shorter alias, save a few bytes
22399 Roo.dd.DDM = Roo.dd.DragDropMgr;
22400 Roo.dd.DDM._addListeners();
22404 * Ext JS Library 1.1.1
22405 * Copyright(c) 2006-2007, Ext JS, LLC.
22407 * Originally Released Under LGPL - original licence link has changed is not relivant.
22410 * <script type="text/javascript">
22415 * A DragDrop implementation where the linked element follows the
22416 * mouse cursor during a drag.
22417 * @extends Roo.dd.DragDrop
22419 * @param {String} id the id of the linked element
22420 * @param {String} sGroup the group of related DragDrop items
22421 * @param {object} config an object containing configurable attributes
22422 * Valid properties for DD:
22425 Roo.dd.DD = function(id, sGroup, config) {
22427 this.init(id, sGroup, config);
22431 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
22434 * When set to true, the utility automatically tries to scroll the browser
22435 * window wehn a drag and drop element is dragged near the viewport boundary.
22436 * Defaults to true.
22443 * Sets the pointer offset to the distance between the linked element's top
22444 * left corner and the location the element was clicked
22445 * @method autoOffset
22446 * @param {int} iPageX the X coordinate of the click
22447 * @param {int} iPageY the Y coordinate of the click
22449 autoOffset: function(iPageX, iPageY) {
22450 var x = iPageX - this.startPageX;
22451 var y = iPageY - this.startPageY;
22452 this.setDelta(x, y);
22456 * Sets the pointer offset. You can call this directly to force the
22457 * offset to be in a particular location (e.g., pass in 0,0 to set it
22458 * to the center of the object)
22460 * @param {int} iDeltaX the distance from the left
22461 * @param {int} iDeltaY the distance from the top
22463 setDelta: function(iDeltaX, iDeltaY) {
22464 this.deltaX = iDeltaX;
22465 this.deltaY = iDeltaY;
22469 * Sets the drag element to the location of the mousedown or click event,
22470 * maintaining the cursor location relative to the location on the element
22471 * that was clicked. Override this if you want to place the element in a
22472 * location other than where the cursor is.
22473 * @method setDragElPos
22474 * @param {int} iPageX the X coordinate of the mousedown or drag event
22475 * @param {int} iPageY the Y coordinate of the mousedown or drag event
22477 setDragElPos: function(iPageX, iPageY) {
22478 // the first time we do this, we are going to check to make sure
22479 // the element has css positioning
22481 var el = this.getDragEl();
22482 this.alignElWithMouse(el, iPageX, iPageY);
22486 * Sets the element to the location of the mousedown or click event,
22487 * maintaining the cursor location relative to the location on the element
22488 * that was clicked. Override this if you want to place the element in a
22489 * location other than where the cursor is.
22490 * @method alignElWithMouse
22491 * @param {HTMLElement} el the element to move
22492 * @param {int} iPageX the X coordinate of the mousedown or drag event
22493 * @param {int} iPageY the Y coordinate of the mousedown or drag event
22495 alignElWithMouse: function(el, iPageX, iPageY) {
22496 var oCoord = this.getTargetCoord(iPageX, iPageY);
22497 var fly = el.dom ? el : Roo.fly(el);
22498 if (!this.deltaSetXY) {
22499 var aCoord = [oCoord.x, oCoord.y];
22501 var newLeft = fly.getLeft(true);
22502 var newTop = fly.getTop(true);
22503 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
22505 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
22508 this.cachePosition(oCoord.x, oCoord.y);
22509 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
22514 * Saves the most recent position so that we can reset the constraints and
22515 * tick marks on-demand. We need to know this so that we can calculate the
22516 * number of pixels the element is offset from its original position.
22517 * @method cachePosition
22518 * @param iPageX the current x position (optional, this just makes it so we
22519 * don't have to look it up again)
22520 * @param iPageY the current y position (optional, this just makes it so we
22521 * don't have to look it up again)
22523 cachePosition: function(iPageX, iPageY) {
22525 this.lastPageX = iPageX;
22526 this.lastPageY = iPageY;
22528 var aCoord = Roo.lib.Dom.getXY(this.getEl());
22529 this.lastPageX = aCoord[0];
22530 this.lastPageY = aCoord[1];
22535 * Auto-scroll the window if the dragged object has been moved beyond the
22536 * visible window boundary.
22537 * @method autoScroll
22538 * @param {int} x the drag element's x position
22539 * @param {int} y the drag element's y position
22540 * @param {int} h the height of the drag element
22541 * @param {int} w the width of the drag element
22544 autoScroll: function(x, y, h, w) {
22547 // The client height
22548 var clientH = Roo.lib.Dom.getViewWidth();
22550 // The client width
22551 var clientW = Roo.lib.Dom.getViewHeight();
22553 // The amt scrolled down
22554 var st = this.DDM.getScrollTop();
22556 // The amt scrolled right
22557 var sl = this.DDM.getScrollLeft();
22559 // Location of the bottom of the element
22562 // Location of the right of the element
22565 // The distance from the cursor to the bottom of the visible area,
22566 // adjusted so that we don't scroll if the cursor is beyond the
22567 // element drag constraints
22568 var toBot = (clientH + st - y - this.deltaY);
22570 // The distance from the cursor to the right of the visible area
22571 var toRight = (clientW + sl - x - this.deltaX);
22574 // How close to the edge the cursor must be before we scroll
22575 // var thresh = (document.all) ? 100 : 40;
22578 // How many pixels to scroll per autoscroll op. This helps to reduce
22579 // clunky scrolling. IE is more sensitive about this ... it needs this
22580 // value to be higher.
22581 var scrAmt = (document.all) ? 80 : 30;
22583 // Scroll down if we are near the bottom of the visible page and the
22584 // obj extends below the crease
22585 if ( bot > clientH && toBot < thresh ) {
22586 window.scrollTo(sl, st + scrAmt);
22589 // Scroll up if the window is scrolled down and the top of the object
22590 // goes above the top border
22591 if ( y < st && st > 0 && y - st < thresh ) {
22592 window.scrollTo(sl, st - scrAmt);
22595 // Scroll right if the obj is beyond the right border and the cursor is
22596 // near the border.
22597 if ( right > clientW && toRight < thresh ) {
22598 window.scrollTo(sl + scrAmt, st);
22601 // Scroll left if the window has been scrolled to the right and the obj
22602 // extends past the left border
22603 if ( x < sl && sl > 0 && x - sl < thresh ) {
22604 window.scrollTo(sl - scrAmt, st);
22610 * Finds the location the element should be placed if we want to move
22611 * it to where the mouse location less the click offset would place us.
22612 * @method getTargetCoord
22613 * @param {int} iPageX the X coordinate of the click
22614 * @param {int} iPageY the Y coordinate of the click
22615 * @return an object that contains the coordinates (Object.x and Object.y)
22618 getTargetCoord: function(iPageX, iPageY) {
22621 var x = iPageX - this.deltaX;
22622 var y = iPageY - this.deltaY;
22624 if (this.constrainX) {
22625 if (x < this.minX) { x = this.minX; }
22626 if (x > this.maxX) { x = this.maxX; }
22629 if (this.constrainY) {
22630 if (y < this.minY) { y = this.minY; }
22631 if (y > this.maxY) { y = this.maxY; }
22634 x = this.getTick(x, this.xTicks);
22635 y = this.getTick(y, this.yTicks);
22642 * Sets up config options specific to this class. Overrides
22643 * Roo.dd.DragDrop, but all versions of this method through the
22644 * inheritance chain are called
22646 applyConfig: function() {
22647 Roo.dd.DD.superclass.applyConfig.call(this);
22648 this.scroll = (this.config.scroll !== false);
22652 * Event that fires prior to the onMouseDown event. Overrides
22655 b4MouseDown: function(e) {
22656 // this.resetConstraints();
22657 this.autoOffset(e.getPageX(),
22662 * Event that fires prior to the onDrag event. Overrides
22665 b4Drag: function(e) {
22666 this.setDragElPos(e.getPageX(),
22670 toString: function() {
22671 return ("DD " + this.id);
22674 //////////////////////////////////////////////////////////////////////////
22675 // Debugging ygDragDrop events that can be overridden
22676 //////////////////////////////////////////////////////////////////////////
22678 startDrag: function(x, y) {
22681 onDrag: function(e) {
22684 onDragEnter: function(e, id) {
22687 onDragOver: function(e, id) {
22690 onDragOut: function(e, id) {
22693 onDragDrop: function(e, id) {
22696 endDrag: function(e) {
22703 * Ext JS Library 1.1.1
22704 * Copyright(c) 2006-2007, Ext JS, LLC.
22706 * Originally Released Under LGPL - original licence link has changed is not relivant.
22709 * <script type="text/javascript">
22713 * @class Roo.dd.DDProxy
22714 * A DragDrop implementation that inserts an empty, bordered div into
22715 * the document that follows the cursor during drag operations. At the time of
22716 * the click, the frame div is resized to the dimensions of the linked html
22717 * element, and moved to the exact location of the linked element.
22719 * References to the "frame" element refer to the single proxy element that
22720 * was created to be dragged in place of all DDProxy elements on the
22723 * @extends Roo.dd.DD
22725 * @param {String} id the id of the linked html element
22726 * @param {String} sGroup the group of related DragDrop objects
22727 * @param {object} config an object containing configurable attributes
22728 * Valid properties for DDProxy in addition to those in DragDrop:
22729 * resizeFrame, centerFrame, dragElId
22731 Roo.dd.DDProxy = function(id, sGroup, config) {
22733 this.init(id, sGroup, config);
22739 * The default drag frame div id
22740 * @property Roo.dd.DDProxy.dragElId
22744 Roo.dd.DDProxy.dragElId = "ygddfdiv";
22746 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
22749 * By default we resize the drag frame to be the same size as the element
22750 * we want to drag (this is to get the frame effect). We can turn it off
22751 * if we want a different behavior.
22752 * @property resizeFrame
22758 * By default the frame is positioned exactly where the drag element is, so
22759 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
22760 * you do not have constraints on the obj is to have the drag frame centered
22761 * around the cursor. Set centerFrame to true for this effect.
22762 * @property centerFrame
22765 centerFrame: false,
22768 * Creates the proxy element if it does not yet exist
22769 * @method createFrame
22771 createFrame: function() {
22773 var body = document.body;
22775 if (!body || !body.firstChild) {
22776 setTimeout( function() { self.createFrame(); }, 50 );
22780 var div = this.getDragEl();
22783 div = document.createElement("div");
22784 div.id = this.dragElId;
22787 s.position = "absolute";
22788 s.visibility = "hidden";
22790 s.border = "2px solid #aaa";
22793 // appendChild can blow up IE if invoked prior to the window load event
22794 // while rendering a table. It is possible there are other scenarios
22795 // that would cause this to happen as well.
22796 body.insertBefore(div, body.firstChild);
22801 * Initialization for the drag frame element. Must be called in the
22802 * constructor of all subclasses
22803 * @method initFrame
22805 initFrame: function() {
22806 this.createFrame();
22809 applyConfig: function() {
22810 Roo.dd.DDProxy.superclass.applyConfig.call(this);
22812 this.resizeFrame = (this.config.resizeFrame !== false);
22813 this.centerFrame = (this.config.centerFrame);
22814 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
22818 * Resizes the drag frame to the dimensions of the clicked object, positions
22819 * it over the object, and finally displays it
22820 * @method showFrame
22821 * @param {int} iPageX X click position
22822 * @param {int} iPageY Y click position
22825 showFrame: function(iPageX, iPageY) {
22826 var el = this.getEl();
22827 var dragEl = this.getDragEl();
22828 var s = dragEl.style;
22830 this._resizeProxy();
22832 if (this.centerFrame) {
22833 this.setDelta( Math.round(parseInt(s.width, 10)/2),
22834 Math.round(parseInt(s.height, 10)/2) );
22837 this.setDragElPos(iPageX, iPageY);
22839 Roo.fly(dragEl).show();
22843 * The proxy is automatically resized to the dimensions of the linked
22844 * element when a drag is initiated, unless resizeFrame is set to false
22845 * @method _resizeProxy
22848 _resizeProxy: function() {
22849 if (this.resizeFrame) {
22850 var el = this.getEl();
22851 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
22855 // overrides Roo.dd.DragDrop
22856 b4MouseDown: function(e) {
22857 var x = e.getPageX();
22858 var y = e.getPageY();
22859 this.autoOffset(x, y);
22860 this.setDragElPos(x, y);
22863 // overrides Roo.dd.DragDrop
22864 b4StartDrag: function(x, y) {
22865 // show the drag frame
22866 this.showFrame(x, y);
22869 // overrides Roo.dd.DragDrop
22870 b4EndDrag: function(e) {
22871 Roo.fly(this.getDragEl()).hide();
22874 // overrides Roo.dd.DragDrop
22875 // By default we try to move the element to the last location of the frame.
22876 // This is so that the default behavior mirrors that of Roo.dd.DD.
22877 endDrag: function(e) {
22879 var lel = this.getEl();
22880 var del = this.getDragEl();
22882 // Show the drag frame briefly so we can get its position
22883 del.style.visibility = "";
22886 // Hide the linked element before the move to get around a Safari
22888 lel.style.visibility = "hidden";
22889 Roo.dd.DDM.moveToEl(lel, del);
22890 del.style.visibility = "hidden";
22891 lel.style.visibility = "";
22896 beforeMove : function(){
22900 afterDrag : function(){
22904 toString: function() {
22905 return ("DDProxy " + this.id);
22911 * Ext JS Library 1.1.1
22912 * Copyright(c) 2006-2007, Ext JS, LLC.
22914 * Originally Released Under LGPL - original licence link has changed is not relivant.
22917 * <script type="text/javascript">
22921 * @class Roo.dd.DDTarget
22922 * A DragDrop implementation that does not move, but can be a drop
22923 * target. You would get the same result by simply omitting implementation
22924 * for the event callbacks, but this way we reduce the processing cost of the
22925 * event listener and the callbacks.
22926 * @extends Roo.dd.DragDrop
22928 * @param {String} id the id of the element that is a drop target
22929 * @param {String} sGroup the group of related DragDrop objects
22930 * @param {object} config an object containing configurable attributes
22931 * Valid properties for DDTarget in addition to those in
22935 Roo.dd.DDTarget = function(id, sGroup, config) {
22937 this.initTarget(id, sGroup, config);
22939 if (config && (config.listeners || config.events)) {
22940 Roo.dd.DragDrop.superclass.constructor.call(this, {
22941 listeners : config.listeners || {},
22942 events : config.events || {}
22947 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
22948 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
22949 toString: function() {
22950 return ("DDTarget " + this.id);
22955 * Ext JS Library 1.1.1
22956 * Copyright(c) 2006-2007, Ext JS, LLC.
22958 * Originally Released Under LGPL - original licence link has changed is not relivant.
22961 * <script type="text/javascript">
22966 * @class Roo.dd.ScrollManager
22967 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
22968 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
22971 Roo.dd.ScrollManager = function(){
22972 var ddm = Roo.dd.DragDropMgr;
22979 var onStop = function(e){
22984 var triggerRefresh = function(){
22985 if(ddm.dragCurrent){
22986 ddm.refreshCache(ddm.dragCurrent.groups);
22990 var doScroll = function(){
22991 if(ddm.dragCurrent){
22992 var dds = Roo.dd.ScrollManager;
22994 if(proc.el.scroll(proc.dir, dds.increment)){
22998 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
23003 var clearProc = function(){
23005 clearInterval(proc.id);
23012 var startProc = function(el, dir){
23013 Roo.log('scroll startproc');
23017 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
23020 var onFire = function(e, isDrop){
23022 if(isDrop || !ddm.dragCurrent){ return; }
23023 var dds = Roo.dd.ScrollManager;
23024 if(!dragEl || dragEl != ddm.dragCurrent){
23025 dragEl = ddm.dragCurrent;
23026 // refresh regions on drag start
23027 dds.refreshCache();
23030 var xy = Roo.lib.Event.getXY(e);
23031 var pt = new Roo.lib.Point(xy[0], xy[1]);
23032 for(var id in els){
23033 var el = els[id], r = el._region;
23034 if(r && r.contains(pt) && el.isScrollable()){
23035 if(r.bottom - pt.y <= dds.thresh){
23037 startProc(el, "down");
23040 }else if(r.right - pt.x <= dds.thresh){
23042 startProc(el, "left");
23045 }else if(pt.y - r.top <= dds.thresh){
23047 startProc(el, "up");
23050 }else if(pt.x - r.left <= dds.thresh){
23052 startProc(el, "right");
23061 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
23062 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
23066 * Registers new overflow element(s) to auto scroll
23067 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
23069 register : function(el){
23070 if(el instanceof Array){
23071 for(var i = 0, len = el.length; i < len; i++) {
23072 this.register(el[i]);
23078 Roo.dd.ScrollManager.els = els;
23082 * Unregisters overflow element(s) so they are no longer scrolled
23083 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
23085 unregister : function(el){
23086 if(el instanceof Array){
23087 for(var i = 0, len = el.length; i < len; i++) {
23088 this.unregister(el[i]);
23097 * The number of pixels from the edge of a container the pointer needs to be to
23098 * trigger scrolling (defaults to 25)
23104 * The number of pixels to scroll in each scroll increment (defaults to 50)
23110 * The frequency of scrolls in milliseconds (defaults to 500)
23116 * True to animate the scroll (defaults to true)
23122 * The animation duration in seconds -
23123 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
23129 * Manually trigger a cache refresh.
23131 refreshCache : function(){
23132 for(var id in els){
23133 if(typeof els[id] == 'object'){ // for people extending the object prototype
23134 els[id]._region = els[id].getRegion();
23141 * Ext JS Library 1.1.1
23142 * Copyright(c) 2006-2007, Ext JS, LLC.
23144 * Originally Released Under LGPL - original licence link has changed is not relivant.
23147 * <script type="text/javascript">
23152 * @class Roo.dd.Registry
23153 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
23154 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
23157 Roo.dd.Registry = function(){
23160 var autoIdSeed = 0;
23162 var getId = function(el, autogen){
23163 if(typeof el == "string"){
23167 if(!id && autogen !== false){
23168 id = "roodd-" + (++autoIdSeed);
23176 * Register a drag drop element
23177 * @param {String|HTMLElement} element The id or DOM node to register
23178 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
23179 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
23180 * knows how to interpret, plus there are some specific properties known to the Registry that should be
23181 * populated in the data object (if applicable):
23183 Value Description<br />
23184 --------- ------------------------------------------<br />
23185 handles Array of DOM nodes that trigger dragging<br />
23186 for the element being registered<br />
23187 isHandle True if the element passed in triggers<br />
23188 dragging itself, else false
23191 register : function(el, data){
23193 if(typeof el == "string"){
23194 el = document.getElementById(el);
23197 elements[getId(el)] = data;
23198 if(data.isHandle !== false){
23199 handles[data.ddel.id] = data;
23202 var hs = data.handles;
23203 for(var i = 0, len = hs.length; i < len; i++){
23204 handles[getId(hs[i])] = data;
23210 * Unregister a drag drop element
23211 * @param {String|HTMLElement} element The id or DOM node to unregister
23213 unregister : function(el){
23214 var id = getId(el, false);
23215 var data = elements[id];
23217 delete elements[id];
23219 var hs = data.handles;
23220 for(var i = 0, len = hs.length; i < len; i++){
23221 delete handles[getId(hs[i], false)];
23228 * Returns the handle registered for a DOM Node by id
23229 * @param {String|HTMLElement} id The DOM node or id to look up
23230 * @return {Object} handle The custom handle data
23232 getHandle : function(id){
23233 if(typeof id != "string"){ // must be element?
23236 return handles[id];
23240 * Returns the handle that is registered for the DOM node that is the target of the event
23241 * @param {Event} e The event
23242 * @return {Object} handle The custom handle data
23244 getHandleFromEvent : function(e){
23245 var t = Roo.lib.Event.getTarget(e);
23246 return t ? handles[t.id] : null;
23250 * Returns a custom data object that is registered for a DOM node by id
23251 * @param {String|HTMLElement} id The DOM node or id to look up
23252 * @return {Object} data The custom data
23254 getTarget : function(id){
23255 if(typeof id != "string"){ // must be element?
23258 return elements[id];
23262 * Returns a custom data object that is registered for the DOM node that is the target of the event
23263 * @param {Event} e The event
23264 * @return {Object} data The custom data
23266 getTargetFromEvent : function(e){
23267 var t = Roo.lib.Event.getTarget(e);
23268 return t ? elements[t.id] || handles[t.id] : null;
23273 * Ext JS Library 1.1.1
23274 * Copyright(c) 2006-2007, Ext JS, LLC.
23276 * Originally Released Under LGPL - original licence link has changed is not relivant.
23279 * <script type="text/javascript">
23284 * @class Roo.dd.StatusProxy
23285 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
23286 * default drag proxy used by all Roo.dd components.
23288 * @param {Object} config
23290 Roo.dd.StatusProxy = function(config){
23291 Roo.apply(this, config);
23292 this.id = this.id || Roo.id();
23293 this.el = new Roo.Layer({
23295 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
23296 {tag: "div", cls: "x-dd-drop-icon"},
23297 {tag: "div", cls: "x-dd-drag-ghost"}
23300 shadow: !config || config.shadow !== false
23302 this.ghost = Roo.get(this.el.dom.childNodes[1]);
23303 this.dropStatus = this.dropNotAllowed;
23306 Roo.dd.StatusProxy.prototype = {
23308 * @cfg {String} dropAllowed
23309 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
23311 dropAllowed : "x-dd-drop-ok",
23313 * @cfg {String} dropNotAllowed
23314 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
23316 dropNotAllowed : "x-dd-drop-nodrop",
23319 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
23320 * over the current target element.
23321 * @param {String} cssClass The css class for the new drop status indicator image
23323 setStatus : function(cssClass){
23324 cssClass = cssClass || this.dropNotAllowed;
23325 if(this.dropStatus != cssClass){
23326 this.el.replaceClass(this.dropStatus, cssClass);
23327 this.dropStatus = cssClass;
23332 * Resets the status indicator to the default dropNotAllowed value
23333 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
23335 reset : function(clearGhost){
23336 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
23337 this.dropStatus = this.dropNotAllowed;
23339 this.ghost.update("");
23344 * Updates the contents of the ghost element
23345 * @param {String} html The html that will replace the current innerHTML of the ghost element
23347 update : function(html){
23348 if(typeof html == "string"){
23349 this.ghost.update(html);
23351 this.ghost.update("");
23352 html.style.margin = "0";
23353 this.ghost.dom.appendChild(html);
23355 // ensure float = none set?? cant remember why though.
23356 var el = this.ghost.dom.firstChild;
23358 Roo.fly(el).setStyle('float', 'none');
23363 * Returns the underlying proxy {@link Roo.Layer}
23364 * @return {Roo.Layer} el
23366 getEl : function(){
23371 * Returns the ghost element
23372 * @return {Roo.Element} el
23374 getGhost : function(){
23380 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
23382 hide : function(clear){
23390 * Stops the repair animation if it's currently running
23393 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
23399 * Displays this proxy
23406 * Force the Layer to sync its shadow and shim positions to the element
23413 * Causes the proxy to return to its position of origin via an animation. Should be called after an
23414 * invalid drop operation by the item being dragged.
23415 * @param {Array} xy The XY position of the element ([x, y])
23416 * @param {Function} callback The function to call after the repair is complete
23417 * @param {Object} scope The scope in which to execute the callback
23419 repair : function(xy, callback, scope){
23420 this.callback = callback;
23421 this.scope = scope;
23422 if(xy && this.animRepair !== false){
23423 this.el.addClass("x-dd-drag-repair");
23424 this.el.hideUnders(true);
23425 this.anim = this.el.shift({
23426 duration: this.repairDuration || .5,
23430 callback: this.afterRepair,
23434 this.afterRepair();
23439 afterRepair : function(){
23441 if(typeof this.callback == "function"){
23442 this.callback.call(this.scope || this);
23444 this.callback = null;
23449 * Ext JS Library 1.1.1
23450 * Copyright(c) 2006-2007, Ext JS, LLC.
23452 * Originally Released Under LGPL - original licence link has changed is not relivant.
23455 * <script type="text/javascript">
23459 * @class Roo.dd.DragSource
23460 * @extends Roo.dd.DDProxy
23461 * A simple class that provides the basic implementation needed to make any element draggable.
23463 * @param {String/HTMLElement/Element} el The container element
23464 * @param {Object} config
23466 Roo.dd.DragSource = function(el, config){
23467 this.el = Roo.get(el);
23468 this.dragData = {};
23470 Roo.apply(this, config);
23473 this.proxy = new Roo.dd.StatusProxy();
23476 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
23477 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
23479 this.dragging = false;
23482 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
23484 * @cfg {String} dropAllowed
23485 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23487 dropAllowed : "x-dd-drop-ok",
23489 * @cfg {String} dropNotAllowed
23490 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23492 dropNotAllowed : "x-dd-drop-nodrop",
23495 * Returns the data object associated with this drag source
23496 * @return {Object} data An object containing arbitrary data
23498 getDragData : function(e){
23499 return this.dragData;
23503 onDragEnter : function(e, id){
23504 var target = Roo.dd.DragDropMgr.getDDById(id);
23505 this.cachedTarget = target;
23506 if(this.beforeDragEnter(target, e, id) !== false){
23507 if(target.isNotifyTarget){
23508 var status = target.notifyEnter(this, e, this.dragData);
23509 this.proxy.setStatus(status);
23511 this.proxy.setStatus(this.dropAllowed);
23514 if(this.afterDragEnter){
23516 * An empty function by default, but provided so that you can perform a custom action
23517 * when the dragged item enters the drop target by providing an implementation.
23518 * @param {Roo.dd.DragDrop} target The drop target
23519 * @param {Event} e The event object
23520 * @param {String} id The id of the dragged element
23521 * @method afterDragEnter
23523 this.afterDragEnter(target, e, id);
23529 * An empty function by default, but provided so that you can perform a custom action
23530 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
23531 * @param {Roo.dd.DragDrop} target The drop target
23532 * @param {Event} e The event object
23533 * @param {String} id The id of the dragged element
23534 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23536 beforeDragEnter : function(target, e, id){
23541 alignElWithMouse: function() {
23542 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
23547 onDragOver : function(e, id){
23548 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23549 if(this.beforeDragOver(target, e, id) !== false){
23550 if(target.isNotifyTarget){
23551 var status = target.notifyOver(this, e, this.dragData);
23552 this.proxy.setStatus(status);
23555 if(this.afterDragOver){
23557 * An empty function by default, but provided so that you can perform a custom action
23558 * while the dragged item is over the drop target by providing an implementation.
23559 * @param {Roo.dd.DragDrop} target The drop target
23560 * @param {Event} e The event object
23561 * @param {String} id The id of the dragged element
23562 * @method afterDragOver
23564 this.afterDragOver(target, e, id);
23570 * An empty function by default, but provided so that you can perform a custom action
23571 * while the dragged item is over the drop target and optionally cancel the onDragOver.
23572 * @param {Roo.dd.DragDrop} target The drop target
23573 * @param {Event} e The event object
23574 * @param {String} id The id of the dragged element
23575 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23577 beforeDragOver : function(target, e, id){
23582 onDragOut : function(e, id){
23583 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23584 if(this.beforeDragOut(target, e, id) !== false){
23585 if(target.isNotifyTarget){
23586 target.notifyOut(this, e, this.dragData);
23588 this.proxy.reset();
23589 if(this.afterDragOut){
23591 * An empty function by default, but provided so that you can perform a custom action
23592 * after the dragged item is dragged out of the target without dropping.
23593 * @param {Roo.dd.DragDrop} target The drop target
23594 * @param {Event} e The event object
23595 * @param {String} id The id of the dragged element
23596 * @method afterDragOut
23598 this.afterDragOut(target, e, id);
23601 this.cachedTarget = null;
23605 * An empty function by default, but provided so that you can perform a custom action before the dragged
23606 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
23607 * @param {Roo.dd.DragDrop} target The drop target
23608 * @param {Event} e The event object
23609 * @param {String} id The id of the dragged element
23610 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23612 beforeDragOut : function(target, e, id){
23617 onDragDrop : function(e, id){
23618 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23619 if(this.beforeDragDrop(target, e, id) !== false){
23620 if(target.isNotifyTarget){
23621 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
23622 this.onValidDrop(target, e, id);
23624 this.onInvalidDrop(target, e, id);
23627 this.onValidDrop(target, e, id);
23630 if(this.afterDragDrop){
23632 * An empty function by default, but provided so that you can perform a custom action
23633 * after a valid drag drop has occurred by providing an implementation.
23634 * @param {Roo.dd.DragDrop} target The drop target
23635 * @param {Event} e The event object
23636 * @param {String} id The id of the dropped element
23637 * @method afterDragDrop
23639 this.afterDragDrop(target, e, id);
23642 delete this.cachedTarget;
23646 * An empty function by default, but provided so that you can perform a custom action before the dragged
23647 * item is dropped onto the target and optionally cancel the onDragDrop.
23648 * @param {Roo.dd.DragDrop} target The drop target
23649 * @param {Event} e The event object
23650 * @param {String} id The id of the dragged element
23651 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
23653 beforeDragDrop : function(target, e, id){
23658 onValidDrop : function(target, e, id){
23660 if(this.afterValidDrop){
23662 * An empty function by default, but provided so that you can perform a custom action
23663 * after a valid drop has occurred by providing an implementation.
23664 * @param {Object} target The target DD
23665 * @param {Event} e The event object
23666 * @param {String} id The id of the dropped element
23667 * @method afterInvalidDrop
23669 this.afterValidDrop(target, e, id);
23674 getRepairXY : function(e, data){
23675 return this.el.getXY();
23679 onInvalidDrop : function(target, e, id){
23680 this.beforeInvalidDrop(target, e, id);
23681 if(this.cachedTarget){
23682 if(this.cachedTarget.isNotifyTarget){
23683 this.cachedTarget.notifyOut(this, e, this.dragData);
23685 this.cacheTarget = null;
23687 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
23689 if(this.afterInvalidDrop){
23691 * An empty function by default, but provided so that you can perform a custom action
23692 * after an invalid drop has occurred by providing an implementation.
23693 * @param {Event} e The event object
23694 * @param {String} id The id of the dropped element
23695 * @method afterInvalidDrop
23697 this.afterInvalidDrop(e, id);
23702 afterRepair : function(){
23704 this.el.highlight(this.hlColor || "c3daf9");
23706 this.dragging = false;
23710 * An empty function by default, but provided so that you can perform a custom action after an invalid
23711 * drop has occurred.
23712 * @param {Roo.dd.DragDrop} target The drop target
23713 * @param {Event} e The event object
23714 * @param {String} id The id of the dragged element
23715 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
23717 beforeInvalidDrop : function(target, e, id){
23722 handleMouseDown : function(e){
23723 if(this.dragging) {
23726 var data = this.getDragData(e);
23727 if(data && this.onBeforeDrag(data, e) !== false){
23728 this.dragData = data;
23730 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
23735 * An empty function by default, but provided so that you can perform a custom action before the initial
23736 * drag event begins and optionally cancel it.
23737 * @param {Object} data An object containing arbitrary data to be shared with drop targets
23738 * @param {Event} e The event object
23739 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23741 onBeforeDrag : function(data, e){
23746 * An empty function by default, but provided so that you can perform a custom action once the initial
23747 * drag event has begun. The drag cannot be canceled from this function.
23748 * @param {Number} x The x position of the click on the dragged object
23749 * @param {Number} y The y position of the click on the dragged object
23751 onStartDrag : Roo.emptyFn,
23753 // private - YUI override
23754 startDrag : function(x, y){
23755 this.proxy.reset();
23756 this.dragging = true;
23757 this.proxy.update("");
23758 this.onInitDrag(x, y);
23763 onInitDrag : function(x, y){
23764 var clone = this.el.dom.cloneNode(true);
23765 clone.id = Roo.id(); // prevent duplicate ids
23766 this.proxy.update(clone);
23767 this.onStartDrag(x, y);
23772 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
23773 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
23775 getProxy : function(){
23780 * Hides the drag source's {@link Roo.dd.StatusProxy}
23782 hideProxy : function(){
23784 this.proxy.reset(true);
23785 this.dragging = false;
23789 triggerCacheRefresh : function(){
23790 Roo.dd.DDM.refreshCache(this.groups);
23793 // private - override to prevent hiding
23794 b4EndDrag: function(e) {
23797 // private - override to prevent moving
23798 endDrag : function(e){
23799 this.onEndDrag(this.dragData, e);
23803 onEndDrag : function(data, e){
23806 // private - pin to cursor
23807 autoOffset : function(x, y) {
23808 this.setDelta(-12, -20);
23812 * Ext JS Library 1.1.1
23813 * Copyright(c) 2006-2007, Ext JS, LLC.
23815 * Originally Released Under LGPL - original licence link has changed is not relivant.
23818 * <script type="text/javascript">
23823 * @class Roo.dd.DropTarget
23824 * @extends Roo.dd.DDTarget
23825 * A simple class that provides the basic implementation needed to make any element a drop target that can have
23826 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
23828 * @param {String/HTMLElement/Element} el The container element
23829 * @param {Object} config
23831 Roo.dd.DropTarget = function(el, config){
23832 this.el = Roo.get(el);
23834 var listeners = false; ;
23835 if (config && config.listeners) {
23836 listeners= config.listeners;
23837 delete config.listeners;
23839 Roo.apply(this, config);
23841 if(this.containerScroll){
23842 Roo.dd.ScrollManager.register(this.el);
23846 * @scope Roo.dd.DropTarget
23851 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
23852 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
23853 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
23855 * IMPORTANT : it should set this.valid to true|false
23857 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23858 * @param {Event} e The event
23859 * @param {Object} data An object containing arbitrary data supplied by the drag source
23865 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
23866 * This method will be called on every mouse movement while the drag source is over the drop target.
23867 * This default implementation simply returns the dropAllowed config value.
23869 * IMPORTANT : it should set this.valid to true|false
23871 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23872 * @param {Event} e The event
23873 * @param {Object} data An object containing arbitrary data supplied by the drag source
23879 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
23880 * out of the target without dropping. This default implementation simply removes the CSS class specified by
23881 * overClass (if any) from the drop element.
23884 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23885 * @param {Event} e The event
23886 * @param {Object} data An object containing arbitrary data supplied by the drag source
23892 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
23893 * been dropped on it. This method has no default implementation and returns false, so you must provide an
23894 * implementation that does something to process the drop event and returns true so that the drag source's
23895 * repair action does not run.
23897 * IMPORTANT : it should set this.success
23899 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23900 * @param {Event} e The event
23901 * @param {Object} data An object containing arbitrary data supplied by the drag source
23907 Roo.dd.DropTarget.superclass.constructor.call( this,
23909 this.ddGroup || this.group,
23912 listeners : listeners || {}
23920 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
23922 * @cfg {String} overClass
23923 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
23926 * @cfg {String} ddGroup
23927 * The drag drop group to handle drop events for
23931 * @cfg {String} dropAllowed
23932 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23934 dropAllowed : "x-dd-drop-ok",
23936 * @cfg {String} dropNotAllowed
23937 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23939 dropNotAllowed : "x-dd-drop-nodrop",
23941 * @cfg {boolean} success
23942 * set this after drop listener..
23946 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
23947 * if the drop point is valid for over/enter..
23954 isNotifyTarget : true,
23959 notifyEnter : function(dd, e, data)
23962 this.fireEvent('enter', dd, e, data);
23963 if(this.overClass){
23964 this.el.addClass(this.overClass);
23966 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23967 this.valid ? this.dropAllowed : this.dropNotAllowed
23974 notifyOver : function(dd, e, data)
23977 this.fireEvent('over', dd, e, data);
23978 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23979 this.valid ? this.dropAllowed : this.dropNotAllowed
23986 notifyOut : function(dd, e, data)
23988 this.fireEvent('out', dd, e, data);
23989 if(this.overClass){
23990 this.el.removeClass(this.overClass);
23997 notifyDrop : function(dd, e, data)
23999 this.success = false;
24000 this.fireEvent('drop', dd, e, data);
24001 return this.success;
24005 * Ext JS Library 1.1.1
24006 * Copyright(c) 2006-2007, Ext JS, LLC.
24008 * Originally Released Under LGPL - original licence link has changed is not relivant.
24011 * <script type="text/javascript">
24016 * @class Roo.dd.DragZone
24017 * @extends Roo.dd.DragSource
24018 * This class provides a container DD instance that proxies for multiple child node sources.<br />
24019 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
24021 * @param {String/HTMLElement/Element} el The container element
24022 * @param {Object} config
24024 Roo.dd.DragZone = function(el, config){
24025 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
24026 if(this.containerScroll){
24027 Roo.dd.ScrollManager.register(this.el);
24031 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
24033 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
24034 * for auto scrolling during drag operations.
24037 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
24038 * method after a failed drop (defaults to "c3daf9" - light blue)
24042 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
24043 * for a valid target to drag based on the mouse down. Override this method
24044 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
24045 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
24046 * @param {EventObject} e The mouse down event
24047 * @return {Object} The dragData
24049 getDragData : function(e){
24050 return Roo.dd.Registry.getHandleFromEvent(e);
24054 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
24055 * this.dragData.ddel
24056 * @param {Number} x The x position of the click on the dragged object
24057 * @param {Number} y The y position of the click on the dragged object
24058 * @return {Boolean} true to continue the drag, false to cancel
24060 onInitDrag : function(x, y){
24061 this.proxy.update(this.dragData.ddel.cloneNode(true));
24062 this.onStartDrag(x, y);
24067 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
24069 afterRepair : function(){
24071 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
24073 this.dragging = false;
24077 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
24078 * the XY of this.dragData.ddel
24079 * @param {EventObject} e The mouse up event
24080 * @return {Array} The xy location (e.g. [100, 200])
24082 getRepairXY : function(e){
24083 return Roo.Element.fly(this.dragData.ddel).getXY();
24087 * Ext JS Library 1.1.1
24088 * Copyright(c) 2006-2007, Ext JS, LLC.
24090 * Originally Released Under LGPL - original licence link has changed is not relivant.
24093 * <script type="text/javascript">
24096 * @class Roo.dd.DropZone
24097 * @extends Roo.dd.DropTarget
24098 * This class provides a container DD instance that proxies for multiple child node targets.<br />
24099 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
24101 * @param {String/HTMLElement/Element} el The container element
24102 * @param {Object} config
24104 Roo.dd.DropZone = function(el, config){
24105 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
24108 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
24110 * Returns a custom data object associated with the DOM node that is the target of the event. By default
24111 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
24112 * provide your own custom lookup.
24113 * @param {Event} e The event
24114 * @return {Object} data The custom data
24116 getTargetFromEvent : function(e){
24117 return Roo.dd.Registry.getTargetFromEvent(e);
24121 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
24122 * that it has registered. This method has no default implementation and should be overridden to provide
24123 * node-specific processing if necessary.
24124 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24125 * {@link #getTargetFromEvent} for this node)
24126 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24127 * @param {Event} e The event
24128 * @param {Object} data An object containing arbitrary data supplied by the drag source
24130 onNodeEnter : function(n, dd, e, data){
24135 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
24136 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
24137 * overridden to provide the proper feedback.
24138 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24139 * {@link #getTargetFromEvent} for this node)
24140 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24141 * @param {Event} e The event
24142 * @param {Object} data An object containing arbitrary data supplied by the drag source
24143 * @return {String} status The CSS class that communicates the drop status back to the source so that the
24144 * underlying {@link Roo.dd.StatusProxy} can be updated
24146 onNodeOver : function(n, dd, e, data){
24147 return this.dropAllowed;
24151 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
24152 * the drop node without dropping. This method has no default implementation and should be overridden to provide
24153 * node-specific processing if necessary.
24154 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24155 * {@link #getTargetFromEvent} for this node)
24156 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24157 * @param {Event} e The event
24158 * @param {Object} data An object containing arbitrary data supplied by the drag source
24160 onNodeOut : function(n, dd, e, data){
24165 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
24166 * the drop node. The default implementation returns false, so it should be overridden to provide the
24167 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
24168 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24169 * {@link #getTargetFromEvent} for this node)
24170 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24171 * @param {Event} e The event
24172 * @param {Object} data An object containing arbitrary data supplied by the drag source
24173 * @return {Boolean} True if the drop was valid, else false
24175 onNodeDrop : function(n, dd, e, data){
24180 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
24181 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
24182 * it should be overridden to provide the proper feedback if necessary.
24183 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24184 * @param {Event} e The event
24185 * @param {Object} data An object containing arbitrary data supplied by the drag source
24186 * @return {String} status The CSS class that communicates the drop status back to the source so that the
24187 * underlying {@link Roo.dd.StatusProxy} can be updated
24189 onContainerOver : function(dd, e, data){
24190 return this.dropNotAllowed;
24194 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
24195 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
24196 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
24197 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
24198 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24199 * @param {Event} e The event
24200 * @param {Object} data An object containing arbitrary data supplied by the drag source
24201 * @return {Boolean} True if the drop was valid, else false
24203 onContainerDrop : function(dd, e, data){
24208 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
24209 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
24210 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
24211 * you should override this method and provide a custom implementation.
24212 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24213 * @param {Event} e The event
24214 * @param {Object} data An object containing arbitrary data supplied by the drag source
24215 * @return {String} status The CSS class that communicates the drop status back to the source so that the
24216 * underlying {@link Roo.dd.StatusProxy} can be updated
24218 notifyEnter : function(dd, e, data){
24219 return this.dropNotAllowed;
24223 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
24224 * This method will be called on every mouse movement while the drag source is over the drop zone.
24225 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
24226 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
24227 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
24228 * registered node, it will call {@link #onContainerOver}.
24229 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24230 * @param {Event} e The event
24231 * @param {Object} data An object containing arbitrary data supplied by the drag source
24232 * @return {String} status The CSS class that communicates the drop status back to the source so that the
24233 * underlying {@link Roo.dd.StatusProxy} can be updated
24235 notifyOver : function(dd, e, data){
24236 var n = this.getTargetFromEvent(e);
24237 if(!n){ // not over valid drop target
24238 if(this.lastOverNode){
24239 this.onNodeOut(this.lastOverNode, dd, e, data);
24240 this.lastOverNode = null;
24242 return this.onContainerOver(dd, e, data);
24244 if(this.lastOverNode != n){
24245 if(this.lastOverNode){
24246 this.onNodeOut(this.lastOverNode, dd, e, data);
24248 this.onNodeEnter(n, dd, e, data);
24249 this.lastOverNode = n;
24251 return this.onNodeOver(n, dd, e, data);
24255 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
24256 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
24257 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
24258 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24259 * @param {Event} e The event
24260 * @param {Object} data An object containing arbitrary data supplied by the drag zone
24262 notifyOut : function(dd, e, data){
24263 if(this.lastOverNode){
24264 this.onNodeOut(this.lastOverNode, dd, e, data);
24265 this.lastOverNode = null;
24270 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
24271 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
24272 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
24273 * otherwise it will call {@link #onContainerDrop}.
24274 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24275 * @param {Event} e The event
24276 * @param {Object} data An object containing arbitrary data supplied by the drag source
24277 * @return {Boolean} True if the drop was valid, else false
24279 notifyDrop : function(dd, e, data){
24280 if(this.lastOverNode){
24281 this.onNodeOut(this.lastOverNode, dd, e, data);
24282 this.lastOverNode = null;
24284 var n = this.getTargetFromEvent(e);
24286 this.onNodeDrop(n, dd, e, data) :
24287 this.onContainerDrop(dd, e, data);
24291 triggerCacheRefresh : function(){
24292 Roo.dd.DDM.refreshCache(this.groups);