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");
508 // internal (non-delayed, will get a return value..)
509 callback : function(cb, scope, args, delay)
511 if(typeof cb != "function"){
515 cb.defer(delay, scope, args || []);
518 return cb.apply(scope, args || []);
523 * Return the dom node for the passed string (id), dom node, or Roo.Element
524 * @param {String/HTMLElement/Roo.Element} el
525 * @return HTMLElement
527 getDom : function(el){
531 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
535 * Shorthand for {@link Roo.ComponentMgr#get}
537 * @return Roo.Component
539 getCmp : function(id){
540 return Roo.ComponentMgr.get(id);
543 num : function(v, defaultValue){
544 if(typeof v != 'number'){
550 destroy : function(){
551 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
555 as.removeAllListeners();
559 if(typeof as.purgeListeners == 'function'){
562 if(typeof as.destroy == 'function'){
569 // inpired by a similar function in mootools library
571 * Returns the type of object that is passed in. If the object passed in is null or undefined it
572 * return false otherwise it returns one of the following values:<ul>
573 * <li><b>string</b>: If the object passed is a string</li>
574 * <li><b>number</b>: If the object passed is a number</li>
575 * <li><b>boolean</b>: If the object passed is a boolean value</li>
576 * <li><b>function</b>: If the object passed is a function reference</li>
577 * <li><b>object</b>: If the object passed is an object</li>
578 * <li><b>array</b>: If the object passed is an array</li>
579 * <li><b>regexp</b>: If the object passed is a regular expression</li>
580 * <li><b>element</b>: If the object passed is a DOM Element</li>
581 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
582 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
583 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
584 * @param {Mixed} object
588 if(o === undefined || o === null){
595 if(t == 'object' && o.nodeName) {
597 case 1: return 'element';
598 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
601 if(t == 'object' || t == 'function') {
602 switch(o.constructor) {
603 case Array: return 'array';
604 case RegExp: return 'regexp';
606 if(typeof o.length == 'number' && typeof o.item == 'function') {
614 * Returns true if the passed value is null, undefined or an empty string (optional).
615 * @param {Mixed} value The value to test
616 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
619 isEmpty : function(v, allowBlank){
620 return v === null || v === undefined || (!allowBlank ? v === '' : false);
628 isFirefox : isFirefox,
640 isBorderBox : isBorderBox,
642 isWindows : isWindows,
650 isAndroid : isAndroid,
655 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
656 * you may want to set this to true.
659 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
664 * Selects a single element as a Roo Element
665 * This is about as close as you can get to jQuery's $('do crazy stuff')
666 * @param {String} selector The selector/xpath query
667 * @param {Node} root (optional) The start of the query (defaults to document).
668 * @return {Roo.Element}
670 selectNode : function(selector, root)
672 var node = Roo.DomQuery.selectNode(selector,root);
673 return node ? Roo.get(node) : new Roo.Element(false);
676 * Find the current bootstrap width Grid size
677 * Note xs is the default for smaller.. - this is currently used by grids to render correct columns
678 * @returns {String} (xs|sm|md|lg|xl)
681 getGridSize : function()
683 var w = Roo.lib.Dom.getViewWidth();
704 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
705 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
710 * Ext JS Library 1.1.1
711 * Copyright(c) 2006-2007, Ext JS, LLC.
713 * Originally Released Under LGPL - original licence link has changed is not relivant.
716 * <script type="text/javascript">
720 // wrappedn so fnCleanup is not in global scope...
722 function fnCleanUp() {
723 var p = Function.prototype;
724 delete p.createSequence;
726 delete p.createDelegate;
727 delete p.createCallback;
728 delete p.createInterceptor;
730 window.detachEvent("onunload", fnCleanUp);
732 window.attachEvent("onunload", fnCleanUp);
739 * These functions are available on every Function object (any JavaScript function).
741 Roo.apply(Function.prototype, {
743 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
744 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
745 * Will create a function that is bound to those 2 args.
746 * @return {Function} The new function
748 createCallback : function(/*args...*/){
749 // make args available, in function below
750 var args = arguments;
753 return method.apply(window, args);
758 * Creates a delegate (callback) that sets the scope to obj.
759 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
760 * Will create a function that is automatically scoped to this.
761 * @param {Object} obj (optional) The object for which the scope is set
762 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
763 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
764 * if a number the args are inserted at the specified position
765 * @return {Function} The new function
767 createDelegate : function(obj, args, appendArgs){
770 var callArgs = args || arguments;
771 if(appendArgs === true){
772 callArgs = Array.prototype.slice.call(arguments, 0);
773 callArgs = callArgs.concat(args);
774 }else if(typeof appendArgs == "number"){
775 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
776 var applyArgs = [appendArgs, 0].concat(args); // create method call params
777 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
779 return method.apply(obj || window, callArgs);
784 * Calls this function after the number of millseconds specified.
785 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
786 * @param {Object} obj (optional) The object for which the scope is set
787 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
788 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
789 * if a number the args are inserted at the specified position
790 * @return {Number} The timeout id that can be used with clearTimeout
792 defer : function(millis, obj, args, appendArgs){
793 var fn = this.createDelegate(obj, args, appendArgs);
795 return setTimeout(fn, millis);
801 * Create a combined function call sequence of the original function + the passed function.
802 * The resulting function returns the results of the original function.
803 * The passed fcn is called with the parameters of the original function
804 * @param {Function} fcn The function to sequence
805 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
806 * @return {Function} The new function
808 createSequence : function(fcn, scope){
809 if(typeof fcn != "function"){
814 var retval = method.apply(this || window, arguments);
815 fcn.apply(scope || this || window, arguments);
821 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
822 * The resulting function returns the results of the original function.
823 * The passed fcn is called with the parameters of the original function.
825 * @param {Function} fcn The function to call before the original
826 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
827 * @return {Function} The new function
829 createInterceptor : function(fcn, scope){
830 if(typeof fcn != "function"){
837 if(fcn.apply(scope || this || window, arguments) === false){
840 return method.apply(this || window, arguments);
846 * Ext JS Library 1.1.1
847 * Copyright(c) 2006-2007, Ext JS, LLC.
849 * Originally Released Under LGPL - original licence link has changed is not relivant.
852 * <script type="text/javascript">
855 Roo.applyIf(String, {
860 * Escapes the passed string for ' and \
861 * @param {String} string The string to escape
862 * @return {String} The escaped string
865 escape : function(string) {
866 return string.replace(/('|\\)/g, "\\$1");
870 * Pads the left side of a string with a specified character. This is especially useful
871 * for normalizing number and date strings. Example usage:
873 var s = String.leftPad('123', 5, '0');
874 // s now contains the string: '00123'
876 * @param {String} string The original string
877 * @param {Number} size The total length of the output string
878 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
879 * @return {String} The padded string
882 leftPad : function (val, size, ch) {
883 var result = new String(val);
884 if(ch === null || ch === undefined || ch === '') {
887 while (result.length < size) {
888 result = ch + result;
894 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
895 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
897 var cls = 'my-class', text = 'Some text';
898 var s = String.format('<div class="{0}">{1}</div>', cls, text);
899 // s now contains the string: '<div class="my-class">Some text</div>'
901 * @param {String} string The tokenized string to be formatted
902 * @param {String} value1 The value to replace token {0}
903 * @param {String} value2 Etc...
904 * @return {String} The formatted string
907 format : function(format){
908 var args = Array.prototype.slice.call(arguments, 1);
909 return format.replace(/\{(\d+)\}/g, function(m, i){
910 return Roo.util.Format.htmlEncode(args[i]);
918 * Utility function that allows you to easily switch a string between two alternating values. The passed value
919 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
920 * they are already different, the first value passed in is returned. Note that this method returns the new value
921 * but does not change the current string.
923 // alternate sort directions
924 sort = sort.toggle('ASC', 'DESC');
926 // instead of conditional logic:
927 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
929 * @param {String} value The value to compare to the current string
930 * @param {String} other The new value to use if the string already equals the first value passed in
931 * @return {String} The new value
934 String.prototype.toggle = function(value, other){
935 return this == value ? other : value;
940 * Remove invalid unicode characters from a string
942 * @return {String} The clean string
944 String.prototype.unicodeClean = function () {
945 return this.replace(/[\s\S]/g,
946 function(character) {
947 if (character.charCodeAt()< 256) {
951 encodeURIComponent(character);
962 * Make the first letter of a string uppercase
964 * @return {String} The new string.
966 String.prototype.toUpperCaseFirst = function () {
967 return this.charAt(0).toUpperCase() + this.slice(1);
972 * Ext JS Library 1.1.1
973 * Copyright(c) 2006-2007, Ext JS, LLC.
975 * Originally Released Under LGPL - original licence link has changed is not relivant.
978 * <script type="text/javascript">
984 Roo.applyIf(Number.prototype, {
986 * Checks whether or not the current number is within a desired range. If the number is already within the
987 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
988 * exceeded. Note that this method returns the constrained value but does not change the current number.
989 * @param {Number} min The minimum number in the range
990 * @param {Number} max The maximum number in the range
991 * @return {Number} The constrained value if outside the range, otherwise the current value
993 constrain : function(min, max){
994 return Math.min(Math.max(this, min), max);
998 * Ext JS Library 1.1.1
999 * Copyright(c) 2006-2007, Ext JS, LLC.
1001 * Originally Released Under LGPL - original licence link has changed is not relivant.
1004 * <script type="text/javascript">
1009 Roo.applyIf(Array.prototype, {
1012 * Checks whether or not the specified object exists in the array.
1013 * @param {Object} o The object to check for
1014 * @return {Number} The index of o in the array (or -1 if it is not found)
1016 indexOf : function(o){
1017 for (var i = 0, len = this.length; i < len; i++){
1018 if(this[i] == o) { return i; }
1024 * Removes the specified object from the array. If the object is not found nothing happens.
1025 * @param {Object} o The object to remove
1027 remove : function(o){
1028 var index = this.indexOf(o);
1030 this.splice(index, 1);
1034 * Map (JS 1.6 compatibility)
1035 * @param {Function} function to call
1037 map : function(fun )
1039 var len = this.length >>> 0;
1040 if (typeof fun != "function") {
1041 throw new TypeError();
1043 var res = new Array(len);
1044 var thisp = arguments[1];
1045 for (var i = 0; i < len; i++)
1048 res[i] = fun.call(thisp, this[i], i, this);
1056 * @param {Array} o The array to compare to
1057 * @returns {Boolean} true if the same
1059 equals : function(b)
1061 // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
1068 if (this.length !== b.length) {
1072 // sort?? a.sort().equals(b.sort());
1074 for (var i = 0; i < this.length; ++i) {
1075 if (this[i] !== b[i]) {
1087 Roo.applyIf(Array, {
1091 * @param {Array} o Or Array like object (eg. nodelist)
1098 for (var i =0; i < o.length; i++) {
1107 * Ext JS Library 1.1.1
1108 * Copyright(c) 2006-2007, Ext JS, LLC.
1110 * Originally Released Under LGPL - original licence link has changed is not relivant.
1113 * <script type="text/javascript">
1119 * The date parsing and format syntax is a subset of
1120 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1121 * supported will provide results equivalent to their PHP versions.
1123 * Following is the list of all currently supported formats:
1126 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1128 Format Output Description
1129 ------ ---------- --------------------------------------------------------------
1130 d 10 Day of the month, 2 digits with leading zeros
1131 D Wed A textual representation of a day, three letters
1132 j 10 Day of the month without leading zeros
1133 l Wednesday A full textual representation of the day of the week
1134 S th English ordinal day of month suffix, 2 chars (use with j)
1135 w 3 Numeric representation of the day of the week
1136 z 9 The julian date, or day of the year (0-365)
1137 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1138 F January A full textual representation of the month
1139 m 01 Numeric representation of a month, with leading zeros
1140 M Jan Month name abbreviation, three letters
1141 n 1 Numeric representation of a month, without leading zeros
1142 t 31 Number of days in the given month
1143 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1144 Y 2007 A full numeric representation of a year, 4 digits
1145 y 07 A two digit representation of a year
1146 a pm Lowercase Ante meridiem and Post meridiem
1147 A PM Uppercase Ante meridiem and Post meridiem
1148 g 3 12-hour format of an hour without leading zeros
1149 G 15 24-hour format of an hour without leading zeros
1150 h 03 12-hour format of an hour with leading zeros
1151 H 15 24-hour format of an hour with leading zeros
1152 i 05 Minutes with leading zeros
1153 s 01 Seconds, with leading zeros
1154 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1155 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1156 T CST Timezone setting of the machine running the code
1157 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1160 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1162 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1163 document.write(dt.format('Y-m-d')); //2007-01-10
1164 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1165 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
1168 * Here are some standard date/time patterns that you might find helpful. They
1169 * are not part of the source of Date.js, but to use them you can simply copy this
1170 * block of code into any script that is included after Date.js and they will also become
1171 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1174 ISO8601Long:"Y-m-d H:i:s",
1175 ISO8601Short:"Y-m-d",
1177 LongDate: "l, F d, Y",
1178 FullDateTime: "l, F d, Y g:i:s A",
1181 LongTime: "g:i:s A",
1182 SortableDateTime: "Y-m-d\\TH:i:s",
1183 UniversalSortableDateTime: "Y-m-d H:i:sO",
1190 var dt = new Date();
1191 document.write(dt.format(Date.patterns.ShortDate));
1196 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1197 * They generate precompiled functions from date formats instead of parsing and
1198 * processing the pattern every time you format a date. These functions are available
1199 * on every Date object (any javascript function).
1201 * The original article and download are here:
1202 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1209 Returns the number of milliseconds between this date and date
1210 @param {Date} date (optional) Defaults to now
1211 @param {String} interval (optional) Default Date.MILLI, A valid date interval enum value (eg. Date.DAY)
1212 @return {Number} The diff in milliseconds or units of interval
1213 @member Date getElapsed
1215 Date.prototype.getElapsed = function(date, interval)
1217 date = date || new Date();
1218 var ret = Math.abs(date.getTime()-this.getTime());
1222 return Math.floor(ret / (1000));
1224 return Math.floor(ret / (1000*60));
1226 return Math.floor(ret / (1000*60*60));
1228 return Math.floor(ret / (1000*60*60*24));
1229 case Date.MONTH: // this does not give exact number...??
1230 return ((date.format("Y") - this.format("Y")) * 12) + (date.format("m") - this.format("m"));
1231 case Date.YEAR: // this does not give exact number...??
1232 return (date.format("Y") - this.format("Y"));
1240 // was in date file..
1244 Date.parseFunctions = {count:0};
1246 Date.parseRegexes = [];
1248 Date.formatFunctions = {count:0};
1251 Date.prototype.dateFormat = function(format) {
1252 if (Date.formatFunctions[format] == null) {
1253 Date.createNewFormat(format);
1255 var func = Date.formatFunctions[format];
1256 return this[func]();
1261 * Formats a date given the supplied format string
1262 * @param {String} format The format string
1263 * @return {String} The formatted date
1266 Date.prototype.format = Date.prototype.dateFormat;
1269 Date.createNewFormat = function(format) {
1270 var funcName = "format" + Date.formatFunctions.count++;
1271 Date.formatFunctions[format] = funcName;
1272 var code = "Date.prototype." + funcName + " = function(){return ";
1273 var special = false;
1275 for (var i = 0; i < format.length; ++i) {
1276 ch = format.charAt(i);
1277 if (!special && ch == "\\") {
1282 code += "'" + String.escape(ch) + "' + ";
1285 code += Date.getFormatCode(ch);
1288 /** eval:var:zzzzzzzzzzzzz */
1289 eval(code.substring(0, code.length - 3) + ";}");
1293 Date.getFormatCode = function(character) {
1294 switch (character) {
1296 return "String.leftPad(this.getDate(), 2, '0') + ";
1298 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1300 return "this.getDate() + ";
1302 return "Date.dayNames[this.getDay()] + ";
1304 return "this.getSuffix() + ";
1306 return "this.getDay() + ";
1308 return "this.getDayOfYear() + ";
1310 return "this.getWeekOfYear() + ";
1312 return "Date.monthNames[this.getMonth()] + ";
1314 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1316 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1318 return "(this.getMonth() + 1) + ";
1320 return "this.getDaysInMonth() + ";
1322 return "(this.isLeapYear() ? 1 : 0) + ";
1324 return "this.getFullYear() + ";
1326 return "('' + this.getFullYear()).substring(2, 4) + ";
1328 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1330 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1332 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1334 return "this.getHours() + ";
1336 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1338 return "String.leftPad(this.getHours(), 2, '0') + ";
1340 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1342 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1344 return "this.getGMTOffset() + ";
1346 return "this.getGMTColonOffset() + ";
1348 return "this.getTimezone() + ";
1350 return "(this.getTimezoneOffset() * -60) + ";
1352 return "'" + String.escape(character) + "' + ";
1357 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1358 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1359 * the date format that is not specified will default to the current date value for that part. Time parts can also
1360 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1361 * string or the parse operation will fail.
1364 //dt = Fri May 25 2007 (current date)
1365 var dt = new Date();
1367 //dt = Thu May 25 2006 (today's month/day in 2006)
1368 dt = Date.parseDate("2006", "Y");
1370 //dt = Sun Jan 15 2006 (all date parts specified)
1371 dt = Date.parseDate("2006-1-15", "Y-m-d");
1373 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1374 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1376 * @param {String} input The unparsed date as a string
1377 * @param {String} format The format the date is in
1378 * @return {Date} The parsed date
1381 Date.parseDate = function(input, format) {
1382 if (Date.parseFunctions[format] == null) {
1383 Date.createParser(format);
1385 var func = Date.parseFunctions[format];
1386 return Date[func](input);
1392 Date.createParser = function(format) {
1393 var funcName = "parse" + Date.parseFunctions.count++;
1394 var regexNum = Date.parseRegexes.length;
1395 var currentGroup = 1;
1396 Date.parseFunctions[format] = funcName;
1398 var code = "Date." + funcName + " = function(input){\n"
1399 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1400 + "var d = new Date();\n"
1401 + "y = d.getFullYear();\n"
1402 + "m = d.getMonth();\n"
1403 + "d = d.getDate();\n"
1404 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1405 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1406 + "if (results && results.length > 0) {";
1409 var special = false;
1411 for (var i = 0; i < format.length; ++i) {
1412 ch = format.charAt(i);
1413 if (!special && ch == "\\") {
1418 regex += String.escape(ch);
1421 var obj = Date.formatCodeToRegex(ch, currentGroup);
1422 currentGroup += obj.g;
1424 if (obj.g && obj.c) {
1430 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1431 + "{v = new Date(y, m, d, h, i, s); v.setFullYear(y);}\n"
1432 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1433 + "{v = new Date(y, m, d, h, i); v.setFullYear(y);}\n"
1434 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1435 + "{v = new Date(y, m, d, h); v.setFullYear(y);}\n"
1436 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1437 + "{v = new Date(y, m, d); v.setFullYear(y);}\n"
1438 + "else if (y >= 0 && m >= 0)\n"
1439 + "{v = new Date(y, m); v.setFullYear(y);}\n"
1440 + "else if (y >= 0)\n"
1441 + "{v = new Date(y); v.setFullYear(y);}\n"
1442 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1443 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1444 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1447 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1448 /** eval:var:zzzzzzzzzzzzz */
1453 Date.formatCodeToRegex = function(character, currentGroup) {
1454 switch (character) {
1458 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1461 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1462 s:"(\\d{1,2})"}; // day of month without leading zeroes
1465 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1466 s:"(\\d{2})"}; // day of month with leading zeroes
1470 s:"(?:" + Date.dayNames.join("|") + ")"};
1474 s:"(?:st|nd|rd|th)"};
1489 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1490 s:"(" + Date.monthNames.join("|") + ")"};
1493 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1494 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1497 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1498 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1501 c:"m = Math.max(0,parseInt(results[" + currentGroup + "], 10) - 1);\n",
1502 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1513 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1517 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1518 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1522 c:"if (results[" + currentGroup + "] == 'am') {\n"
1523 + "if (h == 12) { h = 0; }\n"
1524 + "} else { if (h < 12) { h += 12; }}",
1528 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1529 + "if (h == 12) { h = 0; }\n"
1530 + "} else { if (h < 12) { h += 12; }}",
1535 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1536 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1540 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1541 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1544 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1548 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1553 "o = results[", currentGroup, "];\n",
1554 "var sn = o.substring(0,1);\n", // get + / - sign
1555 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1556 "var mn = o.substring(3,5) % 60;\n", // get minutes
1557 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1558 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1560 s:"([+\-]\\d{2,4})"};
1566 "o = results[", currentGroup, "];\n",
1567 "var sn = o.substring(0,1);\n",
1568 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1569 "var mn = o.substring(4,6) % 60;\n",
1570 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1571 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1577 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1580 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1581 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1582 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1586 s:String.escape(character)};
1591 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1592 * @return {String} The abbreviated timezone name (e.g. 'CST')
1594 Date.prototype.getTimezone = function() {
1595 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1599 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1600 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1602 Date.prototype.getGMTOffset = function() {
1603 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1604 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1605 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1609 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1610 * @return {String} 2-characters representing hours and 2-characters representing minutes
1611 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1613 Date.prototype.getGMTColonOffset = function() {
1614 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1615 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1617 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1621 * Get the numeric day number of the year, adjusted for leap year.
1622 * @return {Number} 0 through 364 (365 in leap years)
1624 Date.prototype.getDayOfYear = function() {
1626 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1627 for (var i = 0; i < this.getMonth(); ++i) {
1628 num += Date.daysInMonth[i];
1630 return num + this.getDate() - 1;
1634 * Get the string representation of the numeric week number of the year
1635 * (equivalent to the format specifier 'W').
1636 * @return {String} '00' through '52'
1638 Date.prototype.getWeekOfYear = function() {
1639 // Skip to Thursday of this week
1640 var now = this.getDayOfYear() + (4 - this.getDay());
1641 // Find the first Thursday of the year
1642 var jan1 = new Date(this.getFullYear(), 0, 1);
1643 var then = (7 - jan1.getDay() + 4);
1644 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1648 * Whether or not the current date is in a leap year.
1649 * @return {Boolean} True if the current date is in a leap year, else false
1651 Date.prototype.isLeapYear = function() {
1652 var year = this.getFullYear();
1653 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1657 * Get the first day of the current month, adjusted for leap year. The returned value
1658 * is the numeric day index within the week (0-6) which can be used in conjunction with
1659 * the {@link #monthNames} array to retrieve the textual day name.
1662 var dt = new Date('1/10/2007');
1663 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1665 * @return {Number} The day number (0-6)
1667 Date.prototype.getFirstDayOfMonth = function() {
1668 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1669 return (day < 0) ? (day + 7) : day;
1673 * Get the last day of the current month, adjusted for leap year. The returned value
1674 * is the numeric day index within the week (0-6) which can be used in conjunction with
1675 * the {@link #monthNames} array to retrieve the textual day name.
1678 var dt = new Date('1/10/2007');
1679 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1681 * @return {Number} The day number (0-6)
1683 Date.prototype.getLastDayOfMonth = function() {
1684 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1685 return (day < 0) ? (day + 7) : day;
1690 * Get the first date of this date's month
1693 Date.prototype.getFirstDateOfMonth = function() {
1694 return new Date(this.getFullYear(), this.getMonth(), 1);
1698 * Get the last date of this date's month
1701 Date.prototype.getLastDateOfMonth = function() {
1702 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1705 * Get the number of days in the current month, adjusted for leap year.
1706 * @return {Number} The number of days in the month
1708 Date.prototype.getDaysInMonth = function() {
1709 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1710 return Date.daysInMonth[this.getMonth()];
1714 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1715 * @return {String} 'st, 'nd', 'rd' or 'th'
1717 Date.prototype.getSuffix = function() {
1718 switch (this.getDate()) {
1735 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1738 * An array of textual month names.
1739 * Override these values for international dates, for example...
1740 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1759 * An array of textual day names.
1760 * Override these values for international dates, for example...
1761 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1777 Date.monthNumbers = {
1792 * Creates and returns a new Date instance with the exact same date value as the called instance.
1793 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1794 * variable will also be changed. When the intention is to create a new variable that will not
1795 * modify the original instance, you should create a clone.
1797 * Example of correctly cloning a date:
1800 var orig = new Date('10/1/2006');
1803 document.write(orig); //returns 'Thu Oct 05 2006'!
1806 var orig = new Date('10/1/2006');
1807 var copy = orig.clone();
1809 document.write(orig); //returns 'Thu Oct 01 2006'
1811 * @return {Date} The new Date instance
1813 Date.prototype.clone = function() {
1814 return new Date(this.getTime());
1818 * Clears any time information from this date
1819 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1820 @return {Date} this or the clone
1822 Date.prototype.clearTime = function(clone){
1824 return this.clone().clearTime();
1829 this.setMilliseconds(0);
1834 // safari setMonth is broken -- check that this is only donw once...
1835 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1836 Date.brokenSetMonth = Date.prototype.setMonth;
1837 Date.prototype.setMonth = function(num){
1839 var n = Math.ceil(-num);
1840 var back_year = Math.ceil(n/12);
1841 var month = (n % 12) ? 12 - n % 12 : 0 ;
1842 this.setFullYear(this.getFullYear() - back_year);
1843 return Date.brokenSetMonth.call(this, month);
1845 return Date.brokenSetMonth.apply(this, arguments);
1850 /** Date interval constant
1854 /** Date interval constant
1858 /** Date interval constant
1862 /** Date interval constant
1866 /** Date interval constant
1870 /** Date interval constant
1874 /** Date interval constant
1880 * Provides a convenient method of performing basic date arithmetic. This method
1881 * does not modify the Date instance being called - it creates and returns
1882 * a new Date instance containing the resulting date value.
1887 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1888 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1890 //Negative values will subtract correctly:
1891 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1892 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1894 //You can even chain several calls together in one line!
1895 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1896 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1899 * @param {String} interval A valid date interval enum value
1900 * @param {Number} value The amount to add to the current date
1901 * @return {Date} The new Date instance
1903 Date.prototype.add = function(interval, value){
1904 var d = this.clone();
1905 if (!interval || value === 0) { return d; }
1906 switch(interval.toLowerCase()){
1908 d.setMilliseconds(this.getMilliseconds() + value);
1911 d.setSeconds(this.getSeconds() + value);
1914 d.setMinutes(this.getMinutes() + value);
1917 d.setHours(this.getHours() + value);
1920 d.setDate(this.getDate() + value);
1923 var day = this.getDate();
1925 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1928 d.setMonth(this.getMonth() + value);
1931 d.setFullYear(this.getFullYear() + value);
1937 * @class Roo.lib.Dom
1941 * Dom utils (from YIU afaik)
1947 * Get the view width
1948 * @param {Boolean} full True will get the full document, otherwise it's the view width
1949 * @return {Number} The width
1952 getViewWidth : function(full) {
1953 return full ? this.getDocumentWidth() : this.getViewportWidth();
1956 * Get the view height
1957 * @param {Boolean} full True will get the full document, otherwise it's the view height
1958 * @return {Number} The height
1960 getViewHeight : function(full) {
1961 return full ? this.getDocumentHeight() : this.getViewportHeight();
1964 * Get the Full Document height
1965 * @return {Number} The height
1967 getDocumentHeight: function() {
1968 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1969 return Math.max(scrollHeight, this.getViewportHeight());
1972 * Get the Full Document width
1973 * @return {Number} The width
1975 getDocumentWidth: function() {
1976 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1977 return Math.max(scrollWidth, this.getViewportWidth());
1980 * Get the Window Viewport height
1981 * @return {Number} The height
1983 getViewportHeight: function() {
1984 var height = self.innerHeight;
1985 var mode = document.compatMode;
1987 if ((mode || Roo.isIE) && !Roo.isOpera) {
1988 height = (mode == "CSS1Compat") ?
1989 document.documentElement.clientHeight :
1990 document.body.clientHeight;
1996 * Get the Window Viewport width
1997 * @return {Number} The width
1999 getViewportWidth: function() {
2000 var width = self.innerWidth;
2001 var mode = document.compatMode;
2003 if (mode || Roo.isIE) {
2004 width = (mode == "CSS1Compat") ?
2005 document.documentElement.clientWidth :
2006 document.body.clientWidth;
2011 isAncestor : function(p, c) {
2018 if (p.contains && !Roo.isSafari) {
2019 return p.contains(c);
2020 } else if (p.compareDocumentPosition) {
2021 return !!(p.compareDocumentPosition(c) & 16);
2023 var parent = c.parentNode;
2028 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
2031 parent = parent.parentNode;
2037 getRegion : function(el) {
2038 return Roo.lib.Region.getRegion(el);
2041 getY : function(el) {
2042 return this.getXY(el)[1];
2045 getX : function(el) {
2046 return this.getXY(el)[0];
2049 getXY : function(el) {
2050 var p, pe, b, scroll, bd = document.body;
2051 el = Roo.getDom(el);
2052 var fly = Roo.lib.AnimBase.fly;
2053 if (el.getBoundingClientRect) {
2054 b = el.getBoundingClientRect();
2055 scroll = fly(document).getScroll();
2056 return [b.left + scroll.left, b.top + scroll.top];
2062 var hasAbsolute = fly(el).getStyle("position") == "absolute";
2069 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
2076 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
2077 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2084 if (p != el && pe.getStyle('overflow') != 'visible') {
2092 if (Roo.isSafari && hasAbsolute) {
2097 if (Roo.isGecko && !hasAbsolute) {
2099 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2100 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2104 while (p && p != bd) {
2105 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2117 setXY : function(el, xy) {
2118 el = Roo.fly(el, '_setXY');
2120 var pts = el.translatePoints(xy);
2121 if (xy[0] !== false) {
2122 el.dom.style.left = pts.left + "px";
2124 if (xy[1] !== false) {
2125 el.dom.style.top = pts.top + "px";
2129 setX : function(el, x) {
2130 this.setXY(el, [x, false]);
2133 setY : function(el, y) {
2134 this.setXY(el, [false, y]);
2138 * Portions of this file are based on pieces of Yahoo User Interface Library
2139 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2140 * YUI licensed under the BSD License:
2141 * http://developer.yahoo.net/yui/license.txt
2142 * <script type="text/javascript">
2146 Roo.lib.Event = function() {
2147 var loadComplete = false;
2149 var unloadListeners = [];
2151 var onAvailStack = [];
2153 var lastError = null;
2166 startInterval: function() {
2167 if (!this._interval) {
2169 var callback = function() {
2170 self._tryPreloadAttach();
2172 this._interval = setInterval(callback, this.POLL_INTERVAL);
2177 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2178 onAvailStack.push({ id: p_id,
2181 override: p_override,
2182 checkReady: false });
2184 retryCount = this.POLL_RETRYS;
2185 this.startInterval();
2189 addListener: function(el, eventName, fn) {
2190 el = Roo.getDom(el);
2195 if ("unload" == eventName) {
2196 unloadListeners[unloadListeners.length] =
2197 [el, eventName, fn];
2201 var wrappedFn = function(e) {
2202 return fn(Roo.lib.Event.getEvent(e));
2205 var li = [el, eventName, fn, wrappedFn];
2207 var index = listeners.length;
2208 listeners[index] = li;
2210 this.doAdd(el, eventName, wrappedFn, false);
2216 removeListener: function(el, eventName, fn) {
2219 el = Roo.getDom(el);
2222 return this.purgeElement(el, false, eventName);
2226 if ("unload" == eventName) {
2228 for (i = 0,len = unloadListeners.length; i < len; i++) {
2229 var li = unloadListeners[i];
2232 li[1] == eventName &&
2234 unloadListeners.splice(i, 1);
2242 var cacheItem = null;
2245 var index = arguments[3];
2247 if ("undefined" == typeof index) {
2248 index = this._getCacheIndex(el, eventName, fn);
2252 cacheItem = listeners[index];
2255 if (!el || !cacheItem) {
2259 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2261 delete listeners[index][this.WFN];
2262 delete listeners[index][this.FN];
2263 listeners.splice(index, 1);
2270 getTarget: function(ev, resolveTextNode) {
2271 ev = ev.browserEvent || ev;
2272 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2273 var t = ev.target || ev.srcElement;
2274 return this.resolveTextNode(t);
2278 resolveTextNode: function(node) {
2279 if (Roo.isSafari && node && 3 == node.nodeType) {
2280 return node.parentNode;
2287 getPageX: function(ev) {
2288 ev = ev.browserEvent || ev;
2289 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2291 if (!x && 0 !== x) {
2292 x = ev.clientX || 0;
2295 x += this.getScroll()[1];
2303 getPageY: function(ev) {
2304 ev = ev.browserEvent || ev;
2305 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2307 if (!y && 0 !== y) {
2308 y = ev.clientY || 0;
2311 y += this.getScroll()[0];
2320 getXY: function(ev) {
2321 ev = ev.browserEvent || ev;
2322 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2323 return [this.getPageX(ev), this.getPageY(ev)];
2327 getRelatedTarget: function(ev) {
2328 ev = ev.browserEvent || ev;
2329 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2330 var t = ev.relatedTarget;
2332 if (ev.type == "mouseout") {
2334 } else if (ev.type == "mouseover") {
2339 return this.resolveTextNode(t);
2343 getTime: function(ev) {
2344 ev = ev.browserEvent || ev;
2345 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2347 var t = new Date().getTime();
2351 this.lastError = ex;
2360 stopEvent: function(ev) {
2361 this.stopPropagation(ev);
2362 this.preventDefault(ev);
2366 stopPropagation: function(ev) {
2367 ev = ev.browserEvent || ev;
2368 if (ev.stopPropagation) {
2369 ev.stopPropagation();
2371 ev.cancelBubble = true;
2376 preventDefault: function(ev) {
2377 ev = ev.browserEvent || ev;
2378 if(ev.preventDefault) {
2379 ev.preventDefault();
2381 ev.returnValue = false;
2386 getEvent: function(e) {
2387 var ev = e || window.event;
2389 var c = this.getEvent.caller;
2391 ev = c.arguments[0];
2392 if (ev && Event == ev.constructor) {
2402 getCharCode: function(ev) {
2403 ev = ev.browserEvent || ev;
2404 return ev.charCode || ev.keyCode || 0;
2408 _getCacheIndex: function(el, eventName, fn) {
2409 for (var i = 0,len = listeners.length; i < len; ++i) {
2410 var li = listeners[i];
2412 li[this.FN] == fn &&
2413 li[this.EL] == el &&
2414 li[this.TYPE] == eventName) {
2426 getEl: function(id) {
2427 return document.getElementById(id);
2431 clearCache: function() {
2435 _load: function(e) {
2436 loadComplete = true;
2437 var EU = Roo.lib.Event;
2441 EU.doRemove(window, "load", EU._load);
2446 _tryPreloadAttach: function() {
2455 var tryAgain = !loadComplete;
2457 tryAgain = (retryCount > 0);
2462 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2463 var item = onAvailStack[i];
2465 var el = this.getEl(item.id);
2468 if (!item.checkReady ||
2471 (document && document.body)) {
2474 if (item.override) {
2475 if (item.override === true) {
2478 scope = item.override;
2481 item.fn.call(scope, item.obj);
2482 onAvailStack[i] = null;
2485 notAvail.push(item);
2490 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2494 this.startInterval();
2496 clearInterval(this._interval);
2497 this._interval = null;
2500 this.locked = false;
2507 purgeElement: function(el, recurse, eventName) {
2508 var elListeners = this.getListeners(el, eventName);
2510 for (var i = 0,len = elListeners.length; i < len; ++i) {
2511 var l = elListeners[i];
2512 this.removeListener(el, l.type, l.fn);
2516 if (recurse && el && el.childNodes) {
2517 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2518 this.purgeElement(el.childNodes[i], recurse, eventName);
2524 getListeners: function(el, eventName) {
2525 var results = [], searchLists;
2527 searchLists = [listeners, unloadListeners];
2528 } else if (eventName == "unload") {
2529 searchLists = [unloadListeners];
2531 searchLists = [listeners];
2534 for (var j = 0; j < searchLists.length; ++j) {
2535 var searchList = searchLists[j];
2536 if (searchList && searchList.length > 0) {
2537 for (var i = 0,len = searchList.length; i < len; ++i) {
2538 var l = searchList[i];
2539 if (l && l[this.EL] === el &&
2540 (!eventName || eventName === l[this.TYPE])) {
2545 adjust: l[this.ADJ_SCOPE],
2553 return (results.length) ? results : null;
2557 _unload: function(e) {
2559 var EU = Roo.lib.Event, i, j, l, len, index;
2561 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2562 l = unloadListeners[i];
2565 if (l[EU.ADJ_SCOPE]) {
2566 if (l[EU.ADJ_SCOPE] === true) {
2569 scope = l[EU.ADJ_SCOPE];
2572 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2573 unloadListeners[i] = null;
2579 unloadListeners = null;
2581 if (listeners && listeners.length > 0) {
2582 j = listeners.length;
2585 l = listeners[index];
2587 EU.removeListener(l[EU.EL], l[EU.TYPE],
2597 EU.doRemove(window, "unload", EU._unload);
2602 getScroll: function() {
2603 var dd = document.documentElement, db = document.body;
2604 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2605 return [dd.scrollTop, dd.scrollLeft];
2607 return [db.scrollTop, db.scrollLeft];
2614 doAdd: function () {
2615 if (window.addEventListener) {
2616 return function(el, eventName, fn, capture) {
2617 el.addEventListener(eventName, fn, (capture));
2619 } else if (window.attachEvent) {
2620 return function(el, eventName, fn, capture) {
2621 el.attachEvent("on" + eventName, fn);
2630 doRemove: function() {
2631 if (window.removeEventListener) {
2632 return function (el, eventName, fn, capture) {
2633 el.removeEventListener(eventName, fn, (capture));
2635 } else if (window.detachEvent) {
2636 return function (el, eventName, fn) {
2637 el.detachEvent("on" + eventName, fn);
2649 var E = Roo.lib.Event;
2650 E.on = E.addListener;
2651 E.un = E.removeListener;
2653 if (document && document.body) {
2656 E.doAdd(window, "load", E._load);
2658 E.doAdd(window, "unload", E._unload);
2659 E._tryPreloadAttach();
2666 * @class Roo.lib.Ajax
2668 * provide a simple Ajax request utility functions
2670 * Portions of this file are based on pieces of Yahoo User Interface Library
2671 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2672 * YUI licensed under the BSD License:
2673 * http://developer.yahoo.net/yui/license.txt
2674 * <script type="text/javascript">
2682 request : function(method, uri, cb, data, options) {
2684 var hs = options.headers;
2687 if(hs.hasOwnProperty(h)){
2688 this.initHeader(h, hs[h], false);
2692 if(options.xmlData){
2693 this.initHeader('Content-Type', 'text/xml', false);
2695 data = options.xmlData;
2699 return this.asyncRequest(method, uri, cb, data);
2705 * @param {DomForm} form element
2706 * @return {String} urlencode form output.
2708 serializeForm : function(form, include_disabled) {
2710 include_disabled = typeof(include_disabled) == 'undefined' ? false : include_disabled;
2712 if(typeof form == 'string') {
2713 form = (document.getElementById(form) || document.forms[form]);
2716 var el, name, val, disabled, data = '', hasSubmit = false;
2717 for (var i = 0; i < form.elements.length; i++) {
2718 el = form.elements[i];
2719 disabled = include_disabled ? false : form.elements[i].disabled;
2720 name = form.elements[i].name;
2721 val = form.elements[i].value;
2723 if (!disabled && name){
2727 case 'select-multiple':
2728 for (var j = 0; j < el.options.length; j++) {
2729 if (el.options[j].selected) {
2731 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2734 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2742 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2755 if(hasSubmit == false) {
2756 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2761 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2766 data = data.substr(0, data.length - 1);
2774 useDefaultHeader:true,
2776 defaultPostHeader:'application/x-www-form-urlencoded',
2778 useDefaultXhrHeader:true,
2780 defaultXhrHeader:'XMLHttpRequest',
2782 hasDefaultHeaders:true,
2794 setProgId:function(id)
2796 this.activeX.unshift(id);
2799 setDefaultPostHeader:function(b)
2801 this.useDefaultHeader = b;
2804 setDefaultXhrHeader:function(b)
2806 this.useDefaultXhrHeader = b;
2809 setPollingInterval:function(i)
2811 if (typeof i == 'number' && isFinite(i)) {
2812 this.pollInterval = i;
2816 createXhrObject:function(transactionId)
2822 http = new XMLHttpRequest();
2824 obj = { conn:http, tId:transactionId };
2828 for (var i = 0; i < this.activeX.length; ++i) {
2832 http = new ActiveXObject(this.activeX[i]);
2834 obj = { conn:http, tId:transactionId };
2847 getConnectionObject:function()
2850 var tId = this.transactionId;
2854 o = this.createXhrObject(tId);
2856 this.transactionId++;
2867 asyncRequest:function(method, uri, callback, postData)
2869 var o = this.getConnectionObject();
2875 o.conn.open(method, uri, true);
2877 if (this.useDefaultXhrHeader) {
2878 if (!this.defaultHeaders['X-Requested-With']) {
2879 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2883 if(postData && this.useDefaultHeader){
2884 this.initHeader('Content-Type', this.defaultPostHeader);
2887 if (this.hasDefaultHeaders || this.hasHeaders) {
2891 this.handleReadyState(o, callback);
2892 o.conn.send(postData || null);
2898 handleReadyState:function(o, callback)
2902 if (callback && callback.timeout) {
2904 this.timeout[o.tId] = window.setTimeout(function() {
2905 oConn.abort(o, callback, true);
2906 }, callback.timeout);
2909 this.poll[o.tId] = window.setInterval(
2911 if (o.conn && o.conn.readyState == 4) {
2912 window.clearInterval(oConn.poll[o.tId]);
2913 delete oConn.poll[o.tId];
2915 if(callback && callback.timeout) {
2916 window.clearTimeout(oConn.timeout[o.tId]);
2917 delete oConn.timeout[o.tId];
2920 oConn.handleTransactionResponse(o, callback);
2923 , this.pollInterval);
2926 handleTransactionResponse:function(o, callback, isAbort)
2930 this.releaseObject(o);
2934 var httpStatus, responseObject;
2938 if (o.conn.status !== undefined && o.conn.status != 0) {
2939 httpStatus = o.conn.status;
2951 if (httpStatus >= 200 && httpStatus < 300) {
2952 responseObject = this.createResponseObject(o, callback.argument);
2953 if (callback.success) {
2954 if (!callback.scope) {
2955 callback.success(responseObject);
2960 callback.success.apply(callback.scope, [responseObject]);
2965 switch (httpStatus) {
2973 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2974 if (callback.failure) {
2975 if (!callback.scope) {
2976 callback.failure(responseObject);
2979 callback.failure.apply(callback.scope, [responseObject]);
2984 responseObject = this.createResponseObject(o, callback.argument);
2985 if (callback.failure) {
2986 if (!callback.scope) {
2987 callback.failure(responseObject);
2990 callback.failure.apply(callback.scope, [responseObject]);
2996 this.releaseObject(o);
2997 responseObject = null;
3000 createResponseObject:function(o, callbackArg)
3007 var headerStr = o.conn.getAllResponseHeaders();
3008 var header = headerStr.split('\n');
3009 for (var i = 0; i < header.length; i++) {
3010 var delimitPos = header[i].indexOf(':');
3011 if (delimitPos != -1) {
3012 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
3020 obj.status = o.conn.status;
3021 obj.statusText = o.conn.statusText;
3022 obj.getResponseHeader = headerObj;
3023 obj.getAllResponseHeaders = headerStr;
3024 obj.responseText = o.conn.responseText;
3025 obj.responseXML = o.conn.responseXML;
3027 if (typeof callbackArg !== undefined) {
3028 obj.argument = callbackArg;
3034 createExceptionObject:function(tId, callbackArg, isAbort)
3037 var COMM_ERROR = 'communication failure';
3038 var ABORT_CODE = -1;
3039 var ABORT_ERROR = 'transaction aborted';
3045 obj.status = ABORT_CODE;
3046 obj.statusText = ABORT_ERROR;
3049 obj.status = COMM_CODE;
3050 obj.statusText = COMM_ERROR;
3054 obj.argument = callbackArg;
3060 initHeader:function(label, value, isDefault)
3062 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
3064 if (headerObj[label] === undefined) {
3065 headerObj[label] = value;
3070 headerObj[label] = value + "," + headerObj[label];
3074 this.hasDefaultHeaders = true;
3077 this.hasHeaders = true;
3082 setHeader:function(o)
3084 if (this.hasDefaultHeaders) {
3085 for (var prop in this.defaultHeaders) {
3086 if (this.defaultHeaders.hasOwnProperty(prop)) {
3087 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3092 if (this.hasHeaders) {
3093 for (var prop in this.headers) {
3094 if (this.headers.hasOwnProperty(prop)) {
3095 o.conn.setRequestHeader(prop, this.headers[prop]);
3099 this.hasHeaders = false;
3103 resetDefaultHeaders:function() {
3104 delete this.defaultHeaders;
3105 this.defaultHeaders = {};
3106 this.hasDefaultHeaders = false;
3109 abort:function(o, callback, isTimeout)
3111 if(this.isCallInProgress(o)) {
3113 window.clearInterval(this.poll[o.tId]);
3114 delete this.poll[o.tId];
3116 delete this.timeout[o.tId];
3119 this.handleTransactionResponse(o, callback, true);
3129 isCallInProgress:function(o)
3132 return o.conn.readyState != 4 && o.conn.readyState != 0;
3141 releaseObject:function(o)
3150 'MSXML2.XMLHTTP.3.0',
3158 * Portions of this file are based on pieces of Yahoo User Interface Library
3159 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3160 * YUI licensed under the BSD License:
3161 * http://developer.yahoo.net/yui/license.txt
3162 * <script type="text/javascript">
3166 Roo.lib.Region = function(t, r, b, l) {
3176 Roo.lib.Region.prototype = {
3177 contains : function(region) {
3178 return ( region.left >= this.left &&
3179 region.right <= this.right &&
3180 region.top >= this.top &&
3181 region.bottom <= this.bottom );
3185 getArea : function() {
3186 return ( (this.bottom - this.top) * (this.right - this.left) );
3189 intersect : function(region) {
3190 var t = Math.max(this.top, region.top);
3191 var r = Math.min(this.right, region.right);
3192 var b = Math.min(this.bottom, region.bottom);
3193 var l = Math.max(this.left, region.left);
3195 if (b >= t && r >= l) {
3196 return new Roo.lib.Region(t, r, b, l);
3201 union : function(region) {
3202 var t = Math.min(this.top, region.top);
3203 var r = Math.max(this.right, region.right);
3204 var b = Math.max(this.bottom, region.bottom);
3205 var l = Math.min(this.left, region.left);
3207 return new Roo.lib.Region(t, r, b, l);
3210 adjust : function(t, l, b, r) {
3219 Roo.lib.Region.getRegion = function(el) {
3220 var p = Roo.lib.Dom.getXY(el);
3223 var r = p[0] + el.offsetWidth;
3224 var b = p[1] + el.offsetHeight;
3227 return new Roo.lib.Region(t, r, b, l);
3230 * Portions of this file are based on pieces of Yahoo User Interface Library
3231 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3232 * YUI licensed under the BSD License:
3233 * http://developer.yahoo.net/yui/license.txt
3234 * <script type="text/javascript">
3237 //@@dep Roo.lib.Region
3240 Roo.lib.Point = function(x, y) {
3241 if (x instanceof Array) {
3245 this.x = this.right = this.left = this[0] = x;
3246 this.y = this.top = this.bottom = this[1] = y;
3249 Roo.lib.Point.prototype = new Roo.lib.Region();
3251 * Portions of this file are based on pieces of Yahoo User Interface Library
3252 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3253 * YUI licensed under the BSD License:
3254 * http://developer.yahoo.net/yui/license.txt
3255 * <script type="text/javascript">
3262 scroll : function(el, args, duration, easing, cb, scope) {
3263 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3266 motion : function(el, args, duration, easing, cb, scope) {
3267 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3270 color : function(el, args, duration, easing, cb, scope) {
3271 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3274 run : function(el, args, duration, easing, cb, scope, type) {
3275 type = type || Roo.lib.AnimBase;
3276 if (typeof easing == "string") {
3277 easing = Roo.lib.Easing[easing];
3279 var anim = new type(el, args, duration, easing);
3280 anim.animateX(function() {
3281 Roo.callback(cb, scope);
3287 * Portions of this file are based on pieces of Yahoo User Interface Library
3288 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3289 * YUI licensed under the BSD License:
3290 * http://developer.yahoo.net/yui/license.txt
3291 * <script type="text/javascript">
3299 if (!libFlyweight) {
3300 libFlyweight = new Roo.Element.Flyweight();
3302 libFlyweight.dom = el;
3303 return libFlyweight;
3306 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3310 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3312 this.init(el, attributes, duration, method);
3316 Roo.lib.AnimBase.fly = fly;
3320 Roo.lib.AnimBase.prototype = {
3322 toString: function() {
3323 var el = this.getEl();
3324 var id = el.id || el.tagName;
3325 return ("Anim " + id);
3329 noNegatives: /width|height|opacity|padding/i,
3330 offsetAttribute: /^((width|height)|(top|left))$/,
3331 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3332 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3336 doMethod: function(attr, start, end) {
3337 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3341 setAttribute: function(attr, val, unit) {
3342 if (this.patterns.noNegatives.test(attr)) {
3343 val = (val > 0) ? val : 0;
3346 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3350 getAttribute: function(attr) {
3351 var el = this.getEl();
3352 var val = fly(el).getStyle(attr);
3354 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3355 return parseFloat(val);
3358 var a = this.patterns.offsetAttribute.exec(attr) || [];
3359 var pos = !!( a[3] );
3360 var box = !!( a[2] );
3363 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3364 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3373 getDefaultUnit: function(attr) {
3374 if (this.patterns.defaultUnit.test(attr)) {
3381 animateX : function(callback, scope) {
3382 var f = function() {
3383 this.onComplete.removeListener(f);
3384 if (typeof callback == "function") {
3385 callback.call(scope || this, this);
3388 this.onComplete.addListener(f, this);
3393 setRuntimeAttribute: function(attr) {
3396 var attributes = this.attributes;
3398 this.runtimeAttributes[attr] = {};
3400 var isset = function(prop) {
3401 return (typeof prop !== 'undefined');
3404 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3408 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3411 if (isset(attributes[attr]['to'])) {
3412 end = attributes[attr]['to'];
3413 } else if (isset(attributes[attr]['by'])) {
3414 if (start.constructor == Array) {
3416 for (var i = 0, len = start.length; i < len; ++i) {
3417 end[i] = start[i] + attributes[attr]['by'][i];
3420 end = start + attributes[attr]['by'];
3424 this.runtimeAttributes[attr].start = start;
3425 this.runtimeAttributes[attr].end = end;
3428 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3432 init: function(el, attributes, duration, method) {
3434 var isAnimated = false;
3437 var startTime = null;
3440 var actualFrames = 0;
3443 el = Roo.getDom(el);
3446 this.attributes = attributes || {};
3449 this.duration = duration || 1;
3452 this.method = method || Roo.lib.Easing.easeNone;
3455 this.useSeconds = true;
3458 this.currentFrame = 0;
3461 this.totalFrames = Roo.lib.AnimMgr.fps;
3464 this.getEl = function() {
3469 this.isAnimated = function() {
3474 this.getStartTime = function() {
3478 this.runtimeAttributes = {};
3481 this.animate = function() {
3482 if (this.isAnimated()) {
3486 this.currentFrame = 0;
3488 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3490 Roo.lib.AnimMgr.registerElement(this);
3494 this.stop = function(finish) {
3496 this.currentFrame = this.totalFrames;
3497 this._onTween.fire();
3499 Roo.lib.AnimMgr.stop(this);
3502 var onStart = function() {
3503 this.onStart.fire();
3505 this.runtimeAttributes = {};
3506 for (var attr in this.attributes) {
3507 this.setRuntimeAttribute(attr);
3512 startTime = new Date();
3516 var onTween = function() {
3518 duration: new Date() - this.getStartTime(),
3519 currentFrame: this.currentFrame
3522 data.toString = function() {
3524 'duration: ' + data.duration +
3525 ', currentFrame: ' + data.currentFrame
3529 this.onTween.fire(data);
3531 var runtimeAttributes = this.runtimeAttributes;
3533 for (var attr in runtimeAttributes) {
3534 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3540 var onComplete = function() {
3541 var actual_duration = (new Date() - startTime) / 1000 ;
3544 duration: actual_duration,
3545 frames: actualFrames,
3546 fps: actualFrames / actual_duration
3549 data.toString = function() {
3551 'duration: ' + data.duration +
3552 ', frames: ' + data.frames +
3553 ', fps: ' + data.fps
3559 this.onComplete.fire(data);
3563 this._onStart = new Roo.util.Event(this);
3564 this.onStart = new Roo.util.Event(this);
3565 this.onTween = new Roo.util.Event(this);
3566 this._onTween = new Roo.util.Event(this);
3567 this.onComplete = new Roo.util.Event(this);
3568 this._onComplete = new Roo.util.Event(this);
3569 this._onStart.addListener(onStart);
3570 this._onTween.addListener(onTween);
3571 this._onComplete.addListener(onComplete);
3576 * Portions of this file are based on pieces of Yahoo User Interface Library
3577 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3578 * YUI licensed under the BSD License:
3579 * http://developer.yahoo.net/yui/license.txt
3580 * <script type="text/javascript">
3584 Roo.lib.AnimMgr = new function() {
3601 this.registerElement = function(tween) {
3602 queue[queue.length] = tween;
3604 tween._onStart.fire();
3609 this.unRegister = function(tween, index) {
3610 tween._onComplete.fire();
3611 index = index || getIndex(tween);
3613 queue.splice(index, 1);
3617 if (tweenCount <= 0) {
3623 this.start = function() {
3624 if (thread === null) {
3625 thread = setInterval(this.run, this.delay);
3630 this.stop = function(tween) {
3632 clearInterval(thread);
3634 for (var i = 0, len = queue.length; i < len; ++i) {
3635 if (queue[0].isAnimated()) {
3636 this.unRegister(queue[0], 0);
3645 this.unRegister(tween);
3650 this.run = function() {
3651 for (var i = 0, len = queue.length; i < len; ++i) {
3652 var tween = queue[i];
3653 if (!tween || !tween.isAnimated()) {
3657 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3659 tween.currentFrame += 1;
3661 if (tween.useSeconds) {
3662 correctFrame(tween);
3664 tween._onTween.fire();
3667 Roo.lib.AnimMgr.stop(tween, i);
3672 var getIndex = function(anim) {
3673 for (var i = 0, len = queue.length; i < len; ++i) {
3674 if (queue[i] == anim) {
3682 var correctFrame = function(tween) {
3683 var frames = tween.totalFrames;
3684 var frame = tween.currentFrame;
3685 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3686 var elapsed = (new Date() - tween.getStartTime());
3689 if (elapsed < tween.duration * 1000) {
3690 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3692 tweak = frames - (frame + 1);
3694 if (tweak > 0 && isFinite(tweak)) {
3695 if (tween.currentFrame + tweak >= frames) {
3696 tweak = frames - (frame + 1);
3699 tween.currentFrame += tweak;
3705 * Portions of this file are based on pieces of Yahoo User Interface Library
3706 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3707 * YUI licensed under the BSD License:
3708 * http://developer.yahoo.net/yui/license.txt
3709 * <script type="text/javascript">
3712 Roo.lib.Bezier = new function() {
3714 this.getPosition = function(points, t) {
3715 var n = points.length;
3718 for (var i = 0; i < n; ++i) {
3719 tmp[i] = [points[i][0], points[i][1]];
3722 for (var j = 1; j < n; ++j) {
3723 for (i = 0; i < n - j; ++i) {
3724 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3725 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3729 return [ tmp[0][0], tmp[0][1] ];
3735 * @class Roo.lib.Color
3737 * An abstract Color implementation. Concrete Color implementations should use
3738 * an instance of this function as their prototype, and implement the getRGB and
3739 * getHSL functions. getRGB should return an object representing the RGB
3740 * components of this Color, with the red, green, and blue components in the
3741 * range [0,255] and the alpha component in the range [0,100]. getHSL should
3742 * return an object representing the HSL components of this Color, with the hue
3743 * component in the range [0,360), the saturation and lightness components in
3744 * the range [0,100], and the alpha component in the range [0,1].
3749 * Functions for Color handling and processing.
3751 * http://www.safalra.com/web-design/javascript/Color-handling-and-processing/
3753 * The author of this program, Safalra (Stephen Morley), irrevocably releases all
3754 * rights to this program, with the intention of it becoming part of the public
3755 * domain. Because this program is released into the public domain, it comes with
3756 * no warranty either expressed or implied, to the extent permitted by law.
3758 * For more free and public domain JavaScript code by the same author, visit:
3759 * http://www.safalra.com/web-design/javascript/
3762 Roo.lib.Color = function() { }
3765 Roo.apply(Roo.lib.Color.prototype, {
3773 * @return {Object} an object representing the RGBA components of this Color. The red,
3774 * green, and blue components are converted to integers in the range [0,255].
3775 * The alpha is a value in the range [0,1].
3777 getIntegerRGB : function(){
3779 // get the RGB components of this Color
3780 var rgb = this.getRGB();
3782 // return the integer components
3784 'r' : Math.round(rgb.r),
3785 'g' : Math.round(rgb.g),
3786 'b' : Math.round(rgb.b),
3794 * @return {Object} an object representing the RGBA components of this Color. The red,
3795 * green, and blue components are converted to numbers in the range [0,100].
3796 * The alpha is a value in the range [0,1].
3798 getPercentageRGB : function(){
3800 // get the RGB components of this Color
3801 var rgb = this.getRGB();
3803 // return the percentage components
3805 'r' : 100 * rgb.r / 255,
3806 'g' : 100 * rgb.g / 255,
3807 'b' : 100 * rgb.b / 255,
3814 * getCSSHexadecimalRGB
3815 * @return {String} a string representing this Color as a CSS hexadecimal RGB Color
3816 * value - that is, a string of the form #RRGGBB where each of RR, GG, and BB
3817 * are two-digit hexadecimal numbers.
3819 getCSSHexadecimalRGB : function()
3822 // get the integer RGB components
3823 var rgb = this.getIntegerRGB();
3825 // determine the hexadecimal equivalents
3826 var r16 = rgb.r.toString(16);
3827 var g16 = rgb.g.toString(16);
3828 var b16 = rgb.b.toString(16);
3830 // return the CSS RGB Color value
3832 + (r16.length == 2 ? r16 : '0' + r16)
3833 + (g16.length == 2 ? g16 : '0' + g16)
3834 + (b16.length == 2 ? b16 : '0' + b16);
3840 * @return {String} a string representing this Color as a CSS integer RGB Color
3841 * value - that is, a string of the form rgb(r,g,b) where each of r, g, and b
3842 * are integers in the range [0,255].
3844 getCSSIntegerRGB : function(){
3846 // get the integer RGB components
3847 var rgb = this.getIntegerRGB();
3849 // return the CSS RGB Color value
3850 return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')';
3856 * @return {String} Returns a string representing this Color as a CSS integer RGBA Color
3857 * value - that is, a string of the form rgba(r,g,b,a) where each of r, g, and
3858 * b are integers in the range [0,255] and a is in the range [0,1].
3860 getCSSIntegerRGBA : function(){
3862 // get the integer RGB components
3863 var rgb = this.getIntegerRGB();
3865 // return the CSS integer RGBA Color value
3866 return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + rgb.a + ')';
3871 * getCSSPercentageRGB
3872 * @return {String} a string representing this Color as a CSS percentage RGB Color
3873 * value - that is, a string of the form rgb(r%,g%,b%) where each of r, g, and
3874 * b are in the range [0,100].
3876 getCSSPercentageRGB : function(){
3878 // get the percentage RGB components
3879 var rgb = this.getPercentageRGB();
3881 // return the CSS RGB Color value
3882 return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%)';
3887 * getCSSPercentageRGBA
3888 * @return {String} a string representing this Color as a CSS percentage RGBA Color
3889 * value - that is, a string of the form rgba(r%,g%,b%,a) where each of r, g,
3890 * and b are in the range [0,100] and a is in the range [0,1].
3892 getCSSPercentageRGBA : function(){
3894 // get the percentage RGB components
3895 var rgb = this.getPercentageRGB();
3897 // return the CSS percentage RGBA Color value
3898 return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%,' + rgb.a + ')';
3904 * @return {String} a string representing this Color as a CSS HSL Color value - that
3905 * is, a string of the form hsl(h,s%,l%) where h is in the range [0,100] and
3906 * s and l are in the range [0,100].
3908 getCSSHSL : function(){
3910 // get the HSL components
3911 var hsl = this.getHSL();
3913 // return the CSS HSL Color value
3914 return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%)';
3920 * @return {String} a string representing this Color as a CSS HSLA Color value - that
3921 * is, a string of the form hsla(h,s%,l%,a) where h is in the range [0,100],
3922 * s and l are in the range [0,100], and a is in the range [0,1].
3924 getCSSHSLA : function(){
3926 // get the HSL components
3927 var hsl = this.getHSL();
3929 // return the CSS HSL Color value
3930 return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%,' + hsl.a + ')';
3935 * Sets the Color of the specified node to this Color. This functions sets
3936 * the CSS 'color' property for the node. The parameter is:
3938 * @param {DomElement} node - the node whose Color should be set
3940 setNodeColor : function(node){
3942 // set the Color of the node
3943 node.style.color = this.getCSSHexadecimalRGB();
3948 * Sets the background Color of the specified node to this Color. This
3949 * functions sets the CSS 'background-color' property for the node. The
3952 * @param {DomElement} node - the node whose background Color should be set
3954 setNodeBackgroundColor : function(node){
3956 // set the background Color of the node
3957 node.style.backgroundColor = this.getCSSHexadecimalRGB();
3960 // convert between formats..
3963 var r = this.getIntegerRGB();
3964 return new Roo.lib.RGBColor(r.r,r.g,r.b,r.a);
3969 var hsl = this.getHSL();
3970 // return the CSS HSL Color value
3971 return new Roo.lib.HSLColor(hsl.h, hsl.s, hsl.l , hsl.a );
3977 var rgb = this.toRGB();
3978 var hsv = rgb.getHSV();
3979 // return the CSS HSL Color value
3980 return new Roo.lib.HSVColor(hsv.h, hsv.s, hsv.v , hsv.a );
3984 // modify v = 0 ... 1 (eg. 0.5)
3985 saturate : function(v)
3987 var rgb = this.toRGB();
3988 var hsv = rgb.getHSV();
3989 return new Roo.lib.HSVColor(hsv.h, hsv.s * v, hsv.v , hsv.a );
3997 * @return {Object} the RGB and alpha components of this Color as an object with r,
3998 * g, b, and a properties. r, g, and b are in the range [0,255] and a is in
4003 // return the RGB components
4015 * @return {Object} the HSV and alpha components of this Color as an object with h,
4016 * s, v, and a properties. h is in the range [0,360), s and v are in the range
4017 * [0,100], and a is in the range [0,1].
4022 // calculate the HSV components if necessary
4023 if (this.hsv == null) {
4024 this.calculateHSV();
4027 // return the HSV components
4039 * @return {Object} the HSL and alpha components of this Color as an object with h,
4040 * s, l, and a properties. h is in the range [0,360), s and l are in the range
4041 * [0,100], and a is in the range [0,1].
4043 getHSL : function(){
4046 // calculate the HSV components if necessary
4047 if (this.hsl == null) { this.calculateHSL(); }
4049 // return the HSL components
4064 * @class Roo.lib.RGBColor
4065 * @extends Roo.lib.Color
4066 * Creates a Color specified in the RGB Color space, with an optional alpha
4067 * component. The parameters are:
4071 * @param {Number} r - the red component, clipped to the range [0,255]
4072 * @param {Number} g - the green component, clipped to the range [0,255]
4073 * @param {Number} b - the blue component, clipped to the range [0,255]
4074 * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4075 * optional and defaults to 1
4077 Roo.lib.RGBColor = function (r, g, b, a){
4079 // store the alpha component after clipping it if necessary
4080 this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4082 // store the RGB components after clipping them if necessary
4085 'r' : Math.max(0, Math.min(255, r)),
4086 'g' : Math.max(0, Math.min(255, g)),
4087 'b' : Math.max(0, Math.min(255, b))
4090 // initialise the HSV and HSL components to null
4094 * //private returns the HSV or HSL hue component of this RGBColor. The hue is in the
4095 * range [0,360). The parameters are:
4097 * maximum - the maximum of the RGB component values
4098 * range - the range of the RGB component values
4103 // this does an 'exteds'
4104 Roo.extend(Roo.lib.RGBColor, Roo.lib.Color, {
4107 getHue : function(maximum, range)
4111 // check whether the range is zero
4114 // set the hue to zero (any hue is acceptable as the Color is grey)
4119 // determine which of the components has the highest value and set the hue
4122 // red has the highest value
4124 var hue = (rgb.g - rgb.b) / range * 60;
4125 if (hue < 0) { hue += 360; }
4128 // green has the highest value
4130 var hue = (rgb.b - rgb.r) / range * 60 + 120;
4133 // blue has the highest value
4135 var hue = (rgb.r - rgb.g) / range * 60 + 240;
4147 /* //private Calculates and stores the HSV components of this RGBColor so that they can
4148 * be returned be the getHSV function.
4150 calculateHSV : function(){
4152 // get the maximum and range of the RGB component values
4153 var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4154 var range = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4156 // store the HSV components
4159 'h' : this.getHue(maximum, range),
4160 's' : (maximum == 0 ? 0 : 100 * range / maximum),
4161 'v' : maximum / 2.55
4166 /* //private Calculates and stores the HSL components of this RGBColor so that they can
4167 * be returned be the getHSL function.
4169 calculateHSL : function(){
4171 // get the maximum and range of the RGB component values
4172 var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4173 var range = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4175 // determine the lightness in the range [0,1]
4176 var l = maximum / 255 - range / 510;
4178 // store the HSL components
4181 'h' : this.getHue(maximum, range),
4182 's' : (range == 0 ? 0 : range / 2.55 / (l < 0.5 ? l * 2 : 2 - l * 2)),
4191 * @class Roo.lib.HSVColor
4192 * @extends Roo.lib.Color
4193 * Creates a Color specified in the HSV Color space, with an optional alpha
4194 * component. The parameters are:
4197 * @param {Number} h - the hue component, wrapped to the range [0,360)
4198 * @param {Number} s - the saturation component, clipped to the range [0,100]
4199 * @param {Number} v - the value component, clipped to the range [0,100]
4200 * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4201 * optional and defaults to 1
4203 Roo.lib.HSVColor = function (h, s, v, a){
4205 // store the alpha component after clipping it if necessary
4206 this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4208 // store the HSV components after clipping or wrapping them if necessary
4211 'h' : (h % 360 + 360) % 360,
4212 's' : Math.max(0, Math.min(100, s)),
4213 'v' : Math.max(0, Math.min(100, v))
4216 // initialise the RGB and HSL components to null
4221 Roo.extend(Roo.lib.HSVColor, Roo.lib.Color, {
4222 /* Calculates and stores the RGB components of this HSVColor so that they can
4223 * be returned be the getRGB function.
4225 calculateRGB: function ()
4228 // check whether the saturation is zero
4231 // set the Color to the appropriate shade of grey
4238 // set some temporary values
4239 var f = hsv.h / 60 - Math.floor(hsv.h / 60);
4240 var p = hsv.v * (1 - hsv.s / 100);
4241 var q = hsv.v * (1 - hsv.s / 100 * f);
4242 var t = hsv.v * (1 - hsv.s / 100 * (1 - f));
4244 // set the RGB Color components to their temporary values
4245 switch (Math.floor(hsv.h / 60)){
4246 case 0: var r = hsv.v; var g = t; var b = p; break;
4247 case 1: var r = q; var g = hsv.v; var b = p; break;
4248 case 2: var r = p; var g = hsv.v; var b = t; break;
4249 case 3: var r = p; var g = q; var b = hsv.v; break;
4250 case 4: var r = t; var g = p; var b = hsv.v; break;
4251 case 5: var r = hsv.v; var g = p; var b = q; break;
4256 // store the RGB components
4266 /* Calculates and stores the HSL components of this HSVColor so that they can
4267 * be returned be the getHSL function.
4269 calculateHSL : function (){
4272 // determine the lightness in the range [0,100]
4273 var l = (2 - hsv.s / 100) * hsv.v / 2;
4275 // store the HSL components
4279 's' : hsv.s * hsv.v / (l < 50 ? l * 2 : 200 - l * 2),
4283 // correct a division-by-zero error
4284 if (isNaN(hsl.s)) { hsl.s = 0; }
4293 * @class Roo.lib.HSLColor
4294 * @extends Roo.lib.Color
4297 * Creates a Color specified in the HSL Color space, with an optional alpha
4298 * component. The parameters are:
4300 * @param {Number} h - the hue component, wrapped to the range [0,360)
4301 * @param {Number} s - the saturation component, clipped to the range [0,100]
4302 * @param {Number} l - the lightness component, clipped to the range [0,100]
4303 * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4304 * optional and defaults to 1
4307 Roo.lib.HSLColor = function(h, s, l, a){
4309 // store the alpha component after clipping it if necessary
4310 this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4312 // store the HSL components after clipping or wrapping them if necessary
4315 'h' : (h % 360 + 360) % 360,
4316 's' : Math.max(0, Math.min(100, s)),
4317 'l' : Math.max(0, Math.min(100, l))
4320 // initialise the RGB and HSV components to null
4323 Roo.extend(Roo.lib.HSLColor, Roo.lib.Color, {
4325 /* Calculates and stores the RGB components of this HSLColor so that they can
4326 * be returned be the getRGB function.
4328 calculateRGB: function (){
4330 // check whether the saturation is zero
4331 if (this.hsl.s == 0){
4333 // store the RGB components representing the appropriate shade of grey
4336 'r' : this.hsl.l * 2.55,
4337 'g' : this.hsl.l * 2.55,
4338 'b' : this.hsl.l * 2.55
4343 // set some temporary values
4344 var p = this.hsl.l < 50
4345 ? this.hsl.l * (1 + hsl.s / 100)
4346 : this.hsl.l + hsl.s - hsl.l * hsl.s / 100;
4347 var q = 2 * hsl.l - p;
4349 // initialise the RGB components
4352 'r' : (h + 120) / 60 % 6,
4354 'b' : (h + 240) / 60 % 6
4357 // loop over the RGB components
4358 for (var key in this.rgb){
4360 // ensure that the property is not inherited from the root object
4361 if (this.rgb.hasOwnProperty(key)){
4363 // set the component to its value in the range [0,100]
4364 if (this.rgb[key] < 1){
4365 this.rgb[key] = q + (p - q) * this.rgb[key];
4366 }else if (this.rgb[key] < 3){
4368 }else if (this.rgb[key] < 4){
4369 this.rgb[key] = q + (p - q) * (4 - this.rgb[key]);
4374 // set the component to its value in the range [0,255]
4375 this.rgb[key] *= 2.55;
4385 /* Calculates and stores the HSV components of this HSLColor so that they can
4386 * be returned be the getHSL function.
4388 calculateHSV : function(){
4390 // set a temporary value
4391 var t = this.hsl.s * (this.hsl.l < 50 ? this.hsl.l : 100 - this.hsl.l) / 100;
4393 // store the HSV components
4397 's' : 200 * t / (this.hsl.l + t),
4398 'v' : t + this.hsl.l
4401 // correct a division-by-zero error
4402 if (isNaN(this.hsv.s)) { this.hsv.s = 0; }
4409 * Portions of this file are based on pieces of Yahoo User Interface Library
4410 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4411 * YUI licensed under the BSD License:
4412 * http://developer.yahoo.net/yui/license.txt
4413 * <script type="text/javascript">
4418 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
4419 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
4422 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
4424 var fly = Roo.lib.AnimBase.fly;
4426 var superclass = Y.ColorAnim.superclass;
4427 var proto = Y.ColorAnim.prototype;
4429 proto.toString = function() {
4430 var el = this.getEl();
4431 var id = el.id || el.tagName;
4432 return ("ColorAnim " + id);
4435 proto.patterns.color = /color$/i;
4436 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
4437 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
4438 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
4439 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
4442 proto.parseColor = function(s) {
4443 if (s.length == 3) {
4447 var c = this.patterns.hex.exec(s);
4448 if (c && c.length == 4) {
4449 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
4452 c = this.patterns.rgb.exec(s);
4453 if (c && c.length == 4) {
4454 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
4457 c = this.patterns.hex3.exec(s);
4458 if (c && c.length == 4) {
4459 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
4464 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
4465 proto.getAttribute = function(attr) {
4466 var el = this.getEl();
4467 if (this.patterns.color.test(attr)) {
4468 var val = fly(el).getStyle(attr);
4470 if (this.patterns.transparent.test(val)) {
4471 var parent = el.parentNode;
4472 val = fly(parent).getStyle(attr);
4474 while (parent && this.patterns.transparent.test(val)) {
4475 parent = parent.parentNode;
4476 val = fly(parent).getStyle(attr);
4477 if (parent.tagName.toUpperCase() == 'HTML') {
4483 val = superclass.getAttribute.call(this, attr);
4488 proto.getAttribute = function(attr) {
4489 var el = this.getEl();
4490 if (this.patterns.color.test(attr)) {
4491 var val = fly(el).getStyle(attr);
4493 if (this.patterns.transparent.test(val)) {
4494 var parent = el.parentNode;
4495 val = fly(parent).getStyle(attr);
4497 while (parent && this.patterns.transparent.test(val)) {
4498 parent = parent.parentNode;
4499 val = fly(parent).getStyle(attr);
4500 if (parent.tagName.toUpperCase() == 'HTML') {
4506 val = superclass.getAttribute.call(this, attr);
4512 proto.doMethod = function(attr, start, end) {
4515 if (this.patterns.color.test(attr)) {
4517 for (var i = 0, len = start.length; i < len; ++i) {
4518 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
4521 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
4524 val = superclass.doMethod.call(this, attr, start, end);
4530 proto.setRuntimeAttribute = function(attr) {
4531 superclass.setRuntimeAttribute.call(this, attr);
4533 if (this.patterns.color.test(attr)) {
4534 var attributes = this.attributes;
4535 var start = this.parseColor(this.runtimeAttributes[attr].start);
4536 var end = this.parseColor(this.runtimeAttributes[attr].end);
4538 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
4539 end = this.parseColor(attributes[attr].by);
4541 for (var i = 0, len = start.length; i < len; ++i) {
4542 end[i] = start[i] + end[i];
4546 this.runtimeAttributes[attr].start = start;
4547 this.runtimeAttributes[attr].end = end;
4553 * Portions of this file are based on pieces of Yahoo User Interface Library
4554 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4555 * YUI licensed under the BSD License:
4556 * http://developer.yahoo.net/yui/license.txt
4557 * <script type="text/javascript">
4563 easeNone: function (t, b, c, d) {
4564 return c * t / d + b;
4568 easeIn: function (t, b, c, d) {
4569 return c * (t /= d) * t + b;
4573 easeOut: function (t, b, c, d) {
4574 return -c * (t /= d) * (t - 2) + b;
4578 easeBoth: function (t, b, c, d) {
4579 if ((t /= d / 2) < 1) {
4580 return c / 2 * t * t + b;
4583 return -c / 2 * ((--t) * (t - 2) - 1) + b;
4587 easeInStrong: function (t, b, c, d) {
4588 return c * (t /= d) * t * t * t + b;
4592 easeOutStrong: function (t, b, c, d) {
4593 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
4597 easeBothStrong: function (t, b, c, d) {
4598 if ((t /= d / 2) < 1) {
4599 return c / 2 * t * t * t * t + b;
4602 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
4607 elasticIn: function (t, b, c, d, a, p) {
4611 if ((t /= d) == 1) {
4618 if (!a || a < Math.abs(c)) {
4623 var s = p / (2 * Math.PI) * Math.asin(c / a);
4626 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4630 elasticOut: function (t, b, c, d, a, p) {
4634 if ((t /= d) == 1) {
4641 if (!a || a < Math.abs(c)) {
4646 var s = p / (2 * Math.PI) * Math.asin(c / a);
4649 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
4653 elasticBoth: function (t, b, c, d, a, p) {
4658 if ((t /= d / 2) == 2) {
4666 if (!a || a < Math.abs(c)) {
4671 var s = p / (2 * Math.PI) * Math.asin(c / a);
4675 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
4676 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4678 return a * Math.pow(2, -10 * (t -= 1)) *
4679 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
4684 backIn: function (t, b, c, d, s) {
4685 if (typeof s == 'undefined') {
4688 return c * (t /= d) * t * ((s + 1) * t - s) + b;
4692 backOut: function (t, b, c, d, s) {
4693 if (typeof s == 'undefined') {
4696 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
4700 backBoth: function (t, b, c, d, s) {
4701 if (typeof s == 'undefined') {
4705 if ((t /= d / 2 ) < 1) {
4706 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
4708 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
4712 bounceIn: function (t, b, c, d) {
4713 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
4717 bounceOut: function (t, b, c, d) {
4718 if ((t /= d) < (1 / 2.75)) {
4719 return c * (7.5625 * t * t) + b;
4720 } else if (t < (2 / 2.75)) {
4721 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
4722 } else if (t < (2.5 / 2.75)) {
4723 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
4725 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
4729 bounceBoth: function (t, b, c, d) {
4731 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
4733 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
4736 * Portions of this file are based on pieces of Yahoo User Interface Library
4737 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4738 * YUI licensed under the BSD License:
4739 * http://developer.yahoo.net/yui/license.txt
4740 * <script type="text/javascript">
4744 Roo.lib.Motion = function(el, attributes, duration, method) {
4746 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
4750 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
4754 var superclass = Y.Motion.superclass;
4755 var proto = Y.Motion.prototype;
4757 proto.toString = function() {
4758 var el = this.getEl();
4759 var id = el.id || el.tagName;
4760 return ("Motion " + id);
4763 proto.patterns.points = /^points$/i;
4765 proto.setAttribute = function(attr, val, unit) {
4766 if (this.patterns.points.test(attr)) {
4767 unit = unit || 'px';
4768 superclass.setAttribute.call(this, 'left', val[0], unit);
4769 superclass.setAttribute.call(this, 'top', val[1], unit);
4771 superclass.setAttribute.call(this, attr, val, unit);
4775 proto.getAttribute = function(attr) {
4776 if (this.patterns.points.test(attr)) {
4778 superclass.getAttribute.call(this, 'left'),
4779 superclass.getAttribute.call(this, 'top')
4782 val = superclass.getAttribute.call(this, attr);
4788 proto.doMethod = function(attr, start, end) {
4791 if (this.patterns.points.test(attr)) {
4792 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4793 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4795 val = superclass.doMethod.call(this, attr, start, end);
4800 proto.setRuntimeAttribute = function(attr) {
4801 if (this.patterns.points.test(attr)) {
4802 var el = this.getEl();
4803 var attributes = this.attributes;
4805 var control = attributes['points']['control'] || [];
4809 if (control.length > 0 && !(control[0] instanceof Array)) {
4810 control = [control];
4813 for (i = 0,len = control.length; i < len; ++i) {
4814 tmp[i] = control[i];
4819 Roo.fly(el).position();
4821 if (isset(attributes['points']['from'])) {
4822 Roo.lib.Dom.setXY(el, attributes['points']['from']);
4825 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4828 start = this.getAttribute('points');
4831 if (isset(attributes['points']['to'])) {
4832 end = translateValues.call(this, attributes['points']['to'], start);
4834 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4835 for (i = 0,len = control.length; i < len; ++i) {
4836 control[i] = translateValues.call(this, control[i], start);
4840 } else if (isset(attributes['points']['by'])) {
4841 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4843 for (i = 0,len = control.length; i < len; ++i) {
4844 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4848 this.runtimeAttributes[attr] = [start];
4850 if (control.length > 0) {
4851 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4854 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4857 superclass.setRuntimeAttribute.call(this, attr);
4861 var translateValues = function(val, start) {
4862 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4863 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4868 var isset = function(prop) {
4869 return (typeof prop !== 'undefined');
4873 * Portions of this file are based on pieces of Yahoo User Interface Library
4874 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4875 * YUI licensed under the BSD License:
4876 * http://developer.yahoo.net/yui/license.txt
4877 * <script type="text/javascript">
4881 Roo.lib.Scroll = function(el, attributes, duration, method) {
4883 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4887 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4891 var superclass = Y.Scroll.superclass;
4892 var proto = Y.Scroll.prototype;
4894 proto.toString = function() {
4895 var el = this.getEl();
4896 var id = el.id || el.tagName;
4897 return ("Scroll " + id);
4900 proto.doMethod = function(attr, start, end) {
4903 if (attr == 'scroll') {
4905 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4906 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4910 val = superclass.doMethod.call(this, attr, start, end);
4915 proto.getAttribute = function(attr) {
4917 var el = this.getEl();
4919 if (attr == 'scroll') {
4920 val = [ el.scrollLeft, el.scrollTop ];
4922 val = superclass.getAttribute.call(this, attr);
4928 proto.setAttribute = function(attr, val, unit) {
4929 var el = this.getEl();
4931 if (attr == 'scroll') {
4932 el.scrollLeft = val[0];
4933 el.scrollTop = val[1];
4935 superclass.setAttribute.call(this, attr, val, unit);
4940 * Originally based of this code... - refactored for Roo...
4941 * https://github.com/aaalsaleh/undo-manager
4944 * @author Abdulrahman Alsaleh
4945 * @copyright 2015 Abdulrahman Alsaleh
4946 * @license MIT License (c)
4948 * Hackily modifyed by alan@roojs.com
4953 * TOTALLY UNTESTED...
4955 * Documentation to be done....
4960 * @class Roo.lib.UndoManager
4961 * An undo manager implementation in JavaScript. It follows the W3C UndoManager and DOM Transaction
4962 * Draft and the undocumented and disabled Mozilla Firefox's UndoManager implementation.
4968 editor.undoManager = new Roo.lib.UndoManager(1000, editor);
4972 * For more information see this blog post with examples:
4973 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4974 - Create Elements using DOM, HTML fragments and Templates</a>.
4976 * @param {Number} limit how far back to go ... use 1000?
4977 * @param {Object} scope usually use document..
4980 Roo.lib.UndoManager = function (limit, undoScopeHost)
4984 this.scope = undoScopeHost;
4985 this.fireEvent = typeof CustomEvent != 'undefined' && undoScopeHost && undoScopeHost.dispatchEvent;
4986 if (this.fireEvent) {
4993 Roo.lib.UndoManager.prototype = {
5004 * To push and execute a transaction, the method undoManager.transact
5005 * must be called by passing a transaction object as the first argument, and a merge
5006 * flag as the second argument. A transaction object has the following properties:
5010 undoManager.transact({
5012 execute: function() { ... },
5013 undo: function() { ... },
5014 // redo same as execute
5015 redo: function() { this.execute(); }
5018 // merge transaction
5019 undoManager.transact({
5021 execute: function() { ... }, // this will be run...
5022 undo: function() { ... }, // what to do when undo is run.
5023 // redo same as execute
5024 redo: function() { this.execute(); }
5029 * @param {Object} transaction The transaction to add to the stack.
5030 * @return {String} The HTML fragment
5034 transact : function (transaction, merge)
5036 if (arguments.length < 2) {
5037 throw new TypeError('Not enough arguments to UndoManager.transact.');
5040 transaction.execute();
5042 this.stack.splice(0, this.position);
5043 if (merge && this.length) {
5044 this.stack[0].push(transaction);
5046 this.stack.unshift([transaction]);
5051 if (this.limit && this.stack.length > this.limit) {
5052 this.length = this.stack.length = this.limit;
5054 this.length = this.stack.length;
5057 if (this.fireEvent) {
5058 this.scope.dispatchEvent(
5059 new CustomEvent('DOMTransaction', {
5061 transactions: this.stack[0].slice()
5069 //Roo.log("transaction: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
5076 //Roo.log("undo: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
5078 if (this.position < this.length) {
5079 for (var i = this.stack[this.position].length - 1; i >= 0; i--) {
5080 this.stack[this.position][i].undo();
5084 if (this.fireEvent) {
5085 this.scope.dispatchEvent(
5086 new CustomEvent('undo', {
5088 transactions: this.stack[this.position - 1].slice()
5100 if (this.position > 0) {
5101 for (var i = 0, n = this.stack[this.position - 1].length; i < n; i++) {
5102 this.stack[this.position - 1][i].redo();
5106 if (this.fireEvent) {
5107 this.scope.dispatchEvent(
5108 new CustomEvent('redo', {
5110 transactions: this.stack[this.position].slice()
5120 item : function (index)
5122 if (index >= 0 && index < this.length) {
5123 return this.stack[index].slice();
5128 clearUndo : function () {
5129 this.stack.length = this.length = this.position;
5132 clearRedo : function () {
5133 this.stack.splice(0, this.position);
5135 this.length = this.stack.length;
5138 * Reset the undo - probaly done on load to clear all history.
5145 this.current_html = this.scope.innerHTML;
5146 if (this.timer !== false) {
5147 clearTimeout(this.timer);
5159 // this will handle the undo/redo on the element.?
5160 bindEvents : function()
5162 var el = this.scope;
5163 el.undoManager = this;
5166 this.scope.addEventListener('keydown', function(e) {
5167 if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
5169 el.undoManager.redo(); // Ctrl/Command + Shift + Z
5171 el.undoManager.undo(); // Ctrl/Command + Z
5178 this.scope.addEventListener('keyup', function(e) {
5179 if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
5188 el.addEventListener('input', function(e) {
5189 if(el.innerHTML == t.current_html) {
5192 // only record events every second.
5193 if (t.timer !== false) {
5194 clearTimeout(t.timer);
5197 t.timer = setTimeout(function() { t.merge = false; }, 1000);
5199 t.addEvent(t.merge);
5200 t.merge = true; // ignore changes happening every second..
5204 * Manually add an event.
5205 * Normall called without arguements - and it will just get added to the stack.
5209 addEvent : function(merge)
5211 //Roo.log("undomanager +" + (merge ? 'Y':'n'));
5212 // not sure if this should clear the timer
5213 merge = typeof(merge) == 'undefined' ? false : merge;
5215 this.scope.undoManager.transact({
5217 oldHTML: this.current_html,
5218 newHTML: this.scope.innerHTML,
5219 // nothing to execute (content already changed when input is fired)
5220 execute: function() { },
5222 this.scope.innerHTML = this.current_html = this.oldHTML;
5225 this.scope.innerHTML = this.current_html = this.newHTML;
5227 }, false); //merge);
5231 this.current_html = this.scope.innerHTML;
5241 * @class Roo.lib.Range
5243 * This is a toolkit, normally used to copy features into a Dom Range element
5244 * Roo.lib.Range.wrap(x);
5249 Roo.lib.Range = function() { };
5252 * Wrap a Dom Range object, to give it new features...
5254 * @param {Range} the range to wrap
5256 Roo.lib.Range.wrap = function(r) {
5257 return Roo.apply(r, Roo.lib.Range.prototype);
5260 * find a parent node eg. LI / OL
5261 * @param {string|Array} node name or array of nodenames
5262 * @return {DomElement|false}
5264 Roo.apply(Roo.lib.Range.prototype,
5267 closest : function(str)
5269 if (typeof(str) != 'string') {
5270 // assume it's a array.
5271 for(var i = 0;i < str.length;i++) {
5272 var r = this.closest(str[i]);
5280 str = str.toLowerCase();
5281 var n = this.commonAncestorContainer; // might not be a node
5282 while (n.nodeType != 1) {
5286 if (n.nodeName.toLowerCase() == str ) {
5289 if (n.nodeName.toLowerCase() == 'body') {
5293 return n.closest(str) || false;
5296 cloneRange : function()
5298 return Roo.lib.Range.wrap(Range.prototype.cloneRange.call(this));
5301 * @class Roo.lib.Selection
5303 * This is a toolkit, normally used to copy features into a Dom Selection element
5304 * Roo.lib.Selection.wrap(x);
5309 Roo.lib.Selection = function() { };
5312 * Wrap a Dom Range object, to give it new features...
5314 * @param {Range} the range to wrap
5316 Roo.lib.Selection.wrap = function(r, doc) {
5317 Roo.apply(r, Roo.lib.Selection.prototype);
5318 r.ownerDocument = doc; // usefull so we dont have to keep referening to it.
5322 * find a parent node eg. LI / OL
5323 * @param {string|Array} node name or array of nodenames
5324 * @return {DomElement|false}
5326 Roo.apply(Roo.lib.Selection.prototype,
5329 * the owner document
5331 ownerDocument : false,
5333 getRangeAt : function(n)
5335 return Roo.lib.Range.wrap(Selection.prototype.getRangeAt.call(this,n));
5339 * insert node at selection
5340 * @param {DomElement|string} node
5341 * @param {string} cursor (after|in|none) where to place the cursor after inserting.
5343 insertNode: function(node, cursor)
5345 if (typeof(node) == 'string') {
5346 node = this.ownerDocument.createElement(node);
5347 if (cursor == 'in') {
5348 node.innerHTML = ' ';
5352 var range = this.getRangeAt(0);
5354 if (this.type != 'Caret') {
5355 range.deleteContents();
5357 var sn = node.childNodes[0]; // select the contents.
5361 range.insertNode(node);
5362 if (cursor == 'after') {
5363 node.insertAdjacentHTML('afterend', ' ');
5364 sn = node.nextSibling;
5367 if (cursor == 'none') {
5371 this.cursorText(sn);
5374 cursorText : function(n)
5377 //var range = this.getRangeAt(0);
5378 range = Roo.lib.Range.wrap(new Range());
5379 //range.selectNode(n);
5381 var ix = Array.from(n.parentNode.childNodes).indexOf(n);
5382 range.setStart(n.parentNode,ix);
5383 range.setEnd(n.parentNode,ix+1);
5384 //range.collapse(false);
5386 this.removeAllRanges();
5387 this.addRange(range);
5389 Roo.log([n, range, this,this.baseOffset,this.extentOffset, this.type]);
5391 cursorAfter : function(n)
5393 if (!n.nextSibling || n.nextSibling.nodeValue != ' ') {
5394 n.insertAdjacentHTML('afterend', ' ');
5396 this.cursorText (n.nextSibling);
5402 * Ext JS Library 1.1.1
5403 * Copyright(c) 2006-2007, Ext JS, LLC.
5405 * Originally Released Under LGPL - original licence link has changed is not relivant.
5408 * <script type="text/javascript">
5412 // nasty IE9 hack - what a pile of crap that is..
5414 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
5415 Range.prototype.createContextualFragment = function (html) {
5416 var doc = window.document;
5417 var container = doc.createElement("div");
5418 container.innerHTML = html;
5419 var frag = doc.createDocumentFragment(), n;
5420 while ((n = container.firstChild)) {
5421 frag.appendChild(n);
5428 * @class Roo.DomHelper
5429 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
5430 * 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>.
5433 Roo.DomHelper = function(){
5434 var tempTableEl = null;
5435 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
5436 var tableRe = /^table|tbody|tr|td$/i;
5438 // build as innerHTML where available
5440 var createHtml = function(o){
5441 if(typeof o == 'string'){
5450 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
5451 if(attr == "style"){
5453 if(typeof s == "function"){
5456 if(typeof s == "string"){
5457 b += ' style="' + s + '"';
5458 }else if(typeof s == "object"){
5461 if(typeof s[key] != "function"){
5462 b += key + ":" + s[key] + ";";
5469 b += ' class="' + o["cls"] + '"';
5470 }else if(attr == "htmlFor"){
5471 b += ' for="' + o["htmlFor"] + '"';
5473 b += " " + attr + '="' + o[attr] + '"';
5477 if(emptyTags.test(o.tag)){
5481 var cn = o.children || o.cn;
5483 //http://bugs.kde.org/show_bug.cgi?id=71506
5484 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5485 for(var i = 0, len = cn.length; i < len; i++) {
5486 b += createHtml(cn[i], b);
5489 b += createHtml(cn, b);
5495 b += "</" + o.tag + ">";
5502 var createDom = function(o, parentNode){
5504 // defininition craeted..
5506 if (o.ns && o.ns != 'html') {
5508 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
5509 xmlns[o.ns] = o.xmlns;
5512 if (typeof(xmlns[o.ns]) == 'undefined') {
5513 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
5519 if (typeof(o) == 'string') {
5520 return parentNode.appendChild(document.createTextNode(o));
5522 o.tag = o.tag || 'div';
5523 if (o.ns && Roo.isIE) {
5525 o.tag = o.ns + ':' + o.tag;
5528 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
5529 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
5532 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
5533 attr == "style" || typeof o[attr] == "function") { continue; }
5535 if(attr=="cls" && Roo.isIE){
5536 el.className = o["cls"];
5538 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
5544 Roo.DomHelper.applyStyles(el, o.style);
5545 var cn = o.children || o.cn;
5547 //http://bugs.kde.org/show_bug.cgi?id=71506
5548 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5549 for(var i = 0, len = cn.length; i < len; i++) {
5550 createDom(cn[i], el);
5557 el.innerHTML = o.html;
5560 parentNode.appendChild(el);
5565 var ieTable = function(depth, s, h, e){
5566 tempTableEl.innerHTML = [s, h, e].join('');
5567 var i = -1, el = tempTableEl;
5568 while(++i < depth && el.firstChild){
5574 // kill repeat to save bytes
5578 tbe = '</tbody>'+te,
5584 * Nasty code for IE's broken table implementation
5586 var insertIntoTable = function(tag, where, el, html){
5588 tempTableEl = document.createElement('div');
5593 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
5596 if(where == 'beforebegin'){
5600 before = el.nextSibling;
5603 node = ieTable(4, trs, html, tre);
5605 else if(tag == 'tr'){
5606 if(where == 'beforebegin'){
5609 node = ieTable(3, tbs, html, tbe);
5610 } else if(where == 'afterend'){
5611 before = el.nextSibling;
5613 node = ieTable(3, tbs, html, tbe);
5614 } else{ // INTO a TR
5615 if(where == 'afterbegin'){
5616 before = el.firstChild;
5618 node = ieTable(4, trs, html, tre);
5620 } else if(tag == 'tbody'){
5621 if(where == 'beforebegin'){
5624 node = ieTable(2, ts, html, te);
5625 } else if(where == 'afterend'){
5626 before = el.nextSibling;
5628 node = ieTable(2, ts, html, te);
5630 if(where == 'afterbegin'){
5631 before = el.firstChild;
5633 node = ieTable(3, tbs, html, tbe);
5636 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
5639 if(where == 'afterbegin'){
5640 before = el.firstChild;
5642 node = ieTable(2, ts, html, te);
5644 el.insertBefore(node, before);
5648 // this is a bit like the react update code...
5651 var updateNode = function(from, to)
5653 // should we handle non-standard elements?
5654 Roo.log(["UpdateNode" , from, to]);
5655 if (from.nodeType != to.nodeType) {
5656 Roo.log(["ReplaceChild - mismatch notType" , to, from ]);
5657 from.parentNode.replaceChild(to, from);
5660 if (from.nodeType == 3) {
5661 // assume it's text?!
5662 if (from.data == to.data) {
5665 from.data = to.data;
5668 if (!from.parentNode) {
5669 // not sure why this is happening?
5672 // assume 'to' doesnt have '1/3 nodetypes!
5673 // not sure why, by from, parent node might not exist?
5674 if (from.nodeType !=1 || from.tagName != to.tagName) {
5675 Roo.log(["ReplaceChild" , from, to ]);
5677 from.parentNode.replaceChild(to, from);
5680 // compare attributes
5681 var ar = Array.from(from.attributes);
5682 for(var i = 0; i< ar.length;i++) {
5683 if (to.hasAttribute(ar[i].name)) {
5686 if (ar[i].name == 'id') { // always keep ids?
5689 //if (ar[i].name == 'style') {
5690 // throw "style removed?";
5692 Roo.log("removeAttribute" + ar[i].name);
5693 from.removeAttribute(ar[i].name);
5696 for(var i = 0; i< ar.length;i++) {
5697 if (from.getAttribute(ar[i].name) == to.getAttribute(ar[i].name)) {
5698 Roo.log("skipAttribute " + ar[i].name + '=' + to.getAttribute(ar[i].name));
5701 Roo.log("updateAttribute " + ar[i].name + '=>' + to.getAttribute(ar[i].name));
5702 from.setAttribute(ar[i].name, to.getAttribute(ar[i].name));
5705 var far = Array.from(from.childNodes);
5706 var tar = Array.from(to.childNodes);
5707 // if the lengths are different.. then it's probably a editable content change, rather than
5708 // a change of the block definition..
5710 // this did notwork , as our rebuilt nodes did not include ID's so did not match at all.
5711 /*if (from.innerHTML == to.innerHTML) {
5714 if (far.length != tar.length) {
5715 from.innerHTML = to.innerHTML;
5720 for(var i = 0; i < Math.max(tar.length, far.length); i++) {
5721 if (i >= far.length) {
5722 from.appendChild(tar[i]);
5723 Roo.log(["add", tar[i]]);
5725 } else if ( i >= tar.length) {
5726 from.removeChild(far[i]);
5727 Roo.log(["remove", far[i]]);
5730 updateNode(far[i], tar[i]);
5742 /** True to force the use of DOM instead of html fragments @type Boolean */
5746 * Returns the markup for the passed Element(s) config
5747 * @param {Object} o The Dom object spec (and children)
5750 markup : function(o){
5751 return createHtml(o);
5755 * Applies a style specification to an element
5756 * @param {String/HTMLElement} el The element to apply styles to
5757 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
5758 * a function which returns such a specification.
5760 applyStyles : function(el, styles){
5763 if(typeof styles == "string"){
5764 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
5766 while ((matches = re.exec(styles)) != null){
5767 el.setStyle(matches[1], matches[2]);
5769 }else if (typeof styles == "object"){
5770 for (var style in styles){
5771 el.setStyle(style, styles[style]);
5773 }else if (typeof styles == "function"){
5774 Roo.DomHelper.applyStyles(el, styles.call());
5780 * Inserts an HTML fragment into the Dom
5781 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
5782 * @param {HTMLElement} el The context element
5783 * @param {String} html The HTML fragmenet
5784 * @return {HTMLElement} The new node
5786 insertHtml : function(where, el, html){
5787 where = where.toLowerCase();
5788 if(el.insertAdjacentHTML){
5789 if(tableRe.test(el.tagName)){
5791 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
5797 el.insertAdjacentHTML('BeforeBegin', html);
5798 return el.previousSibling;
5800 el.insertAdjacentHTML('AfterBegin', html);
5801 return el.firstChild;
5803 el.insertAdjacentHTML('BeforeEnd', html);
5804 return el.lastChild;
5806 el.insertAdjacentHTML('AfterEnd', html);
5807 return el.nextSibling;
5809 throw 'Illegal insertion point -> "' + where + '"';
5811 var range = el.ownerDocument.createRange();
5815 range.setStartBefore(el);
5816 frag = range.createContextualFragment(html);
5817 el.parentNode.insertBefore(frag, el);
5818 return el.previousSibling;
5821 range.setStartBefore(el.firstChild);
5822 frag = range.createContextualFragment(html);
5823 el.insertBefore(frag, el.firstChild);
5824 return el.firstChild;
5826 el.innerHTML = html;
5827 return el.firstChild;
5831 range.setStartAfter(el.lastChild);
5832 frag = range.createContextualFragment(html);
5833 el.appendChild(frag);
5834 return el.lastChild;
5836 el.innerHTML = html;
5837 return el.lastChild;
5840 range.setStartAfter(el);
5841 frag = range.createContextualFragment(html);
5842 el.parentNode.insertBefore(frag, el.nextSibling);
5843 return el.nextSibling;
5845 throw 'Illegal insertion point -> "' + where + '"';
5849 * Creates new Dom element(s) and inserts them before el
5850 * @param {String/HTMLElement/Element} el The context element
5851 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5852 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5853 * @return {HTMLElement/Roo.Element} The new node
5855 insertBefore : function(el, o, returnElement){
5856 return this.doInsert(el, o, returnElement, "beforeBegin");
5860 * Creates new Dom element(s) and inserts them after el
5861 * @param {String/HTMLElement/Element} el The context element
5862 * @param {Object} o The Dom object spec (and children)
5863 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5864 * @return {HTMLElement/Roo.Element} The new node
5866 insertAfter : function(el, o, returnElement){
5867 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
5871 * Creates new Dom element(s) and inserts them as the first child of el
5872 * @param {String/HTMLElement/Element} el The context element
5873 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5874 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5875 * @return {HTMLElement/Roo.Element} The new node
5877 insertFirst : function(el, o, returnElement){
5878 return this.doInsert(el, o, returnElement, "afterBegin");
5882 doInsert : function(el, o, returnElement, pos, sibling){
5883 el = Roo.getDom(el);
5885 if(this.useDom || o.ns){
5886 newNode = createDom(o, null);
5887 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
5889 var html = createHtml(o);
5890 newNode = this.insertHtml(pos, el, html);
5892 return returnElement ? Roo.get(newNode, true) : newNode;
5896 * Creates new Dom element(s) and appends them to el
5897 * @param {String/HTMLElement/Element} el The context element
5898 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5899 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5900 * @return {HTMLElement/Roo.Element} The new node
5902 append : function(el, o, returnElement){
5903 el = Roo.getDom(el);
5905 if(this.useDom || o.ns){
5906 newNode = createDom(o, null);
5907 el.appendChild(newNode);
5909 var html = createHtml(o);
5910 newNode = this.insertHtml("beforeEnd", el, html);
5912 return returnElement ? Roo.get(newNode, true) : newNode;
5916 * Creates new Dom element(s) and overwrites the contents of el with them
5917 * @param {String/HTMLElement/Element} el The context element
5918 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5919 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5920 * @return {HTMLElement/Roo.Element} The new node
5922 overwrite : function(el, o, returnElement)
5924 el = Roo.getDom(el);
5927 while (el.childNodes.length) {
5928 el.removeChild(el.firstChild);
5932 el.innerHTML = createHtml(o);
5935 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5939 * Creates a new Roo.DomHelper.Template from the Dom object spec
5940 * @param {Object} o The Dom object spec (and children)
5941 * @return {Roo.DomHelper.Template} The new template
5943 createTemplate : function(o){
5944 var html = createHtml(o);
5945 return new Roo.Template(html);
5948 * Updates the first element with the spec from the o (replacing if necessary)
5949 * This iterates through the children, and updates attributes / children etc..
5950 * @param {String/HTMLElement/Element} el The context element
5951 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5954 update : function(el, o)
5956 updateNode(Roo.getDom(el), createDom(o));
5965 * Ext JS Library 1.1.1
5966 * Copyright(c) 2006-2007, Ext JS, LLC.
5968 * Originally Released Under LGPL - original licence link has changed is not relivant.
5971 * <script type="text/javascript">
5975 * @class Roo.Template
5976 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
5977 * For a list of available format functions, see {@link Roo.util.Format}.<br />
5980 var t = new Roo.Template({
5981 html : '<div name="{id}">' +
5982 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
5984 myformat: function (value, allValues) {
5985 return 'XX' + value;
5988 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
5990 * For more information see this blog post with examples:
5991 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
5992 - Create Elements using DOM, HTML fragments and Templates</a>.
5994 * @param {Object} cfg - Configuration object.
5996 Roo.Template = function(cfg){
5998 if(cfg instanceof Array){
6000 }else if(arguments.length > 1){
6001 cfg = Array.prototype.join.call(arguments, "");
6005 if (typeof(cfg) == 'object') {
6016 Roo.Template.prototype = {
6019 * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
6025 * @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..
6026 * it should be fixed so that template is observable...
6030 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
6038 * Returns an HTML fragment of this template with the specified values applied.
6039 * @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'})
6040 * @return {String} The HTML fragment
6045 applyTemplate : function(values){
6046 //Roo.log(["applyTemplate", values]);
6050 return this.compiled(values);
6052 var useF = this.disableFormats !== true;
6053 var fm = Roo.util.Format, tpl = this;
6054 var fn = function(m, name, format, args){
6056 if(format.substr(0, 5) == "this."){
6057 return tpl.call(format.substr(5), values[name], values);
6060 // quoted values are required for strings in compiled templates,
6061 // but for non compiled we need to strip them
6062 // quoted reversed for jsmin
6063 var re = /^\s*['"](.*)["']\s*$/;
6064 args = args.split(',');
6065 for(var i = 0, len = args.length; i < len; i++){
6066 args[i] = args[i].replace(re, "$1");
6068 args = [values[name]].concat(args);
6070 args = [values[name]];
6072 return fm[format].apply(fm, args);
6075 return values[name] !== undefined ? values[name] : "";
6078 return this.html.replace(this.re, fn);
6096 this.loading = true;
6097 this.compiled = false;
6099 var cx = new Roo.data.Connection();
6103 success : function (response) {
6107 _t.set(response.responseText,true);
6113 failure : function(response) {
6114 Roo.log("Template failed to load from " + _t.url);
6121 * Sets the HTML used as the template and optionally compiles it.
6122 * @param {String} html
6123 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
6124 * @return {Roo.Template} this
6126 set : function(html, compile){
6128 this.compiled = false;
6136 * True to disable format functions (defaults to false)
6139 disableFormats : false,
6142 * The regular expression used to match template variables
6146 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
6149 * Compiles the template into an internal function, eliminating the RegEx overhead.
6150 * @return {Roo.Template} this
6152 compile : function(){
6153 var fm = Roo.util.Format;
6154 var useF = this.disableFormats !== true;
6155 var sep = Roo.isGecko ? "+" : ",";
6156 var fn = function(m, name, format, args){
6158 args = args ? ',' + args : "";
6159 if(format.substr(0, 5) != "this."){
6160 format = "fm." + format + '(';
6162 format = 'this.call("'+ format.substr(5) + '", ';
6166 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
6168 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
6171 // branched to use + in gecko and [].join() in others
6173 body = "this.compiled = function(values){ return '" +
6174 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
6177 body = ["this.compiled = function(values){ return ['"];
6178 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
6179 body.push("'].join('');};");
6180 body = body.join('');
6190 // private function used to call members
6191 call : function(fnName, value, allValues){
6192 return this[fnName](value, allValues);
6196 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
6197 * @param {String/HTMLElement/Roo.Element} el The context element
6198 * @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'})
6199 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6200 * @return {HTMLElement/Roo.Element} The new node or Element
6202 insertFirst: function(el, values, returnElement){
6203 return this.doInsert('afterBegin', el, values, returnElement);
6207 * Applies the supplied values to the template and inserts the new node(s) before el.
6208 * @param {String/HTMLElement/Roo.Element} el The context element
6209 * @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'})
6210 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6211 * @return {HTMLElement/Roo.Element} The new node or Element
6213 insertBefore: function(el, values, returnElement){
6214 return this.doInsert('beforeBegin', el, values, returnElement);
6218 * Applies the supplied values to the template and inserts the new node(s) after el.
6219 * @param {String/HTMLElement/Roo.Element} el The context element
6220 * @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'})
6221 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6222 * @return {HTMLElement/Roo.Element} The new node or Element
6224 insertAfter : function(el, values, returnElement){
6225 return this.doInsert('afterEnd', el, values, returnElement);
6229 * Applies the supplied values to the template and appends the new node(s) to el.
6230 * @param {String/HTMLElement/Roo.Element} el The context element
6231 * @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'})
6232 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6233 * @return {HTMLElement/Roo.Element} The new node or Element
6235 append : function(el, values, returnElement){
6236 return this.doInsert('beforeEnd', el, values, returnElement);
6239 doInsert : function(where, el, values, returnEl){
6240 el = Roo.getDom(el);
6241 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
6242 return returnEl ? Roo.get(newNode, true) : newNode;
6246 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
6247 * @param {String/HTMLElement/Roo.Element} el The context element
6248 * @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'})
6249 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6250 * @return {HTMLElement/Roo.Element} The new node or Element
6252 overwrite : function(el, values, returnElement){
6253 el = Roo.getDom(el);
6254 el.innerHTML = this.applyTemplate(values);
6255 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
6259 * Alias for {@link #applyTemplate}
6262 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
6265 Roo.DomHelper.Template = Roo.Template;
6268 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
6269 * @param {String/HTMLElement} el A DOM element or its id
6270 * @returns {Roo.Template} The created template
6273 Roo.Template.from = function(el){
6274 el = Roo.getDom(el);
6275 return new Roo.Template(el.value || el.innerHTML);
6278 * Ext JS Library 1.1.1
6279 * Copyright(c) 2006-2007, Ext JS, LLC.
6281 * Originally Released Under LGPL - original licence link has changed is not relivant.
6284 * <script type="text/javascript">
6289 * This is code is also distributed under MIT license for use
6290 * with jQuery and prototype JavaScript libraries.
6293 * @class Roo.DomQuery
6294 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).
6296 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>
6299 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.
6301 <h4>Element Selectors:</h4>
6303 <li> <b>*</b> any element</li>
6304 <li> <b>E</b> an element with the tag E</li>
6305 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
6306 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
6307 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
6308 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
6310 <h4>Attribute Selectors:</h4>
6311 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
6313 <li> <b>E[foo]</b> has an attribute "foo"</li>
6314 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
6315 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
6316 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
6317 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
6318 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
6319 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
6321 <h4>Pseudo Classes:</h4>
6323 <li> <b>E:first-child</b> E is the first child of its parent</li>
6324 <li> <b>E:last-child</b> E is the last child of its parent</li>
6325 <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>
6326 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
6327 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
6328 <li> <b>E:only-child</b> E is the only child of its parent</li>
6329 <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>
6330 <li> <b>E:first</b> the first E in the resultset</li>
6331 <li> <b>E:last</b> the last E in the resultset</li>
6332 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
6333 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
6334 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
6335 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
6336 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
6337 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
6338 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
6339 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
6340 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
6342 <h4>CSS Value Selectors:</h4>
6344 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
6345 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
6346 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
6347 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
6348 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
6349 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
6353 Roo.DomQuery = function(){
6354 var cache = {}, simpleCache = {}, valueCache = {};
6355 var nonSpace = /\S/;
6356 var trimRe = /^\s+|\s+$/g;
6357 var tplRe = /\{(\d+)\}/g;
6358 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
6359 var tagTokenRe = /^(#)?([\w-\*]+)/;
6360 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
6362 function child(p, index){
6364 var n = p.firstChild;
6366 if(n.nodeType == 1){
6377 while((n = n.nextSibling) && n.nodeType != 1);
6382 while((n = n.previousSibling) && n.nodeType != 1);
6386 function children(d){
6387 var n = d.firstChild, ni = -1;
6389 var nx = n.nextSibling;
6390 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
6400 function byClassName(c, a, v){
6404 var r = [], ri = -1, cn;
6405 for(var i = 0, ci; ci = c[i]; i++){
6409 ( (ci instanceof SVGElement) ? ci.className.baseVal : ci.className)
6410 +' ').indexOf(v) != -1){
6417 function attrValue(n, attr){
6418 if(!n.tagName && typeof n.length != "undefined"){
6427 if(attr == "class" || attr == "className"){
6428 return (n instanceof SVGElement) ? n.className.baseVal : n.className;
6430 return n.getAttribute(attr) || n[attr];
6434 function getNodes(ns, mode, tagName){
6435 var result = [], ri = -1, cs;
6439 tagName = tagName || "*";
6440 if(typeof ns.getElementsByTagName != "undefined"){
6444 for(var i = 0, ni; ni = ns[i]; i++){
6445 cs = ni.getElementsByTagName(tagName);
6446 for(var j = 0, ci; ci = cs[j]; j++){
6450 }else if(mode == "/" || mode == ">"){
6451 var utag = tagName.toUpperCase();
6452 for(var i = 0, ni, cn; ni = ns[i]; i++){
6453 cn = ni.children || ni.childNodes;
6454 for(var j = 0, cj; cj = cn[j]; j++){
6455 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
6460 }else if(mode == "+"){
6461 var utag = tagName.toUpperCase();
6462 for(var i = 0, n; n = ns[i]; i++){
6463 while((n = n.nextSibling) && n.nodeType != 1);
6464 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
6468 }else if(mode == "~"){
6469 for(var i = 0, n; n = ns[i]; i++){
6470 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
6479 function concat(a, b){
6483 for(var i = 0, l = b.length; i < l; i++){
6489 function byTag(cs, tagName){
6490 if(cs.tagName || cs == document){
6496 var r = [], ri = -1;
6497 tagName = tagName.toLowerCase();
6498 for(var i = 0, ci; ci = cs[i]; i++){
6499 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
6506 function byId(cs, attr, id){
6507 if(cs.tagName || cs == document){
6513 var r = [], ri = -1;
6514 for(var i = 0,ci; ci = cs[i]; i++){
6515 if(ci && ci.id == id){
6523 function byAttribute(cs, attr, value, op, custom){
6524 var r = [], ri = -1, st = custom=="{";
6525 var f = Roo.DomQuery.operators[op];
6526 for(var i = 0, ci; ci = cs[i]; i++){
6529 a = Roo.DomQuery.getStyle(ci, attr);
6531 else if(attr == "class" || attr == "className"){
6532 a = (ci instanceof SVGElement) ? ci.className.baseVal : ci.className;
6533 }else if(attr == "for"){
6535 }else if(attr == "href"){
6536 a = ci.getAttribute("href", 2);
6538 a = ci.getAttribute(attr);
6540 if((f && f(a, value)) || (!f && a)){
6547 function byPseudo(cs, name, value){
6548 return Roo.DomQuery.pseudos[name](cs, value);
6551 // This is for IE MSXML which does not support expandos.
6552 // IE runs the same speed using setAttribute, however FF slows way down
6553 // and Safari completely fails so they need to continue to use expandos.
6554 var isIE = window.ActiveXObject ? true : false;
6556 // this eval is stop the compressor from
6557 // renaming the variable to something shorter
6559 /** eval:var:batch */
6564 function nodupIEXml(cs){
6566 cs[0].setAttribute("_nodup", d);
6568 for(var i = 1, len = cs.length; i < len; i++){
6570 if(!c.getAttribute("_nodup") != d){
6571 c.setAttribute("_nodup", d);
6575 for(var i = 0, len = cs.length; i < len; i++){
6576 cs[i].removeAttribute("_nodup");
6585 var len = cs.length, c, i, r = cs, cj, ri = -1;
6586 if(!len || typeof cs.nodeType != "undefined" || len == 1){
6589 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
6590 return nodupIEXml(cs);
6594 for(i = 1; c = cs[i]; i++){
6599 for(var j = 0; j < i; j++){
6602 for(j = i+1; cj = cs[j]; j++){
6614 function quickDiffIEXml(c1, c2){
6616 for(var i = 0, len = c1.length; i < len; i++){
6617 c1[i].setAttribute("_qdiff", d);
6620 for(var i = 0, len = c2.length; i < len; i++){
6621 if(c2[i].getAttribute("_qdiff") != d){
6622 r[r.length] = c2[i];
6625 for(var i = 0, len = c1.length; i < len; i++){
6626 c1[i].removeAttribute("_qdiff");
6631 function quickDiff(c1, c2){
6632 var len1 = c1.length;
6636 if(isIE && c1[0].selectSingleNode){
6637 return quickDiffIEXml(c1, c2);
6640 for(var i = 0; i < len1; i++){
6644 for(var i = 0, len = c2.length; i < len; i++){
6645 if(c2[i]._qdiff != d){
6646 r[r.length] = c2[i];
6652 function quickId(ns, mode, root, id){
6654 var d = root.ownerDocument || root;
6655 return d.getElementById(id);
6657 ns = getNodes(ns, mode, "*");
6658 return byId(ns, null, id);
6662 getStyle : function(el, name){
6663 return Roo.fly(el).getStyle(name);
6666 * Compiles a selector/xpath query into a reusable function. The returned function
6667 * takes one parameter "root" (optional), which is the context node from where the query should start.
6668 * @param {String} selector The selector/xpath query
6669 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
6670 * @return {Function}
6672 compile : function(path, type){
6673 type = type || "select";
6675 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
6676 var q = path, mode, lq;
6677 var tk = Roo.DomQuery.matchers;
6678 var tklen = tk.length;
6681 // accept leading mode switch
6682 var lmode = q.match(modeRe);
6683 if(lmode && lmode[1]){
6684 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
6685 q = q.replace(lmode[1], "");
6687 // strip leading slashes
6688 while(path.substr(0, 1)=="/"){
6689 path = path.substr(1);
6692 while(q && lq != q){
6694 var tm = q.match(tagTokenRe);
6695 if(type == "select"){
6698 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
6700 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
6702 q = q.replace(tm[0], "");
6703 }else if(q.substr(0, 1) != '@'){
6704 fn[fn.length] = 'n = getNodes(n, mode, "*");';
6709 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
6711 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
6713 q = q.replace(tm[0], "");
6716 while(!(mm = q.match(modeRe))){
6717 var matched = false;
6718 for(var j = 0; j < tklen; j++){
6720 var m = q.match(t.re);
6722 fn[fn.length] = t.select.replace(tplRe, function(x, i){
6725 q = q.replace(m[0], "");
6730 // prevent infinite loop on bad selector
6732 throw 'Error parsing selector, parsing failed at "' + q + '"';
6736 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
6737 q = q.replace(mm[1], "");
6740 fn[fn.length] = "return nodup(n);\n}";
6743 * list of variables that need from compression as they are used by eval.
6753 * eval:var:byClassName
6755 * eval:var:byAttribute
6756 * eval:var:attrValue
6764 * Selects a group of elements.
6765 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
6766 * @param {Node} root (optional) The start of the query (defaults to document).
6769 select : function(path, root, type){
6770 if(!root || root == document){
6773 if(typeof root == "string"){
6774 root = document.getElementById(root);
6776 var paths = path.split(",");
6778 for(var i = 0, len = paths.length; i < len; i++){
6779 var p = paths[i].replace(trimRe, "");
6781 cache[p] = Roo.DomQuery.compile(p);
6783 throw p + " is not a valid selector";
6786 var result = cache[p](root);
6787 if(result && result != document){
6788 results = results.concat(result);
6791 if(paths.length > 1){
6792 return nodup(results);
6798 * Selects a single element.
6799 * @param {String} selector The selector/xpath query
6800 * @param {Node} root (optional) The start of the query (defaults to document).
6803 selectNode : function(path, root){
6804 return Roo.DomQuery.select(path, root)[0];
6808 * Selects the value of a node, optionally replacing null with the defaultValue.
6809 * @param {String} selector The selector/xpath query
6810 * @param {Node} root (optional) The start of the query (defaults to document).
6811 * @param {String} defaultValue
6813 selectValue : function(path, root, defaultValue){
6814 path = path.replace(trimRe, "");
6815 if(!valueCache[path]){
6816 valueCache[path] = Roo.DomQuery.compile(path, "select");
6818 var n = valueCache[path](root);
6819 n = n[0] ? n[0] : n;
6820 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
6821 return ((v === null||v === undefined||v==='') ? defaultValue : v);
6825 * Selects the value of a node, parsing integers and floats.
6826 * @param {String} selector The selector/xpath query
6827 * @param {Node} root (optional) The start of the query (defaults to document).
6828 * @param {Number} defaultValue
6831 selectNumber : function(path, root, defaultValue){
6832 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
6833 return parseFloat(v);
6837 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
6838 * @param {String/HTMLElement/Array} el An element id, element or array of elements
6839 * @param {String} selector The simple selector to test
6842 is : function(el, ss){
6843 if(typeof el == "string"){
6844 el = document.getElementById(el);
6846 var isArray = (el instanceof Array);
6847 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
6848 return isArray ? (result.length == el.length) : (result.length > 0);
6852 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
6853 * @param {Array} el An array of elements to filter
6854 * @param {String} selector The simple selector to test
6855 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
6856 * the selector instead of the ones that match
6859 filter : function(els, ss, nonMatches){
6860 ss = ss.replace(trimRe, "");
6861 if(!simpleCache[ss]){
6862 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
6864 var result = simpleCache[ss](els);
6865 return nonMatches ? quickDiff(result, els) : result;
6869 * Collection of matching regular expressions and code snippets.
6873 select: 'n = byClassName(n, null, " {1} ");'
6875 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
6876 select: 'n = byPseudo(n, "{1}", "{2}");'
6878 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
6879 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
6882 select: 'n = byId(n, null, "{1}");'
6885 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
6890 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
6891 * 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, > <.
6894 "=" : function(a, v){
6897 "!=" : function(a, v){
6900 "^=" : function(a, v){
6901 return a && a.substr(0, v.length) == v;
6903 "$=" : function(a, v){
6904 return a && a.substr(a.length-v.length) == v;
6906 "*=" : function(a, v){
6907 return a && a.indexOf(v) !== -1;
6909 "%=" : function(a, v){
6910 return (a % v) == 0;
6912 "|=" : function(a, v){
6913 return a && (a == v || a.substr(0, v.length+1) == v+'-');
6915 "~=" : function(a, v){
6916 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
6921 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
6922 * and the argument (if any) supplied in the selector.
6925 "first-child" : function(c){
6926 var r = [], ri = -1, n;
6927 for(var i = 0, ci; ci = n = c[i]; i++){
6928 while((n = n.previousSibling) && n.nodeType != 1);
6936 "last-child" : function(c){
6937 var r = [], ri = -1, n;
6938 for(var i = 0, ci; ci = n = c[i]; i++){
6939 while((n = n.nextSibling) && n.nodeType != 1);
6947 "nth-child" : function(c, a) {
6948 var r = [], ri = -1;
6949 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
6950 var f = (m[1] || 1) - 0, l = m[2] - 0;
6951 for(var i = 0, n; n = c[i]; i++){
6952 var pn = n.parentNode;
6953 if (batch != pn._batch) {
6955 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
6956 if(cn.nodeType == 1){
6963 if (l == 0 || n.nodeIndex == l){
6966 } else if ((n.nodeIndex + l) % f == 0){
6974 "only-child" : function(c){
6975 var r = [], ri = -1;;
6976 for(var i = 0, ci; ci = c[i]; i++){
6977 if(!prev(ci) && !next(ci)){
6984 "empty" : function(c){
6985 var r = [], ri = -1;
6986 for(var i = 0, ci; ci = c[i]; i++){
6987 var cns = ci.childNodes, j = 0, cn, empty = true;
6990 if(cn.nodeType == 1 || cn.nodeType == 3){
7002 "contains" : function(c, v){
7003 var r = [], ri = -1;
7004 for(var i = 0, ci; ci = c[i]; i++){
7005 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
7012 "nodeValue" : function(c, v){
7013 var r = [], ri = -1;
7014 for(var i = 0, ci; ci = c[i]; i++){
7015 if(ci.firstChild && ci.firstChild.nodeValue == v){
7022 "checked" : function(c){
7023 var r = [], ri = -1;
7024 for(var i = 0, ci; ci = c[i]; i++){
7025 if(ci.checked == true){
7032 "not" : function(c, ss){
7033 return Roo.DomQuery.filter(c, ss, true);
7036 "odd" : function(c){
7037 return this["nth-child"](c, "odd");
7040 "even" : function(c){
7041 return this["nth-child"](c, "even");
7044 "nth" : function(c, a){
7045 return c[a-1] || [];
7048 "first" : function(c){
7052 "last" : function(c){
7053 return c[c.length-1] || [];
7056 "has" : function(c, ss){
7057 var s = Roo.DomQuery.select;
7058 var r = [], ri = -1;
7059 for(var i = 0, ci; ci = c[i]; i++){
7060 if(s(ss, ci).length > 0){
7067 "next" : function(c, ss){
7068 var is = Roo.DomQuery.is;
7069 var r = [], ri = -1;
7070 for(var i = 0, ci; ci = c[i]; i++){
7079 "prev" : function(c, ss){
7080 var is = Roo.DomQuery.is;
7081 var r = [], ri = -1;
7082 for(var i = 0, ci; ci = c[i]; i++){
7095 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
7096 * @param {String} path The selector/xpath query
7097 * @param {Node} root (optional) The start of the query (defaults to document).
7102 Roo.query = Roo.DomQuery.select;
7105 * Ext JS Library 1.1.1
7106 * Copyright(c) 2006-2007, Ext JS, LLC.
7108 * Originally Released Under LGPL - original licence link has changed is not relivant.
7111 * <script type="text/javascript">
7115 * @class Roo.util.Observable
7116 * Base class that provides a common interface for publishing events. Subclasses are expected to
7117 * to have a property "events" with all the events defined.<br>
7120 Employee = function(name){
7127 Roo.extend(Employee, Roo.util.Observable);
7129 * @param {Object} config properties to use (incuding events / listeners)
7132 Roo.util.Observable = function(cfg){
7135 this.addEvents(cfg.events || {});
7137 delete cfg.events; // make sure
7140 Roo.apply(this, cfg);
7143 this.on(this.listeners);
7144 delete this.listeners;
7147 Roo.util.Observable.prototype = {
7149 * @cfg {Object} listeners list of events and functions to call for this object,
7153 'click' : function(e) {
7163 * Fires the specified event with the passed parameters (minus the event name).
7164 * @param {String} eventName
7165 * @param {Object...} args Variable number of parameters are passed to handlers
7166 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
7168 fireEvent : function(){
7169 var ce = this.events[arguments[0].toLowerCase()];
7170 if(typeof ce == "object"){
7171 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
7178 filterOptRe : /^(?:scope|delay|buffer|single)$/,
7181 * Appends an event handler to this component
7182 * @param {String} eventName The type of event to listen for
7183 * @param {Function} handler The method the event invokes
7184 * @param {Object} scope (optional) The scope in which to execute the handler
7185 * function. The handler function's "this" context.
7186 * @param {Object} options (optional) An object containing handler configuration
7187 * properties. This may contain any of the following properties:<ul>
7188 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7189 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7190 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7191 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7192 * by the specified number of milliseconds. If the event fires again within that time, the original
7193 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7196 * <b>Combining Options</b><br>
7197 * Using the options argument, it is possible to combine different types of listeners:<br>
7199 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
7201 el.on('click', this.onClick, this, {
7208 * <b>Attaching multiple handlers in 1 call</b><br>
7209 * The method also allows for a single argument to be passed which is a config object containing properties
7210 * which specify multiple handlers.
7219 fn: this.onMouseOver,
7223 fn: this.onMouseOut,
7229 * Or a shorthand syntax which passes the same scope object to all handlers:
7232 'click': this.onClick,
7233 'mouseover': this.onMouseOver,
7234 'mouseout': this.onMouseOut,
7239 addListener : function(eventName, fn, scope, o){
7240 if(typeof eventName == "object"){
7243 if(this.filterOptRe.test(e)){
7246 if(typeof o[e] == "function"){
7248 this.addListener(e, o[e], o.scope, o);
7250 // individual options
7251 this.addListener(e, o[e].fn, o[e].scope, o[e]);
7256 o = (!o || typeof o == "boolean") ? {} : o;
7257 eventName = eventName.toLowerCase();
7258 var ce = this.events[eventName] || true;
7259 if(typeof ce == "boolean"){
7260 ce = new Roo.util.Event(this, eventName);
7261 this.events[eventName] = ce;
7263 ce.addListener(fn, scope, o);
7267 * Removes a listener
7268 * @param {String} eventName The type of event to listen for
7269 * @param {Function} handler The handler to remove
7270 * @param {Object} scope (optional) The scope (this object) for the handler
7272 removeListener : function(eventName, fn, scope){
7273 var ce = this.events[eventName.toLowerCase()];
7274 if(typeof ce == "object"){
7275 ce.removeListener(fn, scope);
7280 * Removes all listeners for this object
7282 purgeListeners : function(){
7283 for(var evt in this.events){
7284 if(typeof this.events[evt] == "object"){
7285 this.events[evt].clearListeners();
7290 relayEvents : function(o, events){
7291 var createHandler = function(ename){
7294 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
7297 for(var i = 0, len = events.length; i < len; i++){
7298 var ename = events[i];
7299 if(!this.events[ename]){
7300 this.events[ename] = true;
7302 o.on(ename, createHandler(ename), this);
7307 * Used to define events on this Observable
7308 * @param {Object} object The object with the events defined
7310 addEvents : function(o){
7314 Roo.applyIf(this.events, o);
7318 * Checks to see if this object has any listeners for a specified event
7319 * @param {String} eventName The name of the event to check for
7320 * @return {Boolean} True if the event is being listened for, else false
7322 hasListener : function(eventName){
7323 var e = this.events[eventName];
7324 return typeof e == "object" && e.listeners.length > 0;
7328 * Appends an event handler to this element (shorthand for addListener)
7329 * @param {String} eventName The type of event to listen for
7330 * @param {Function} handler The method the event invokes
7331 * @param {Object} scope (optional) The scope in which to execute the handler
7332 * function. The handler function's "this" context.
7333 * @param {Object} options (optional)
7336 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
7338 * Removes a listener (shorthand for removeListener)
7339 * @param {String} eventName The type of event to listen for
7340 * @param {Function} handler The handler to remove
7341 * @param {Object} scope (optional) The scope (this object) for the handler
7344 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
7347 * Starts capture on the specified Observable. All events will be passed
7348 * to the supplied function with the event name + standard signature of the event
7349 * <b>before</b> the event is fired. If the supplied function returns false,
7350 * the event will not fire.
7351 * @param {Observable} o The Observable to capture
7352 * @param {Function} fn The function to call
7353 * @param {Object} scope (optional) The scope (this object) for the fn
7356 Roo.util.Observable.capture = function(o, fn, scope){
7357 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
7361 * Removes <b>all</b> added captures from the Observable.
7362 * @param {Observable} o The Observable to release
7365 Roo.util.Observable.releaseCapture = function(o){
7366 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
7371 var createBuffered = function(h, o, scope){
7372 var task = new Roo.util.DelayedTask();
7374 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
7378 var createSingle = function(h, e, fn, scope){
7380 e.removeListener(fn, scope);
7381 return h.apply(scope, arguments);
7385 var createDelayed = function(h, o, scope){
7387 var args = Array.prototype.slice.call(arguments, 0);
7388 setTimeout(function(){
7389 h.apply(scope, args);
7394 Roo.util.Event = function(obj, name){
7397 this.listeners = [];
7400 Roo.util.Event.prototype = {
7401 addListener : function(fn, scope, options){
7402 var o = options || {};
7403 scope = scope || this.obj;
7404 if(!this.isListening(fn, scope)){
7405 var l = {fn: fn, scope: scope, options: o};
7408 h = createDelayed(h, o, scope);
7411 h = createSingle(h, this, fn, scope);
7414 h = createBuffered(h, o, scope);
7417 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
7418 this.listeners.push(l);
7420 this.listeners = this.listeners.slice(0);
7421 this.listeners.push(l);
7426 findListener : function(fn, scope){
7427 scope = scope || this.obj;
7428 var ls = this.listeners;
7429 for(var i = 0, len = ls.length; i < len; i++){
7431 if(l.fn == fn && l.scope == scope){
7438 isListening : function(fn, scope){
7439 return this.findListener(fn, scope) != -1;
7442 removeListener : function(fn, scope){
7444 if((index = this.findListener(fn, scope)) != -1){
7446 this.listeners.splice(index, 1);
7448 this.listeners = this.listeners.slice(0);
7449 this.listeners.splice(index, 1);
7456 clearListeners : function(){
7457 this.listeners = [];
7461 var ls = this.listeners, scope, len = ls.length;
7464 var args = Array.prototype.slice.call(arguments, 0);
7465 for(var i = 0; i < len; i++){
7467 if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
7468 this.firing = false;
7472 this.firing = false;
7479 * Copyright(c) 2007-2017, Roo J Solutions Ltd
7486 * @class Roo.Document
7487 * @extends Roo.util.Observable
7488 * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
7490 * @param {Object} config the methods and properties of the 'base' class for the application.
7492 * Generic Page handler - implement this to start your app..
7495 * MyProject = new Roo.Document({
7497 'load' : true // your events..
7500 'ready' : function() {
7501 // fired on Roo.onReady()
7506 Roo.Document = function(cfg) {
7511 Roo.util.Observable.call(this,cfg);
7515 Roo.onReady(function() {
7516 _this.fireEvent('ready');
7522 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
7524 * Ext JS Library 1.1.1
7525 * Copyright(c) 2006-2007, Ext JS, LLC.
7527 * Originally Released Under LGPL - original licence link has changed is not relivant.
7530 * <script type="text/javascript">
7534 * @class Roo.EventManager
7535 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
7536 * several useful events directly.
7537 * See {@link Roo.EventObject} for more details on normalized event objects.
7540 Roo.EventManager = function(){
7541 var docReadyEvent, docReadyProcId, docReadyState = false;
7542 var resizeEvent, resizeTask, textEvent, textSize;
7543 var E = Roo.lib.Event;
7544 var D = Roo.lib.Dom;
7549 var fireDocReady = function(){
7551 docReadyState = true;
7554 clearInterval(docReadyProcId);
7556 if(Roo.isGecko || Roo.isOpera) {
7557 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
7560 var defer = document.getElementById("ie-deferred-loader");
7562 defer.onreadystatechange = null;
7563 defer.parentNode.removeChild(defer);
7567 docReadyEvent.fire();
7568 docReadyEvent.clearListeners();
7573 var initDocReady = function(){
7574 docReadyEvent = new Roo.util.Event();
7575 if(Roo.isGecko || Roo.isOpera) {
7576 document.addEventListener("DOMContentLoaded", fireDocReady, false);
7578 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
7579 var defer = document.getElementById("ie-deferred-loader");
7580 defer.onreadystatechange = function(){
7581 if(this.readyState == "complete"){
7585 }else if(Roo.isSafari){
7586 docReadyProcId = setInterval(function(){
7587 var rs = document.readyState;
7588 if(rs == "complete") {
7593 // no matter what, make sure it fires on load
7594 E.on(window, "load", fireDocReady);
7597 var createBuffered = function(h, o){
7598 var task = new Roo.util.DelayedTask(h);
7600 // create new event object impl so new events don't wipe out properties
7601 e = new Roo.EventObjectImpl(e);
7602 task.delay(o.buffer, h, null, [e]);
7606 var createSingle = function(h, el, ename, fn){
7608 Roo.EventManager.removeListener(el, ename, fn);
7613 var createDelayed = function(h, o){
7615 // create new event object impl so new events don't wipe out properties
7616 e = new Roo.EventObjectImpl(e);
7617 setTimeout(function(){
7622 var transitionEndVal = false;
7624 var transitionEnd = function()
7626 if (transitionEndVal) {
7627 return transitionEndVal;
7629 var el = document.createElement('div');
7631 var transEndEventNames = {
7632 WebkitTransition : 'webkitTransitionEnd',
7633 MozTransition : 'transitionend',
7634 OTransition : 'oTransitionEnd otransitionend',
7635 transition : 'transitionend'
7638 for (var name in transEndEventNames) {
7639 if (el.style[name] !== undefined) {
7640 transitionEndVal = transEndEventNames[name];
7641 return transitionEndVal ;
7648 var listen = function(element, ename, opt, fn, scope)
7650 var o = (!opt || typeof opt == "boolean") ? {} : opt;
7651 fn = fn || o.fn; scope = scope || o.scope;
7652 var el = Roo.getDom(element);
7656 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
7659 if (ename == 'transitionend') {
7660 ename = transitionEnd();
7662 var h = function(e){
7663 e = Roo.EventObject.setEvent(e);
7666 t = e.getTarget(o.delegate, el);
7673 if(o.stopEvent === true){
7676 if(o.preventDefault === true){
7679 if(o.stopPropagation === true){
7680 e.stopPropagation();
7683 if(o.normalized === false){
7687 fn.call(scope || el, e, t, o);
7690 h = createDelayed(h, o);
7693 h = createSingle(h, el, ename, fn);
7696 h = createBuffered(h, o);
7699 fn._handlers = fn._handlers || [];
7702 fn._handlers.push([Roo.id(el), ename, h]);
7706 E.on(el, ename, h); // this adds the actuall listener to the object..
7709 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
7710 el.addEventListener("DOMMouseScroll", h, false);
7711 E.on(window, 'unload', function(){
7712 el.removeEventListener("DOMMouseScroll", h, false);
7715 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7716 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
7721 var stopListening = function(el, ename, fn){
7722 var id = Roo.id(el), hds = fn._handlers, hd = fn;
7724 for(var i = 0, len = hds.length; i < len; i++){
7726 if(h[0] == id && h[1] == ename){
7733 E.un(el, ename, hd);
7734 el = Roo.getDom(el);
7735 if(ename == "mousewheel" && el.addEventListener){
7736 el.removeEventListener("DOMMouseScroll", hd, false);
7738 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7739 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
7743 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
7750 * @scope Roo.EventManager
7755 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
7756 * object with a Roo.EventObject
7757 * @param {Function} fn The method the event invokes
7758 * @param {Object} scope An object that becomes the scope of the handler
7759 * @param {boolean} override If true, the obj passed in becomes
7760 * the execution scope of the listener
7761 * @return {Function} The wrapped function
7764 wrap : function(fn, scope, override){
7766 Roo.EventObject.setEvent(e);
7767 fn.call(override ? scope || window : window, Roo.EventObject, scope);
7772 * Appends an event handler to an element (shorthand for addListener)
7773 * @param {String/HTMLElement} element The html element or id to assign the
7774 * @param {String} eventName The type of event to listen for
7775 * @param {Function} handler The method the event invokes
7776 * @param {Object} scope (optional) The scope in which to execute the handler
7777 * function. The handler function's "this" context.
7778 * @param {Object} options (optional) An object containing handler configuration
7779 * properties. This may contain any of the following properties:<ul>
7780 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7781 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7782 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7783 * <li>preventDefault {Boolean} True to prevent the default action</li>
7784 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7785 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7786 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7787 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7788 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7789 * by the specified number of milliseconds. If the event fires again within that time, the original
7790 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7793 * <b>Combining Options</b><br>
7794 * Using the options argument, it is possible to combine different types of listeners:<br>
7796 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7798 el.on('click', this.onClick, this, {
7805 * <b>Attaching multiple handlers in 1 call</b><br>
7806 * The method also allows for a single argument to be passed which is a config object containing properties
7807 * which specify multiple handlers.
7817 fn: this.onMouseOver
7826 * Or a shorthand syntax:<br>
7829 'click' : this.onClick,
7830 'mouseover' : this.onMouseOver,
7831 'mouseout' : this.onMouseOut
7835 addListener : function(element, eventName, fn, scope, options){
7836 if(typeof eventName == "object"){
7842 if(typeof o[e] == "function"){
7844 listen(element, e, o, o[e], o.scope);
7846 // individual options
7847 listen(element, e, o[e]);
7852 return listen(element, eventName, options, fn, scope);
7856 * Removes an event handler
7858 * @param {String/HTMLElement} element The id or html element to remove the
7860 * @param {String} eventName The type of event
7861 * @param {Function} fn
7862 * @return {Boolean} True if a listener was actually removed
7864 removeListener : function(element, eventName, fn){
7865 return stopListening(element, eventName, fn);
7869 * Fires when the document is ready (before onload and before images are loaded). Can be
7870 * accessed shorthanded Roo.onReady().
7871 * @param {Function} fn The method the event invokes
7872 * @param {Object} scope An object that becomes the scope of the handler
7873 * @param {boolean} options
7875 onDocumentReady : function(fn, scope, options){
7876 if(docReadyState){ // if it already fired
7877 docReadyEvent.addListener(fn, scope, options);
7878 docReadyEvent.fire();
7879 docReadyEvent.clearListeners();
7885 docReadyEvent.addListener(fn, scope, options);
7889 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
7890 * @param {Function} fn The method the event invokes
7891 * @param {Object} scope An object that becomes the scope of the handler
7892 * @param {boolean} options
7894 onWindowResize : function(fn, scope, options)
7897 resizeEvent = new Roo.util.Event();
7898 resizeTask = new Roo.util.DelayedTask(function(){
7899 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7901 E.on(window, "resize", function()
7904 resizeTask.delay(50);
7906 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7910 resizeEvent.addListener(fn, scope, options);
7914 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
7915 * @param {Function} fn The method the event invokes
7916 * @param {Object} scope An object that becomes the scope of the handler
7917 * @param {boolean} options
7919 onTextResize : function(fn, scope, options){
7921 textEvent = new Roo.util.Event();
7922 var textEl = new Roo.Element(document.createElement('div'));
7923 textEl.dom.className = 'x-text-resize';
7924 textEl.dom.innerHTML = 'X';
7925 textEl.appendTo(document.body);
7926 textSize = textEl.dom.offsetHeight;
7927 setInterval(function(){
7928 if(textEl.dom.offsetHeight != textSize){
7929 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
7931 }, this.textResizeInterval);
7933 textEvent.addListener(fn, scope, options);
7937 * Removes the passed window resize listener.
7938 * @param {Function} fn The method the event invokes
7939 * @param {Object} scope The scope of handler
7941 removeResizeListener : function(fn, scope){
7943 resizeEvent.removeListener(fn, scope);
7948 fireResize : function(){
7950 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7954 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
7958 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
7960 textResizeInterval : 50
7965 * @scopeAlias pub=Roo.EventManager
7969 * Appends an event handler to an element (shorthand for addListener)
7970 * @param {String/HTMLElement} element The html element or id to assign the
7971 * @param {String} eventName The type of event to listen for
7972 * @param {Function} handler The method the event invokes
7973 * @param {Object} scope (optional) The scope in which to execute the handler
7974 * function. The handler function's "this" context.
7975 * @param {Object} options (optional) An object containing handler configuration
7976 * properties. This may contain any of the following properties:<ul>
7977 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7978 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7979 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7980 * <li>preventDefault {Boolean} True to prevent the default action</li>
7981 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7982 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7983 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7984 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7985 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7986 * by the specified number of milliseconds. If the event fires again within that time, the original
7987 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7990 * <b>Combining Options</b><br>
7991 * Using the options argument, it is possible to combine different types of listeners:<br>
7993 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7995 el.on('click', this.onClick, this, {
8002 * <b>Attaching multiple handlers in 1 call</b><br>
8003 * The method also allows for a single argument to be passed which is a config object containing properties
8004 * which specify multiple handlers.
8014 fn: this.onMouseOver
8023 * Or a shorthand syntax:<br>
8026 'click' : this.onClick,
8027 'mouseover' : this.onMouseOver,
8028 'mouseout' : this.onMouseOut
8032 pub.on = pub.addListener;
8033 pub.un = pub.removeListener;
8035 pub.stoppedMouseDownEvent = new Roo.util.Event();
8039 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
8040 * @param {Function} fn The method the event invokes
8041 * @param {Object} scope An object that becomes the scope of the handler
8042 * @param {boolean} override If true, the obj passed in becomes
8043 * the execution scope of the listener
8047 Roo.onReady = Roo.EventManager.onDocumentReady;
8049 Roo.onReady(function(){
8050 var bd = Roo.get(document.body);
8055 : Roo.isIE11 ? "roo-ie11"
8056 : Roo.isEdge ? "roo-edge"
8057 : Roo.isGecko ? "roo-gecko"
8058 : Roo.isOpera ? "roo-opera"
8059 : Roo.isSafari ? "roo-safari" : ""];
8062 cls.push("roo-mac");
8065 cls.push("roo-linux");
8068 cls.push("roo-ios");
8071 cls.push("roo-touch");
8073 if(Roo.isBorderBox){
8074 cls.push('roo-border-box');
8076 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
8077 var p = bd.dom.parentNode;
8079 p.className += ' roo-strict';
8082 bd.addClass(cls.join(' '));
8086 * @class Roo.EventObject
8087 * EventObject exposes the Yahoo! UI Event functionality directly on the object
8088 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
8091 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
8093 var target = e.getTarget();
8096 var myDiv = Roo.get("myDiv");
8097 myDiv.on("click", handleClick);
8099 Roo.EventManager.on("myDiv", 'click', handleClick);
8100 Roo.EventManager.addListener("myDiv", 'click', handleClick);
8104 Roo.EventObject = function(){
8106 var E = Roo.lib.Event;
8108 // safari keypress events for special keys return bad keycodes
8111 63235 : 39, // right
8114 63276 : 33, // page up
8115 63277 : 34, // page down
8116 63272 : 46, // delete
8121 // normalize button clicks
8122 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
8123 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
8125 Roo.EventObjectImpl = function(e){
8127 this.setEvent(e.browserEvent || e);
8130 Roo.EventObjectImpl.prototype = {
8132 * Used to fix doc tools.
8133 * @scope Roo.EventObject.prototype
8139 /** The normal browser event */
8140 browserEvent : null,
8141 /** The button pressed in a mouse event */
8143 /** True if the shift key was down during the event */
8145 /** True if the control key was down during the event */
8147 /** True if the alt key was down during the event */
8206 setEvent : function(e){
8207 if(e == this || (e && e.browserEvent)){ // already wrapped
8210 this.browserEvent = e;
8212 // normalize buttons
8213 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
8214 if(e.type == 'click' && this.button == -1){
8218 this.shiftKey = e.shiftKey;
8219 // mac metaKey behaves like ctrlKey
8220 this.ctrlKey = e.ctrlKey || e.metaKey;
8221 this.altKey = e.altKey;
8222 // in getKey these will be normalized for the mac
8223 this.keyCode = e.keyCode;
8224 // keyup warnings on firefox.
8225 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
8226 // cache the target for the delayed and or buffered events
8227 this.target = E.getTarget(e);
8229 this.xy = E.getXY(e);
8232 this.shiftKey = false;
8233 this.ctrlKey = false;
8234 this.altKey = false;
8244 * Stop the event (preventDefault and stopPropagation)
8246 stopEvent : function(){
8247 if(this.browserEvent){
8248 if(this.browserEvent.type == 'mousedown'){
8249 Roo.EventManager.stoppedMouseDownEvent.fire(this);
8251 E.stopEvent(this.browserEvent);
8256 * Prevents the browsers default handling of the event.
8258 preventDefault : function(){
8259 if(this.browserEvent){
8260 E.preventDefault(this.browserEvent);
8265 isNavKeyPress : function(){
8266 var k = this.keyCode;
8267 k = Roo.isSafari ? (safariKeys[k] || k) : k;
8268 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
8271 isSpecialKey : function(){
8272 var k = this.keyCode;
8273 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
8274 (k == 16) || (k == 17) ||
8275 (k >= 18 && k <= 20) ||
8276 (k >= 33 && k <= 35) ||
8277 (k >= 36 && k <= 39) ||
8278 (k >= 44 && k <= 45);
8281 * Cancels bubbling of the event.
8283 stopPropagation : function(){
8284 if(this.browserEvent){
8285 if(this.type == 'mousedown'){
8286 Roo.EventManager.stoppedMouseDownEvent.fire(this);
8288 E.stopPropagation(this.browserEvent);
8293 * Gets the key code for the event.
8296 getCharCode : function(){
8297 return this.charCode || this.keyCode;
8301 * Returns a normalized keyCode for the event.
8302 * @return {Number} The key code
8304 getKey : function(){
8305 var k = this.keyCode || this.charCode;
8306 return Roo.isSafari ? (safariKeys[k] || k) : k;
8310 * Gets the x coordinate of the event.
8313 getPageX : function(){
8318 * Gets the y coordinate of the event.
8321 getPageY : function(){
8326 * Gets the time of the event.
8329 getTime : function(){
8330 if(this.browserEvent){
8331 return E.getTime(this.browserEvent);
8337 * Gets the page coordinates of the event.
8338 * @return {Array} The xy values like [x, y]
8345 * Gets the target for the event.
8346 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
8347 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8348 search as a number or element (defaults to 10 || document.body)
8349 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8350 * @return {HTMLelement}
8352 getTarget : function(selector, maxDepth, returnEl){
8353 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
8356 * Gets the related target.
8357 * @return {HTMLElement}
8359 getRelatedTarget : function(){
8360 if(this.browserEvent){
8361 return E.getRelatedTarget(this.browserEvent);
8367 * Normalizes mouse wheel delta across browsers
8368 * @return {Number} The delta
8370 getWheelDelta : function(){
8371 var e = this.browserEvent;
8373 if(e.wheelDelta){ /* IE/Opera. */
8374 delta = e.wheelDelta/120;
8375 }else if(e.detail){ /* Mozilla case. */
8376 delta = -e.detail/3;
8382 * Returns true if the control, meta, shift or alt key was pressed during this event.
8385 hasModifier : function(){
8386 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
8390 * Returns true if the target of this event equals el or is a child of el
8391 * @param {String/HTMLElement/Element} el
8392 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
8395 within : function(el, related){
8396 var t = this[related ? "getRelatedTarget" : "getTarget"]();
8397 return t && Roo.fly(el).contains(t);
8400 getPoint : function(){
8401 return new Roo.lib.Point(this.xy[0], this.xy[1]);
8405 return new Roo.EventObjectImpl();
8410 * Ext JS Library 1.1.1
8411 * Copyright(c) 2006-2007, Ext JS, LLC.
8413 * Originally Released Under LGPL - original licence link has changed is not relivant.
8416 * <script type="text/javascript">
8420 // was in Composite Element!??!?!
8423 var D = Roo.lib.Dom;
8424 var E = Roo.lib.Event;
8425 var A = Roo.lib.Anim;
8427 // local style camelizing for speed
8429 var camelRe = /(-[a-z])/gi;
8430 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
8431 var view = document.defaultView;
8434 * @class Roo.Element
8435 * Represents an Element in the DOM.<br><br>
8438 var el = Roo.get("my-div");
8441 var el = getEl("my-div");
8443 // or with a DOM element
8444 var el = Roo.get(myDivElement);
8446 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
8447 * each call instead of constructing a new one.<br><br>
8448 * <b>Animations</b><br />
8449 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
8450 * should either be a boolean (true) or an object literal with animation options. The animation options are:
8452 Option Default Description
8453 --------- -------- ---------------------------------------------
8454 duration .35 The duration of the animation in seconds
8455 easing easeOut The YUI easing method
8456 callback none A function to execute when the anim completes
8457 scope this The scope (this) of the callback function
8459 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
8460 * manipulate the animation. Here's an example:
8462 var el = Roo.get("my-div");
8467 // default animation
8468 el.setWidth(100, true);
8470 // animation with some options set
8477 // using the "anim" property to get the Anim object
8483 el.setWidth(100, opt);
8485 if(opt.anim.isAnimated()){
8489 * <b> Composite (Collections of) Elements</b><br />
8490 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
8491 * @constructor Create a new Element directly.
8492 * @param {String/HTMLElement} element
8493 * @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).
8495 Roo.Element = function(element, forceNew)
8497 var dom = typeof element == "string" ?
8498 document.getElementById(element) : element;
8500 this.listeners = {};
8502 if(!dom){ // invalid id/element
8506 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
8507 return Roo.Element.cache[id];
8517 * The DOM element ID
8520 this.id = id || Roo.id(dom);
8522 return this; // assumed for cctor?
8525 var El = Roo.Element;
8529 * The element's default display mode (defaults to "")
8532 originalDisplay : "",
8535 // note this is overridden in BS version..
8538 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
8544 * Sets the element's visibility mode. When setVisible() is called it
8545 * will use this to determine whether to set the visibility or the display property.
8546 * @param visMode Element.VISIBILITY or Element.DISPLAY
8547 * @return {Roo.Element} this
8549 setVisibilityMode : function(visMode){
8550 this.visibilityMode = visMode;
8554 * Convenience method for setVisibilityMode(Element.DISPLAY)
8555 * @param {String} display (optional) What to set display to when visible
8556 * @return {Roo.Element} this
8558 enableDisplayMode : function(display){
8559 this.setVisibilityMode(El.DISPLAY);
8560 if(typeof display != "undefined") { this.originalDisplay = display; }
8565 * 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)
8566 * @param {String} selector The simple selector to test
8567 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8568 search as a number or element (defaults to 10 || document.body)
8569 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8570 * @return {HTMLElement} The matching DOM node (or null if no match was found)
8572 findParent : function(simpleSelector, maxDepth, returnEl){
8573 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
8574 maxDepth = maxDepth || 50;
8575 if(typeof maxDepth != "number"){
8576 stopEl = Roo.getDom(maxDepth);
8579 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
8580 if(dq.is(p, simpleSelector)){
8581 return returnEl ? Roo.get(p) : p;
8591 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
8592 * @param {String} selector The simple selector to test
8593 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8594 search as a number or element (defaults to 10 || document.body)
8595 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8596 * @return {HTMLElement} The matching DOM node (or null if no match was found)
8598 findParentNode : function(simpleSelector, maxDepth, returnEl){
8599 var p = Roo.fly(this.dom.parentNode, '_internal');
8600 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
8604 * Looks at the scrollable parent element
8606 findScrollableParent : function()
8608 var overflowRegex = /(auto|scroll)/;
8610 if(this.getStyle('position') === 'fixed'){
8611 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8614 var excludeStaticParent = this.getStyle('position') === "absolute";
8616 for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
8618 if (excludeStaticParent && parent.getStyle('position') === "static") {
8622 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
8626 if(parent.dom.nodeName.toLowerCase() == 'body'){
8627 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8631 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8635 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
8636 * This is a shortcut for findParentNode() that always returns an Roo.Element.
8637 * @param {String} selector The simple selector to test
8638 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8639 search as a number or element (defaults to 10 || document.body)
8640 * @return {Roo.Element} The matching DOM node (or null if no match was found)
8642 up : function(simpleSelector, maxDepth){
8643 return this.findParentNode(simpleSelector, maxDepth, true);
8649 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
8650 * @param {String} selector The simple selector to test
8651 * @return {Boolean} True if this element matches the selector, else false
8653 is : function(simpleSelector){
8654 return Roo.DomQuery.is(this.dom, simpleSelector);
8658 * Perform animation on this element.
8659 * @param {Object} args The YUI animation control args
8660 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
8661 * @param {Function} onComplete (optional) Function to call when animation completes
8662 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
8663 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
8664 * @return {Roo.Element} this
8666 animate : function(args, duration, onComplete, easing, animType){
8667 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
8672 * @private Internal animation call
8674 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
8675 animType = animType || 'run';
8677 var anim = Roo.lib.Anim[animType](
8679 (opt.duration || defaultDur) || .35,
8680 (opt.easing || defaultEase) || 'easeOut',
8682 Roo.callback(cb, this);
8683 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
8691 // private legacy anim prep
8692 preanim : function(a, i){
8693 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
8697 * Removes worthless text nodes
8698 * @param {Boolean} forceReclean (optional) By default the element
8699 * keeps track if it has been cleaned already so
8700 * you can call this over and over. However, if you update the element and
8701 * need to force a reclean, you can pass true.
8703 clean : function(forceReclean){
8704 if(this.isCleaned && forceReclean !== true){
8708 var d = this.dom, n = d.firstChild, ni = -1;
8710 var nx = n.nextSibling;
8711 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
8718 this.isCleaned = true;
8723 calcOffsetsTo : function(el){
8726 var restorePos = false;
8727 if(el.getStyle('position') == 'static'){
8728 el.position('relative');
8733 while(op && op != d && op.tagName != 'HTML'){
8736 op = op.offsetParent;
8739 el.position('static');
8745 * Scrolls this element into view within the passed container.
8746 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
8747 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
8748 * @return {Roo.Element} this
8750 scrollIntoView : function(container, hscroll){
8751 var c = Roo.getDom(container) || document.body;
8754 var o = this.calcOffsetsTo(c),
8757 b = t+el.offsetHeight,
8758 r = l+el.offsetWidth;
8760 var ch = c.clientHeight;
8761 var ct = parseInt(c.scrollTop, 10);
8762 var cl = parseInt(c.scrollLeft, 10);
8764 var cr = cl + c.clientWidth;
8772 if(hscroll !== false){
8776 c.scrollLeft = r-c.clientWidth;
8783 scrollChildIntoView : function(child, hscroll){
8784 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
8788 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
8789 * the new height may not be available immediately.
8790 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
8791 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
8792 * @param {Function} onComplete (optional) Function to call when animation completes
8793 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
8794 * @return {Roo.Element} this
8796 autoHeight : function(animate, duration, onComplete, easing){
8797 var oldHeight = this.getHeight();
8799 this.setHeight(1); // force clipping
8800 setTimeout(function(){
8801 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
8803 this.setHeight(height);
8805 if(typeof onComplete == "function"){
8809 this.setHeight(oldHeight); // restore original height
8810 this.setHeight(height, animate, duration, function(){
8812 if(typeof onComplete == "function") { onComplete(); }
8813 }.createDelegate(this), easing);
8815 }.createDelegate(this), 0);
8820 * Returns true if this element is an ancestor of the passed element
8821 * @param {HTMLElement/String} el The element to check
8822 * @return {Boolean} True if this element is an ancestor of el, else false
8824 contains : function(el){
8825 if(!el){return false;}
8826 return D.isAncestor(this.dom, el.dom ? el.dom : el);
8830 * Checks whether the element is currently visible using both visibility and display properties.
8831 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
8832 * @return {Boolean} True if the element is currently visible, else false
8834 isVisible : function(deep) {
8835 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
8836 if(deep !== true || !vis){
8839 var p = this.dom.parentNode;
8840 while(p && p.tagName.toLowerCase() != "body"){
8841 if(!Roo.fly(p, '_isVisible').isVisible()){
8850 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
8851 * @param {String} selector The CSS selector
8852 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
8853 * @return {CompositeElement/CompositeElementLite} The composite element
8855 select : function(selector, unique){
8856 return El.select(selector, unique, this.dom);
8860 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
8861 * @param {String} selector The CSS selector
8862 * @return {Array} An array of the matched nodes
8864 query : function(selector, unique){
8865 return Roo.DomQuery.select(selector, this.dom);
8869 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
8870 * @param {String} selector The CSS selector
8871 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8872 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8874 child : function(selector, returnDom){
8875 var n = Roo.DomQuery.selectNode(selector, this.dom);
8876 return returnDom ? n : Roo.get(n);
8880 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
8881 * @param {String} selector The CSS selector
8882 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8883 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8885 down : function(selector, returnDom){
8886 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
8887 return returnDom ? n : Roo.get(n);
8891 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
8892 * @param {String} group The group the DD object is member of
8893 * @param {Object} config The DD config object
8894 * @param {Object} overrides An object containing methods to override/implement on the DD object
8895 * @return {Roo.dd.DD} The DD object
8897 initDD : function(group, config, overrides){
8898 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
8899 return Roo.apply(dd, overrides);
8903 * Initializes a {@link Roo.dd.DDProxy} object for this element.
8904 * @param {String} group The group the DDProxy object is member of
8905 * @param {Object} config The DDProxy config object
8906 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
8907 * @return {Roo.dd.DDProxy} The DDProxy object
8909 initDDProxy : function(group, config, overrides){
8910 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
8911 return Roo.apply(dd, overrides);
8915 * Initializes a {@link Roo.dd.DDTarget} object for this element.
8916 * @param {String} group The group the DDTarget object is member of
8917 * @param {Object} config The DDTarget config object
8918 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
8919 * @return {Roo.dd.DDTarget} The DDTarget object
8921 initDDTarget : function(group, config, overrides){
8922 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
8923 return Roo.apply(dd, overrides);
8927 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
8928 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
8929 * @param {Boolean} visible Whether the element is visible
8930 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8931 * @return {Roo.Element} this
8933 setVisible : function(visible, animate){
8935 if(this.visibilityMode == El.DISPLAY){
8936 this.setDisplayed(visible);
8939 this.dom.style.visibility = visible ? "visible" : "hidden";
8942 // closure for composites
8944 var visMode = this.visibilityMode;
8946 this.setOpacity(.01);
8947 this.setVisible(true);
8949 this.anim({opacity: { to: (visible?1:0) }},
8950 this.preanim(arguments, 1),
8951 null, .35, 'easeIn', function(){
8953 if(visMode == El.DISPLAY){
8954 dom.style.display = "none";
8956 dom.style.visibility = "hidden";
8958 Roo.get(dom).setOpacity(1);
8966 * Returns true if display is not "none"
8969 isDisplayed : function() {
8970 return this.getStyle("display") != "none";
8974 * Toggles the element's visibility or display, depending on visibility mode.
8975 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8976 * @return {Roo.Element} this
8978 toggle : function(animate){
8979 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
8984 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
8985 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
8986 * @return {Roo.Element} this
8988 setDisplayed : function(value) {
8989 if(typeof value == "boolean"){
8990 value = value ? this.originalDisplay : "none";
8992 this.setStyle("display", value);
8997 * Tries to focus the element. Any exceptions are caught and ignored.
8998 * @return {Roo.Element} this
9000 focus : function() {
9008 * Tries to blur the element. Any exceptions are caught and ignored.
9009 * @return {Roo.Element} this
9019 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
9020 * @param {String/Array} className The CSS class to add, or an array of classes
9021 * @return {Roo.Element} this
9023 addClass : function(className){
9024 if(className instanceof Array){
9025 for(var i = 0, len = className.length; i < len; i++) {
9026 this.addClass(className[i]);
9029 if(className && !this.hasClass(className)){
9030 if (this.dom instanceof SVGElement) {
9031 this.dom.className.baseVal =this.dom.className.baseVal + " " + className;
9033 this.dom.className = this.dom.className + " " + className;
9041 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
9042 * @param {String/Array} className The CSS class to add, or an array of classes
9043 * @return {Roo.Element} this
9045 radioClass : function(className){
9046 var siblings = this.dom.parentNode.childNodes;
9047 for(var i = 0; i < siblings.length; i++) {
9048 var s = siblings[i];
9049 if(s.nodeType == 1){
9050 Roo.get(s).removeClass(className);
9053 this.addClass(className);
9058 * Removes one or more CSS classes from the element.
9059 * @param {String/Array} className The CSS class to remove, or an array of classes
9060 * @return {Roo.Element} this
9062 removeClass : function(className){
9064 var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
9065 if(!className || !cn){
9068 if(className instanceof Array){
9069 for(var i = 0, len = className.length; i < len; i++) {
9070 this.removeClass(className[i]);
9073 if(this.hasClass(className)){
9074 var re = this.classReCache[className];
9076 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
9077 this.classReCache[className] = re;
9079 if (this.dom instanceof SVGElement) {
9080 this.dom.className.baseVal = cn.replace(re, " ");
9082 this.dom.className = cn.replace(re, " ");
9093 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
9094 * @param {String} className The CSS class to toggle
9095 * @return {Roo.Element} this
9097 toggleClass : function(className){
9098 if(this.hasClass(className)){
9099 this.removeClass(className);
9101 this.addClass(className);
9107 * Checks if the specified CSS class exists on this element's DOM node.
9108 * @param {String} className The CSS class to check for
9109 * @return {Boolean} True if the class exists, else false
9111 hasClass : function(className){
9112 if (this.dom instanceof SVGElement) {
9113 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1;
9115 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
9119 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
9120 * @param {String} oldClassName The CSS class to replace
9121 * @param {String} newClassName The replacement CSS class
9122 * @return {Roo.Element} this
9124 replaceClass : function(oldClassName, newClassName){
9125 this.removeClass(oldClassName);
9126 this.addClass(newClassName);
9131 * Returns an object with properties matching the styles requested.
9132 * For example, el.getStyles('color', 'font-size', 'width') might return
9133 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
9134 * @param {String} style1 A style name
9135 * @param {String} style2 A style name
9136 * @param {String} etc.
9137 * @return {Object} The style object
9139 getStyles : function(){
9140 var a = arguments, len = a.length, r = {};
9141 for(var i = 0; i < len; i++){
9142 r[a[i]] = this.getStyle(a[i]);
9148 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
9149 * @param {String} property The style property whose value is returned.
9150 * @return {String} The current value of the style property for this element.
9152 getStyle : function(){
9153 return view && view.getComputedStyle ?
9155 var el = this.dom, v, cs, camel;
9156 if(prop == 'float'){
9159 if(el.style && (v = el.style[prop])){
9162 if(cs = view.getComputedStyle(el, "")){
9163 if(!(camel = propCache[prop])){
9164 camel = propCache[prop] = prop.replace(camelRe, camelFn);
9171 var el = this.dom, v, cs, camel;
9172 if(prop == 'opacity'){
9173 if(typeof el.style.filter == 'string'){
9174 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
9176 var fv = parseFloat(m[1]);
9178 return fv ? fv / 100 : 0;
9183 }else if(prop == 'float'){
9184 prop = "styleFloat";
9186 if(!(camel = propCache[prop])){
9187 camel = propCache[prop] = prop.replace(camelRe, camelFn);
9189 if(v = el.style[camel]){
9192 if(cs = el.currentStyle){
9200 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
9201 * @param {String/Object} property The style property to be set, or an object of multiple styles.
9202 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
9203 * @return {Roo.Element} this
9205 setStyle : function(prop, value){
9206 if(typeof prop == "string"){
9208 if (prop == 'float') {
9209 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
9214 if(!(camel = propCache[prop])){
9215 camel = propCache[prop] = prop.replace(camelRe, camelFn);
9218 if(camel == 'opacity') {
9219 this.setOpacity(value);
9221 this.dom.style[camel] = value;
9224 for(var style in prop){
9225 if(typeof prop[style] != "function"){
9226 this.setStyle(style, prop[style]);
9234 * More flexible version of {@link #setStyle} for setting style properties.
9235 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
9236 * a function which returns such a specification.
9237 * @return {Roo.Element} this
9239 applyStyles : function(style){
9240 Roo.DomHelper.applyStyles(this.dom, style);
9245 * 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).
9246 * @return {Number} The X position of the element
9249 return D.getX(this.dom);
9253 * 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).
9254 * @return {Number} The Y position of the element
9257 return D.getY(this.dom);
9261 * 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).
9262 * @return {Array} The XY position of the element
9265 return D.getXY(this.dom);
9269 * 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).
9270 * @param {Number} The X position of the element
9271 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9272 * @return {Roo.Element} this
9274 setX : function(x, animate){
9276 D.setX(this.dom, x);
9278 this.setXY([x, this.getY()], this.preanim(arguments, 1));
9284 * 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).
9285 * @param {Number} The Y position of the element
9286 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9287 * @return {Roo.Element} this
9289 setY : function(y, animate){
9291 D.setY(this.dom, y);
9293 this.setXY([this.getX(), y], this.preanim(arguments, 1));
9299 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
9300 * @param {String} left The left CSS property value
9301 * @return {Roo.Element} this
9303 setLeft : function(left){
9304 this.setStyle("left", this.addUnits(left));
9309 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
9310 * @param {String} top The top CSS property value
9311 * @return {Roo.Element} this
9313 setTop : function(top){
9314 this.setStyle("top", this.addUnits(top));
9319 * Sets the element's CSS right style.
9320 * @param {String} right The right CSS property value
9321 * @return {Roo.Element} this
9323 setRight : function(right){
9324 this.setStyle("right", this.addUnits(right));
9329 * Sets the element's CSS bottom style.
9330 * @param {String} bottom The bottom CSS property value
9331 * @return {Roo.Element} this
9333 setBottom : function(bottom){
9334 this.setStyle("bottom", this.addUnits(bottom));
9339 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9340 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9341 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
9342 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9343 * @return {Roo.Element} this
9345 setXY : function(pos, animate){
9347 D.setXY(this.dom, pos);
9349 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
9355 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9356 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9357 * @param {Number} x X value for new position (coordinates are page-based)
9358 * @param {Number} y Y value for new position (coordinates are page-based)
9359 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9360 * @return {Roo.Element} this
9362 setLocation : function(x, y, animate){
9363 this.setXY([x, y], this.preanim(arguments, 2));
9368 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9369 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9370 * @param {Number} x X value for new position (coordinates are page-based)
9371 * @param {Number} y Y value for new position (coordinates are page-based)
9372 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9373 * @return {Roo.Element} this
9375 moveTo : function(x, y, animate){
9376 this.setXY([x, y], this.preanim(arguments, 2));
9381 * Returns the region of the given element.
9382 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
9383 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
9385 getRegion : function(){
9386 return D.getRegion(this.dom);
9390 * Returns the offset height of the element
9391 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
9392 * @return {Number} The element's height
9394 getHeight : function(contentHeight){
9395 var h = this.dom.offsetHeight || 0;
9396 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
9400 * Returns the offset width of the element
9401 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
9402 * @return {Number} The element's width
9404 getWidth : function(contentWidth){
9405 var w = this.dom.offsetWidth || 0;
9406 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
9410 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
9411 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
9412 * if a height has not been set using CSS.
9415 getComputedHeight : function(){
9416 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
9418 h = parseInt(this.getStyle('height'), 10) || 0;
9419 if(!this.isBorderBox()){
9420 h += this.getFrameWidth('tb');
9427 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
9428 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
9429 * if a width has not been set using CSS.
9432 getComputedWidth : function(){
9433 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
9435 w = parseInt(this.getStyle('width'), 10) || 0;
9436 if(!this.isBorderBox()){
9437 w += this.getFrameWidth('lr');
9444 * Returns the size of the element.
9445 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
9446 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
9448 getSize : function(contentSize){
9449 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
9453 * Returns the width and height of the viewport.
9454 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
9456 getViewSize : function(){
9457 var d = this.dom, doc = document, aw = 0, ah = 0;
9458 if(d == doc || d == doc.body){
9459 return {width : D.getViewWidth(), height: D.getViewHeight()};
9462 width : d.clientWidth,
9463 height: d.clientHeight
9469 * Returns the value of the "value" attribute
9470 * @param {Boolean} asNumber true to parse the value as a number
9471 * @return {String/Number}
9473 getValue : function(asNumber){
9474 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
9478 adjustWidth : function(width){
9479 if(typeof width == "number"){
9480 if(this.autoBoxAdjust && !this.isBorderBox()){
9481 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9491 adjustHeight : function(height){
9492 if(typeof height == "number"){
9493 if(this.autoBoxAdjust && !this.isBorderBox()){
9494 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9504 * Set the width of the element
9505 * @param {Number} width The new width
9506 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9507 * @return {Roo.Element} this
9509 setWidth : function(width, animate){
9510 width = this.adjustWidth(width);
9512 this.dom.style.width = this.addUnits(width);
9514 this.anim({width: {to: width}}, this.preanim(arguments, 1));
9520 * Set the height of the element
9521 * @param {Number} height The new height
9522 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9523 * @return {Roo.Element} this
9525 setHeight : function(height, animate){
9526 height = this.adjustHeight(height);
9528 this.dom.style.height = this.addUnits(height);
9530 this.anim({height: {to: height}}, this.preanim(arguments, 1));
9536 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
9537 * @param {Number} width The new width
9538 * @param {Number} height The new height
9539 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9540 * @return {Roo.Element} this
9542 setSize : function(width, height, animate){
9543 if(typeof width == "object"){ // in case of object from getSize()
9544 height = width.height; width = width.width;
9546 width = this.adjustWidth(width); height = this.adjustHeight(height);
9548 this.dom.style.width = this.addUnits(width);
9549 this.dom.style.height = this.addUnits(height);
9551 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
9557 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
9558 * @param {Number} x X value for new position (coordinates are page-based)
9559 * @param {Number} y Y value for new position (coordinates are page-based)
9560 * @param {Number} width The new width
9561 * @param {Number} height The new height
9562 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9563 * @return {Roo.Element} this
9565 setBounds : function(x, y, width, height, animate){
9567 this.setSize(width, height);
9568 this.setLocation(x, y);
9570 width = this.adjustWidth(width); height = this.adjustHeight(height);
9571 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
9572 this.preanim(arguments, 4), 'motion');
9578 * 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.
9579 * @param {Roo.lib.Region} region The region to fill
9580 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9581 * @return {Roo.Element} this
9583 setRegion : function(region, animate){
9584 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
9589 * Appends an event handler
9591 * @param {String} eventName The type of event to append
9592 * @param {Function} fn The method the event invokes
9593 * @param {Object} scope (optional) The scope (this object) of the fn
9594 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9596 addListener : function(eventName, fn, scope, options)
9598 if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
9599 this.addListener('touchstart', this.onTapHandler, this);
9602 // we need to handle a special case where dom element is a svg element.
9603 // in this case we do not actua
9608 if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
9609 if (typeof(this.listeners[eventName]) == 'undefined') {
9610 this.listeners[eventName] = new Roo.util.Event(this, eventName);
9612 this.listeners[eventName].addListener(fn, scope, options);
9617 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
9622 onTapHandler : function(event)
9624 if(!this.tapedTwice) {
9625 this.tapedTwice = true;
9627 setTimeout( function() {
9628 s.tapedTwice = false;
9632 event.preventDefault();
9633 var revent = new MouseEvent('dblclick', {
9639 this.dom.dispatchEvent(revent);
9640 //action on double tap goes below
9645 * Removes an event handler from this element
9646 * @param {String} eventName the type of event to remove
9647 * @param {Function} fn the method the event invokes
9648 * @param {Function} scope (needed for svg fake listeners)
9649 * @return {Roo.Element} this
9651 removeListener : function(eventName, fn, scope){
9652 Roo.EventManager.removeListener(this.dom, eventName, fn);
9653 if (typeof(this.listeners) == 'undefined' || typeof(this.listeners[eventName]) == 'undefined') {
9656 this.listeners[eventName].removeListener(fn, scope);
9661 * Removes all previous added listeners from this element
9662 * @return {Roo.Element} this
9664 removeAllListeners : function(){
9665 E.purgeElement(this.dom);
9666 this.listeners = {};
9670 relayEvent : function(eventName, observable){
9671 this.on(eventName, function(e){
9672 observable.fireEvent(eventName, e);
9678 * Set the opacity of the element
9679 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
9680 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9681 * @return {Roo.Element} this
9683 setOpacity : function(opacity, animate){
9685 var s = this.dom.style;
9688 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
9689 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
9691 s.opacity = opacity;
9694 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
9700 * Gets the left X coordinate
9701 * @param {Boolean} local True to get the local css position instead of page coordinate
9704 getLeft : function(local){
9708 return parseInt(this.getStyle("left"), 10) || 0;
9713 * Gets the right X coordinate of the element (element X position + element width)
9714 * @param {Boolean} local True to get the local css position instead of page coordinate
9717 getRight : function(local){
9719 return this.getX() + this.getWidth();
9721 return (this.getLeft(true) + this.getWidth()) || 0;
9726 * Gets the top Y coordinate
9727 * @param {Boolean} local True to get the local css position instead of page coordinate
9730 getTop : function(local) {
9734 return parseInt(this.getStyle("top"), 10) || 0;
9739 * Gets the bottom Y coordinate of the element (element Y position + element height)
9740 * @param {Boolean} local True to get the local css position instead of page coordinate
9743 getBottom : function(local){
9745 return this.getY() + this.getHeight();
9747 return (this.getTop(true) + this.getHeight()) || 0;
9752 * Initializes positioning on this element. If a desired position is not passed, it will make the
9753 * the element positioned relative IF it is not already positioned.
9754 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
9755 * @param {Number} zIndex (optional) The zIndex to apply
9756 * @param {Number} x (optional) Set the page X position
9757 * @param {Number} y (optional) Set the page Y position
9759 position : function(pos, zIndex, x, y){
9761 if(this.getStyle('position') == 'static'){
9762 this.setStyle('position', 'relative');
9765 this.setStyle("position", pos);
9768 this.setStyle("z-index", zIndex);
9770 if(x !== undefined && y !== undefined){
9772 }else if(x !== undefined){
9774 }else if(y !== undefined){
9780 * Clear positioning back to the default when the document was loaded
9781 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
9782 * @return {Roo.Element} this
9784 clearPositioning : function(value){
9792 "position" : "static"
9798 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
9799 * snapshot before performing an update and then restoring the element.
9802 getPositioning : function(){
9803 var l = this.getStyle("left");
9804 var t = this.getStyle("top");
9806 "position" : this.getStyle("position"),
9808 "right" : l ? "" : this.getStyle("right"),
9810 "bottom" : t ? "" : this.getStyle("bottom"),
9811 "z-index" : this.getStyle("z-index")
9816 * Gets the width of the border(s) for the specified side(s)
9817 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9818 * passing lr would get the border (l)eft width + the border (r)ight width.
9819 * @return {Number} The width of the sides passed added together
9821 getBorderWidth : function(side){
9822 return this.addStyles(side, El.borders);
9826 * Gets the width of the padding(s) for the specified side(s)
9827 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9828 * passing lr would get the padding (l)eft + the padding (r)ight.
9829 * @return {Number} The padding of the sides passed added together
9831 getPadding : function(side){
9832 return this.addStyles(side, El.paddings);
9836 * Set positioning with an object returned by getPositioning().
9837 * @param {Object} posCfg
9838 * @return {Roo.Element} this
9840 setPositioning : function(pc){
9841 this.applyStyles(pc);
9842 if(pc.right == "auto"){
9843 this.dom.style.right = "";
9845 if(pc.bottom == "auto"){
9846 this.dom.style.bottom = "";
9852 fixDisplay : function(){
9853 if(this.getStyle("display") == "none"){
9854 this.setStyle("visibility", "hidden");
9855 this.setStyle("display", this.originalDisplay); // first try reverting to default
9856 if(this.getStyle("display") == "none"){ // if that fails, default to block
9857 this.setStyle("display", "block");
9863 * Quick set left and top adding default units
9864 * @param {String} left The left CSS property value
9865 * @param {String} top The top CSS property value
9866 * @return {Roo.Element} this
9868 setLeftTop : function(left, top){
9869 this.dom.style.left = this.addUnits(left);
9870 this.dom.style.top = this.addUnits(top);
9875 * Move this element relative to its current position.
9876 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9877 * @param {Number} distance How far to move the element in pixels
9878 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9879 * @return {Roo.Element} this
9881 move : function(direction, distance, animate){
9882 var xy = this.getXY();
9883 direction = direction.toLowerCase();
9887 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
9891 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
9896 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
9901 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
9908 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
9909 * @return {Roo.Element} this
9912 if(!this.isClipped){
9913 this.isClipped = true;
9914 this.originalClip = {
9915 "o": this.getStyle("overflow"),
9916 "x": this.getStyle("overflow-x"),
9917 "y": this.getStyle("overflow-y")
9919 this.setStyle("overflow", "hidden");
9920 this.setStyle("overflow-x", "hidden");
9921 this.setStyle("overflow-y", "hidden");
9927 * Return clipping (overflow) to original clipping before clip() was called
9928 * @return {Roo.Element} this
9930 unclip : function(){
9932 this.isClipped = false;
9933 var o = this.originalClip;
9934 if(o.o){this.setStyle("overflow", o.o);}
9935 if(o.x){this.setStyle("overflow-x", o.x);}
9936 if(o.y){this.setStyle("overflow-y", o.y);}
9943 * Gets the x,y coordinates specified by the anchor position on the element.
9944 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
9945 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
9946 * {width: (target width), height: (target height)} (defaults to the element's current size)
9947 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
9948 * @return {Array} [x, y] An array containing the element's x and y coordinates
9950 getAnchorXY : function(anchor, local, s){
9951 //Passing a different size is useful for pre-calculating anchors,
9952 //especially for anchored animations that change the el size.
9954 var w, h, vp = false;
9957 if(d == document.body || d == document){
9959 w = D.getViewWidth(); h = D.getViewHeight();
9961 w = this.getWidth(); h = this.getHeight();
9964 w = s.width; h = s.height;
9966 var x = 0, y = 0, r = Math.round;
9967 switch((anchor || "tl").toLowerCase()){
10005 if(local === true){
10009 var sc = this.getScroll();
10010 return [x + sc.left, y + sc.top];
10012 //Add the element's offset xy
10013 var o = this.getXY();
10014 return [x+o[0], y+o[1]];
10018 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
10019 * supported position values.
10020 * @param {String/HTMLElement/Roo.Element} element The element to align to.
10021 * @param {String} position The position to align to.
10022 * @param {Array} offsets (optional) Offset the positioning by [x, y]
10023 * @return {Array} [x, y]
10025 getAlignToXY : function(el, p, o)
10030 throw "Element.alignTo with an element that doesn't exist";
10032 var c = false; //constrain to viewport
10033 var p1 = "", p2 = "";
10038 }else if(p == "?"){
10040 }else if(p.indexOf("-") == -1){
10043 p = p.toLowerCase();
10044 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
10046 throw "Element.alignTo with an invalid alignment " + p;
10048 p1 = m[1]; p2 = m[2]; c = !!m[3];
10050 //Subtract the aligned el's internal xy from the target's offset xy
10051 //plus custom offset to get the aligned el's new offset xy
10052 var a1 = this.getAnchorXY(p1, true);
10053 var a2 = el.getAnchorXY(p2, false);
10054 var x = a2[0] - a1[0] + o[0];
10055 var y = a2[1] - a1[1] + o[1];
10057 //constrain the aligned el to viewport if necessary
10058 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
10059 // 5px of margin for ie
10060 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
10062 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
10063 //perpendicular to the vp border, allow the aligned el to slide on that border,
10064 //otherwise swap the aligned el to the opposite border of the target.
10065 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
10066 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
10067 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t") );
10068 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
10070 var doc = document;
10071 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
10072 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
10074 if((x+w) > dw + scrollX){
10075 x = swapX ? r.left-w : dw+scrollX-w;
10078 x = swapX ? r.right : scrollX;
10080 if((y+h) > dh + scrollY){
10081 y = swapY ? r.top-h : dh+scrollY-h;
10084 y = swapY ? r.bottom : scrollY;
10091 getConstrainToXY : function(){
10092 var os = {top:0, left:0, bottom:0, right: 0};
10094 return function(el, local, offsets, proposedXY){
10096 offsets = offsets ? Roo.applyIf(offsets, os) : os;
10098 var vw, vh, vx = 0, vy = 0;
10099 if(el.dom == document.body || el.dom == document){
10100 vw = Roo.lib.Dom.getViewWidth();
10101 vh = Roo.lib.Dom.getViewHeight();
10103 vw = el.dom.clientWidth;
10104 vh = el.dom.clientHeight;
10106 var vxy = el.getXY();
10112 var s = el.getScroll();
10114 vx += offsets.left + s.left;
10115 vy += offsets.top + s.top;
10117 vw -= offsets.right;
10118 vh -= offsets.bottom;
10123 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
10124 var x = xy[0], y = xy[1];
10125 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
10127 // only move it if it needs it
10130 // first validate right/bottom
10139 // then make sure top/left isn't negative
10148 return moved ? [x, y] : false;
10153 adjustForConstraints : function(xy, parent, offsets){
10154 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
10158 * Aligns this element with another element relative to the specified anchor points. If the other element is the
10159 * document it aligns it to the viewport.
10160 * The position parameter is optional, and can be specified in any one of the following formats:
10162 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
10163 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
10164 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
10165 * deprecated in favor of the newer two anchor syntax below</i>.</li>
10166 * <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
10167 * element's anchor point, and the second value is used as the target's anchor point.</li>
10169 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
10170 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
10171 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
10172 * that specified in order to enforce the viewport constraints.
10173 * Following are all of the supported anchor positions:
10176 ----- -----------------------------
10177 tl The top left corner (default)
10178 t The center of the top edge
10179 tr The top right corner
10180 l The center of the left edge
10181 c In the center of the element
10182 r The center of the right edge
10183 bl The bottom left corner
10184 b The center of the bottom edge
10185 br The bottom right corner
10189 // align el to other-el using the default positioning ("tl-bl", non-constrained)
10190 el.alignTo("other-el");
10192 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
10193 el.alignTo("other-el", "tr?");
10195 // align the bottom right corner of el with the center left edge of other-el
10196 el.alignTo("other-el", "br-l?");
10198 // align the center of el with the bottom left corner of other-el and
10199 // adjust the x position by -6 pixels (and the y position by 0)
10200 el.alignTo("other-el", "c-bl", [-6, 0]);
10202 * @param {String/HTMLElement/Roo.Element} element The element to align to.
10203 * @param {String} position The position to align to.
10204 * @param {Array} offsets (optional) Offset the positioning by [x, y]
10205 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10206 * @return {Roo.Element} this
10208 alignTo : function(element, position, offsets, animate){
10209 var xy = this.getAlignToXY(element, position, offsets);
10210 this.setXY(xy, this.preanim(arguments, 3));
10215 * Anchors an element to another element and realigns it when the window is resized.
10216 * @param {String/HTMLElement/Roo.Element} element The element to align to.
10217 * @param {String} position The position to align to.
10218 * @param {Array} offsets (optional) Offset the positioning by [x, y]
10219 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
10220 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
10221 * is a number, it is used as the buffer delay (defaults to 50ms).
10222 * @param {Function} callback The function to call after the animation finishes
10223 * @return {Roo.Element} this
10225 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
10226 var action = function(){
10227 this.alignTo(el, alignment, offsets, animate);
10228 Roo.callback(callback, this);
10230 Roo.EventManager.onWindowResize(action, this);
10231 var tm = typeof monitorScroll;
10232 if(tm != 'undefined'){
10233 Roo.EventManager.on(window, 'scroll', action, this,
10234 {buffer: tm == 'number' ? monitorScroll : 50});
10236 action.call(this); // align immediately
10240 * Clears any opacity settings from this element. Required in some cases for IE.
10241 * @return {Roo.Element} this
10243 clearOpacity : function(){
10244 if (window.ActiveXObject) {
10245 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
10246 this.dom.style.filter = "";
10249 this.dom.style.opacity = "";
10250 this.dom.style["-moz-opacity"] = "";
10251 this.dom.style["-khtml-opacity"] = "";
10257 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
10258 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10259 * @return {Roo.Element} this
10261 hide : function(animate){
10262 this.setVisible(false, this.preanim(arguments, 0));
10267 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
10268 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10269 * @return {Roo.Element} this
10271 show : function(animate){
10272 this.setVisible(true, this.preanim(arguments, 0));
10277 * @private Test if size has a unit, otherwise appends the default
10279 addUnits : function(size){
10280 return Roo.Element.addUnits(size, this.defaultUnit);
10284 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
10285 * @return {Roo.Element} this
10287 beginMeasure : function(){
10289 if(el.offsetWidth || el.offsetHeight){
10290 return this; // offsets work already
10293 var p = this.dom, b = document.body; // start with this element
10294 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
10295 var pe = Roo.get(p);
10296 if(pe.getStyle('display') == 'none'){
10297 changed.push({el: p, visibility: pe.getStyle("visibility")});
10298 p.style.visibility = "hidden";
10299 p.style.display = "block";
10303 this._measureChanged = changed;
10309 * Restores displays to before beginMeasure was called
10310 * @return {Roo.Element} this
10312 endMeasure : function(){
10313 var changed = this._measureChanged;
10315 for(var i = 0, len = changed.length; i < len; i++) {
10316 var r = changed[i];
10317 r.el.style.visibility = r.visibility;
10318 r.el.style.display = "none";
10320 this._measureChanged = null;
10326 * Update the innerHTML of this element, optionally searching for and processing scripts
10327 * @param {String} html The new HTML
10328 * @param {Boolean} loadScripts (optional) true to look for and process scripts
10329 * @param {Function} callback For async script loading you can be noticed when the update completes
10330 * @return {Roo.Element} this
10332 update : function(html, loadScripts, callback){
10333 if(typeof html == "undefined"){
10336 if(loadScripts !== true){
10337 this.dom.innerHTML = html;
10338 if(typeof callback == "function"){
10344 var dom = this.dom;
10346 html += '<span id="' + id + '"></span>';
10348 E.onAvailable(id, function(){
10349 var hd = document.getElementsByTagName("head")[0];
10350 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
10351 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
10352 var typeRe = /\stype=([\'\"])(.*?)\1/i;
10355 while(match = re.exec(html)){
10356 var attrs = match[1];
10357 var srcMatch = attrs ? attrs.match(srcRe) : false;
10358 if(srcMatch && srcMatch[2]){
10359 var s = document.createElement("script");
10360 s.src = srcMatch[2];
10361 var typeMatch = attrs.match(typeRe);
10362 if(typeMatch && typeMatch[2]){
10363 s.type = typeMatch[2];
10366 }else if(match[2] && match[2].length > 0){
10367 if(window.execScript) {
10368 window.execScript(match[2]);
10376 window.eval(match[2]);
10380 var el = document.getElementById(id);
10381 if(el){el.parentNode.removeChild(el);}
10382 if(typeof callback == "function"){
10386 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
10391 * Direct access to the UpdateManager update() method (takes the same parameters).
10392 * @param {String/Function} url The url for this request or a function to call to get the url
10393 * @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}
10394 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
10395 * @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.
10396 * @return {Roo.Element} this
10399 var um = this.getUpdateManager();
10400 um.update.apply(um, arguments);
10405 * Gets this element's UpdateManager
10406 * @return {Roo.UpdateManager} The UpdateManager
10408 getUpdateManager : function(){
10409 if(!this.updateManager){
10410 this.updateManager = new Roo.UpdateManager(this);
10412 return this.updateManager;
10416 * Disables text selection for this element (normalized across browsers)
10417 * @return {Roo.Element} this
10419 unselectable : function(){
10420 this.dom.unselectable = "on";
10421 this.swallowEvent("selectstart", true);
10422 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
10423 this.addClass("x-unselectable");
10428 * Calculates the x, y to center this element on the screen
10429 * @return {Array} The x, y values [x, y]
10431 getCenterXY : function(){
10432 return this.getAlignToXY(document, 'c-c');
10436 * Centers the Element in either the viewport, or another Element.
10437 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
10439 center : function(centerIn){
10440 this.alignTo(centerIn || document, 'c-c');
10445 * Tests various css rules/browsers to determine if this element uses a border box
10446 * @return {Boolean}
10448 isBorderBox : function(){
10449 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
10453 * Return a box {x, y, width, height} that can be used to set another elements
10454 * size/location to match this element.
10455 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
10456 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
10457 * @return {Object} box An object in the format {x, y, width, height}
10459 getBox : function(contentBox, local){
10464 var left = parseInt(this.getStyle("left"), 10) || 0;
10465 var top = parseInt(this.getStyle("top"), 10) || 0;
10468 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
10470 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
10472 var l = this.getBorderWidth("l")+this.getPadding("l");
10473 var r = this.getBorderWidth("r")+this.getPadding("r");
10474 var t = this.getBorderWidth("t")+this.getPadding("t");
10475 var b = this.getBorderWidth("b")+this.getPadding("b");
10476 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)};
10478 bx.right = bx.x + bx.width;
10479 bx.bottom = bx.y + bx.height;
10484 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
10485 for more information about the sides.
10486 * @param {String} sides
10489 getFrameWidth : function(sides, onlyContentBox){
10490 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
10494 * 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.
10495 * @param {Object} box The box to fill {x, y, width, height}
10496 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
10497 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10498 * @return {Roo.Element} this
10500 setBox : function(box, adjust, animate){
10501 var w = box.width, h = box.height;
10502 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
10503 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
10504 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
10506 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
10511 * Forces the browser to repaint this element
10512 * @return {Roo.Element} this
10514 repaint : function(){
10515 var dom = this.dom;
10516 this.addClass("x-repaint");
10517 setTimeout(function(){
10518 Roo.get(dom).removeClass("x-repaint");
10524 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
10525 * then it returns the calculated width of the sides (see getPadding)
10526 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
10527 * @return {Object/Number}
10529 getMargins : function(side){
10532 top: parseInt(this.getStyle("margin-top"), 10) || 0,
10533 left: parseInt(this.getStyle("margin-left"), 10) || 0,
10534 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
10535 right: parseInt(this.getStyle("margin-right"), 10) || 0
10538 return this.addStyles(side, El.margins);
10543 addStyles : function(sides, styles){
10545 for(var i = 0, len = sides.length; i < len; i++){
10546 v = this.getStyle(styles[sides.charAt(i)]);
10548 w = parseInt(v, 10);
10556 * Creates a proxy element of this element
10557 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
10558 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
10559 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
10560 * @return {Roo.Element} The new proxy element
10562 createProxy : function(config, renderTo, matchBox){
10564 renderTo = Roo.getDom(renderTo);
10566 renderTo = document.body;
10568 config = typeof config == "object" ?
10569 config : {tag : "div", cls: config};
10570 var proxy = Roo.DomHelper.append(renderTo, config, true);
10572 proxy.setBox(this.getBox());
10578 * Puts a mask over this element to disable user interaction. Requires core.css.
10579 * This method can only be applied to elements which accept child nodes.
10580 * @param {String} msg (optional) A message to display in the mask
10581 * @param {String} msgCls (optional) A css class to apply to the msg element - use no-spinner to hide the spinner on bootstrap
10582 * @return {Element} The mask element
10584 mask : function(msg, msgCls)
10586 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
10587 this.setStyle("position", "relative");
10590 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
10593 this.addClass("x-masked");
10594 this._mask.setDisplayed(true);
10598 var dom = this.dom;
10599 while (dom && dom.style) {
10600 if (!isNaN(parseInt(dom.style.zIndex))) {
10601 z = Math.max(z, parseInt(dom.style.zIndex));
10603 dom = dom.parentNode;
10605 // if we are masking the body - then it hides everything..
10606 if (this.dom == document.body) {
10608 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
10609 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
10612 if(typeof msg == 'string'){
10613 if(!this._maskMsg){
10614 this._maskMsg = Roo.DomHelper.append(this.dom, {
10615 cls: "roo-el-mask-msg",
10619 cls: 'fa fa-spinner fa-spin'
10627 var mm = this._maskMsg;
10628 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
10629 if (mm.dom.lastChild) { // weird IE issue?
10630 mm.dom.lastChild.innerHTML = msg;
10632 mm.setDisplayed(true);
10634 mm.setStyle('z-index', z + 102);
10636 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
10637 this._mask.setHeight(this.getHeight());
10639 this._mask.setStyle('z-index', z + 100);
10645 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
10646 * it is cached for reuse.
10648 unmask : function(removeEl){
10650 if(removeEl === true){
10651 this._mask.remove();
10654 this._maskMsg.remove();
10655 delete this._maskMsg;
10658 this._mask.setDisplayed(false);
10660 this._maskMsg.setDisplayed(false);
10664 this.removeClass("x-masked");
10668 * Returns true if this element is masked
10669 * @return {Boolean}
10671 isMasked : function(){
10672 return this._mask && this._mask.isVisible();
10676 * Creates an iframe shim for this element to keep selects and other windowed objects from
10678 * @return {Roo.Element} The new shim element
10680 createShim : function(){
10681 var el = document.createElement('iframe');
10682 el.frameBorder = 'no';
10683 el.className = 'roo-shim';
10684 if(Roo.isIE && Roo.isSecure){
10685 el.src = Roo.SSL_SECURE_URL;
10687 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
10688 shim.autoBoxAdjust = false;
10693 * Removes this element from the DOM and deletes it from the cache
10695 remove : function(){
10696 if(this.dom.parentNode){
10697 this.dom.parentNode.removeChild(this.dom);
10699 delete El.cache[this.dom.id];
10703 * Sets up event handlers to add and remove a css class when the mouse is over this element
10704 * @param {String} className
10705 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
10706 * mouseout events for children elements
10707 * @return {Roo.Element} this
10709 addClassOnOver : function(className, preventFlicker){
10710 this.on("mouseover", function(){
10711 Roo.fly(this, '_internal').addClass(className);
10713 var removeFn = function(e){
10714 if(preventFlicker !== true || !e.within(this, true)){
10715 Roo.fly(this, '_internal').removeClass(className);
10718 this.on("mouseout", removeFn, this.dom);
10723 * Sets up event handlers to add and remove a css class when this element has the focus
10724 * @param {String} className
10725 * @return {Roo.Element} this
10727 addClassOnFocus : function(className){
10728 this.on("focus", function(){
10729 Roo.fly(this, '_internal').addClass(className);
10731 this.on("blur", function(){
10732 Roo.fly(this, '_internal').removeClass(className);
10737 * 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)
10738 * @param {String} className
10739 * @return {Roo.Element} this
10741 addClassOnClick : function(className){
10742 var dom = this.dom;
10743 this.on("mousedown", function(){
10744 Roo.fly(dom, '_internal').addClass(className);
10745 var d = Roo.get(document);
10746 var fn = function(){
10747 Roo.fly(dom, '_internal').removeClass(className);
10748 d.removeListener("mouseup", fn);
10750 d.on("mouseup", fn);
10756 * Stops the specified event from bubbling and optionally prevents the default action
10757 * @param {String} eventName
10758 * @param {Boolean} preventDefault (optional) true to prevent the default action too
10759 * @return {Roo.Element} this
10761 swallowEvent : function(eventName, preventDefault){
10762 var fn = function(e){
10763 e.stopPropagation();
10764 if(preventDefault){
10765 e.preventDefault();
10768 if(eventName instanceof Array){
10769 for(var i = 0, len = eventName.length; i < len; i++){
10770 this.on(eventName[i], fn);
10774 this.on(eventName, fn);
10781 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
10784 * Sizes this element to its parent element's dimensions performing
10785 * neccessary box adjustments.
10786 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
10787 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
10788 * @return {Roo.Element} this
10790 fitToParent : function(monitorResize, targetParent) {
10791 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
10792 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
10793 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
10796 var p = Roo.get(targetParent || this.dom.parentNode);
10797 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
10798 if (monitorResize === true) {
10799 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
10800 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
10806 * Gets the next sibling, skipping text nodes
10807 * @return {HTMLElement} The next sibling or null
10809 getNextSibling : function(){
10810 var n = this.dom.nextSibling;
10811 while(n && n.nodeType != 1){
10818 * Gets the previous sibling, skipping text nodes
10819 * @return {HTMLElement} The previous sibling or null
10821 getPrevSibling : function(){
10822 var n = this.dom.previousSibling;
10823 while(n && n.nodeType != 1){
10824 n = n.previousSibling;
10831 * Appends the passed element(s) to this element
10832 * @param {String/HTMLElement/Array/Element/CompositeElement} el
10833 * @return {Roo.Element} this
10835 appendChild: function(el){
10842 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
10843 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
10844 * automatically generated with the specified attributes.
10845 * @param {HTMLElement} insertBefore (optional) a child element of this element
10846 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
10847 * @return {Roo.Element} The new child element
10849 createChild: function(config, insertBefore, returnDom){
10850 config = config || {tag:'div'};
10852 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
10854 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
10858 * Appends this element to the passed element
10859 * @param {String/HTMLElement/Element} el The new parent element
10860 * @return {Roo.Element} this
10862 appendTo: function(el){
10863 el = Roo.getDom(el);
10864 el.appendChild(this.dom);
10869 * Inserts this element before the passed element in the DOM
10870 * @param {String/HTMLElement/Element} el The element to insert before
10871 * @return {Roo.Element} this
10873 insertBefore: function(el){
10874 el = Roo.getDom(el);
10875 el.parentNode.insertBefore(this.dom, el);
10880 * Inserts this element after the passed element in the DOM
10881 * @param {String/HTMLElement/Element} el The element to insert after
10882 * @return {Roo.Element} this
10884 insertAfter: function(el){
10885 el = Roo.getDom(el);
10886 el.parentNode.insertBefore(this.dom, el.nextSibling);
10891 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
10892 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10893 * @return {Roo.Element} The new child
10895 insertFirst: function(el, returnDom){
10897 if(typeof el == 'object' && !el.nodeType){ // dh config
10898 return this.createChild(el, this.dom.firstChild, returnDom);
10900 el = Roo.getDom(el);
10901 this.dom.insertBefore(el, this.dom.firstChild);
10902 return !returnDom ? Roo.get(el) : el;
10907 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
10908 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10909 * @param {String} where (optional) 'before' or 'after' defaults to before
10910 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10911 * @return {Roo.Element} the inserted Element
10913 insertSibling: function(el, where, returnDom){
10914 where = where ? where.toLowerCase() : 'before';
10916 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
10918 if(typeof el == 'object' && !el.nodeType){ // dh config
10919 if(where == 'after' && !this.dom.nextSibling){
10920 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
10922 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
10926 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
10927 where == 'before' ? this.dom : this.dom.nextSibling);
10936 * Creates and wraps this element with another element
10937 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
10938 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10939 * @return {HTMLElement/Element} The newly created wrapper element
10941 wrap: function(config, returnDom){
10943 config = {tag: "div"};
10945 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
10946 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
10951 * Replaces the passed element with this element
10952 * @param {String/HTMLElement/Element} el The element to replace
10953 * @return {Roo.Element} this
10955 replace: function(el){
10957 this.insertBefore(el);
10963 * Inserts an html fragment into this element
10964 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
10965 * @param {String} html The HTML fragment
10966 * @param {Boolean} returnEl True to return an Roo.Element
10967 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
10969 insertHtml : function(where, html, returnEl){
10970 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
10971 return returnEl ? Roo.get(el) : el;
10975 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
10976 * @param {Object} o The object with the attributes
10977 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
10978 * @return {Roo.Element} this
10980 set : function(o, useSet){
10982 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
10983 for(var attr in o){
10984 if(attr == "style" || typeof o[attr] == "function") { continue; }
10986 el.className = o["cls"];
10989 el.setAttribute(attr, o[attr]);
10991 el[attr] = o[attr];
10996 Roo.DomHelper.applyStyles(el, o.style);
11002 * Convenience method for constructing a KeyMap
11003 * @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:
11004 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
11005 * @param {Function} fn The function to call
11006 * @param {Object} scope (optional) The scope of the function
11007 * @return {Roo.KeyMap} The KeyMap created
11009 addKeyListener : function(key, fn, scope){
11011 if(typeof key != "object" || key instanceof Array){
11027 return new Roo.KeyMap(this, config);
11031 * Creates a KeyMap for this element
11032 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
11033 * @return {Roo.KeyMap} The KeyMap created
11035 addKeyMap : function(config){
11036 return new Roo.KeyMap(this, config);
11040 * Returns true if this element is scrollable.
11041 * @return {Boolean}
11043 isScrollable : function(){
11044 var dom = this.dom;
11045 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
11049 * 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().
11050 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
11051 * @param {Number} value The new scroll value
11052 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
11053 * @return {Element} this
11056 scrollTo : function(side, value, animate){
11057 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
11058 if(!animate || !A){
11059 this.dom[prop] = value;
11061 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
11062 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
11068 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
11069 * within this element's scrollable range.
11070 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
11071 * @param {Number} distance How far to scroll the element in pixels
11072 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
11073 * @return {Boolean} Returns true if a scroll was triggered or false if the element
11074 * was scrolled as far as it could go.
11076 scroll : function(direction, distance, animate){
11077 if(!this.isScrollable()){
11081 var l = el.scrollLeft, t = el.scrollTop;
11082 var w = el.scrollWidth, h = el.scrollHeight;
11083 var cw = el.clientWidth, ch = el.clientHeight;
11084 direction = direction.toLowerCase();
11085 var scrolled = false;
11086 var a = this.preanim(arguments, 2);
11091 var v = Math.min(l + distance, w-cw);
11092 this.scrollTo("left", v, a);
11099 var v = Math.max(l - distance, 0);
11100 this.scrollTo("left", v, a);
11108 var v = Math.max(t - distance, 0);
11109 this.scrollTo("top", v, a);
11117 var v = Math.min(t + distance, h-ch);
11118 this.scrollTo("top", v, a);
11127 * Translates the passed page coordinates into left/top css values for this element
11128 * @param {Number/Array} x The page x or an array containing [x, y]
11129 * @param {Number} y The page y
11130 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
11132 translatePoints : function(x, y){
11133 if(typeof x == 'object' || x instanceof Array){
11134 y = x[1]; x = x[0];
11136 var p = this.getStyle('position');
11137 var o = this.getXY();
11139 var l = parseInt(this.getStyle('left'), 10);
11140 var t = parseInt(this.getStyle('top'), 10);
11143 l = (p == "relative") ? 0 : this.dom.offsetLeft;
11146 t = (p == "relative") ? 0 : this.dom.offsetTop;
11149 return {left: (x - o[0] + l), top: (y - o[1] + t)};
11153 * Returns the current scroll position of the element.
11154 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
11156 getScroll : function(){
11157 var d = this.dom, doc = document;
11158 if(d == doc || d == doc.body){
11159 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
11160 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
11161 return {left: l, top: t};
11163 return {left: d.scrollLeft, top: d.scrollTop};
11168 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
11169 * are convert to standard 6 digit hex color.
11170 * @param {String} attr The css attribute
11171 * @param {String} defaultValue The default value to use when a valid color isn't found
11172 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
11175 getColor : function(attr, defaultValue, prefix){
11176 var v = this.getStyle(attr);
11177 if(!v || v == "transparent" || v == "inherit") {
11178 return defaultValue;
11180 var color = typeof prefix == "undefined" ? "#" : prefix;
11181 if(v.substr(0, 4) == "rgb("){
11182 var rvs = v.slice(4, v.length -1).split(",");
11183 for(var i = 0; i < 3; i++){
11184 var h = parseInt(rvs[i]).toString(16);
11191 if(v.substr(0, 1) == "#"){
11192 if(v.length == 4) {
11193 for(var i = 1; i < 4; i++){
11194 var c = v.charAt(i);
11197 }else if(v.length == 7){
11198 color += v.substr(1);
11202 return(color.length > 5 ? color.toLowerCase() : defaultValue);
11206 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
11207 * gradient background, rounded corners and a 4-way shadow.
11208 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
11209 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
11210 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
11211 * @return {Roo.Element} this
11213 boxWrap : function(cls){
11214 cls = cls || 'x-box';
11215 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
11216 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
11221 * Returns the value of a namespaced attribute from the element's underlying DOM node.
11222 * @param {String} namespace The namespace in which to look for the attribute
11223 * @param {String} name The attribute name
11224 * @return {String} The attribute value
11226 getAttributeNS : Roo.isIE ? function(ns, name){
11228 var type = typeof d[ns+":"+name];
11229 if(type != 'undefined' && type != 'unknown'){
11230 return d[ns+":"+name];
11233 } : function(ns, name){
11235 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
11240 * Sets or Returns the value the dom attribute value
11241 * @param {String|Object} name The attribute name (or object to set multiple attributes)
11242 * @param {String} value (optional) The value to set the attribute to
11243 * @return {String} The attribute value
11245 attr : function(name){
11246 if (arguments.length > 1) {
11247 this.dom.setAttribute(name, arguments[1]);
11248 return arguments[1];
11250 if (typeof(name) == 'object') {
11251 for(var i in name) {
11252 this.attr(i, name[i]);
11258 if (!this.dom.hasAttribute(name)) {
11261 return this.dom.getAttribute(name);
11268 var ep = El.prototype;
11271 * Appends an event handler (Shorthand for addListener)
11272 * @param {String} eventName The type of event to append
11273 * @param {Function} fn The method the event invokes
11274 * @param {Object} scope (optional) The scope (this object) of the fn
11275 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
11278 ep.on = ep.addListener;
11279 // backwards compat
11280 ep.mon = ep.addListener;
11283 * Removes an event handler from this element (shorthand for removeListener)
11284 * @param {String} eventName the type of event to remove
11285 * @param {Function} fn the method the event invokes
11286 * @return {Roo.Element} this
11289 ep.un = ep.removeListener;
11292 * true to automatically adjust width and height settings for box-model issues (default to true)
11294 ep.autoBoxAdjust = true;
11297 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
11300 El.addUnits = function(v, defaultUnit){
11301 if(v === "" || v == "auto"){
11304 if(v === undefined){
11307 if(typeof v == "number" || !El.unitPattern.test(v)){
11308 return v + (defaultUnit || 'px');
11313 // special markup used throughout Roo when box wrapping elements
11314 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>';
11316 * Visibility mode constant - Use visibility to hide element
11322 * Visibility mode constant - Use display to hide element
11328 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
11329 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
11330 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
11342 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
11343 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
11344 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
11345 * @return {Element} The Element object
11348 El.get = function(el){
11350 if(!el){ return null; }
11351 if(typeof el == "string"){ // element id
11352 if(!(elm = document.getElementById(el))){
11355 if(ex = El.cache[el]){
11358 ex = El.cache[el] = new El(elm);
11361 }else if(el.tagName){ // dom element
11365 if(ex = El.cache[id]){
11368 ex = El.cache[id] = new El(el);
11371 }else if(el instanceof El){
11373 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
11374 // catch case where it hasn't been appended
11375 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
11378 }else if(el.isComposite){
11380 }else if(el instanceof Array){
11381 return El.select(el);
11382 }else if(el == document){
11383 // create a bogus element object representing the document object
11385 var f = function(){};
11386 f.prototype = El.prototype;
11388 docEl.dom = document;
11396 El.uncache = function(el){
11397 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
11399 delete El.cache[a[i].id || a[i]];
11405 // Garbage collection - uncache elements/purge listeners on orphaned elements
11406 // so we don't hold a reference and cause the browser to retain them
11407 El.garbageCollect = function(){
11408 if(!Roo.enableGarbageCollector){
11409 clearInterval(El.collectorThread);
11412 for(var eid in El.cache){
11413 var el = El.cache[eid], d = el.dom;
11414 // -------------------------------------------------------
11415 // Determining what is garbage:
11416 // -------------------------------------------------------
11418 // dom node is null, definitely garbage
11419 // -------------------------------------------------------
11421 // no parentNode == direct orphan, definitely garbage
11422 // -------------------------------------------------------
11423 // !d.offsetParent && !document.getElementById(eid)
11424 // display none elements have no offsetParent so we will
11425 // also try to look it up by it's id. However, check
11426 // offsetParent first so we don't do unneeded lookups.
11427 // This enables collection of elements that are not orphans
11428 // directly, but somewhere up the line they have an orphan
11430 // -------------------------------------------------------
11431 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
11432 delete El.cache[eid];
11433 if(d && Roo.enableListenerCollection){
11439 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
11443 El.Flyweight = function(dom){
11446 El.Flyweight.prototype = El.prototype;
11448 El._flyweights = {};
11450 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
11451 * the dom node can be overwritten by other code.
11452 * @param {String/HTMLElement} el The dom node or id
11453 * @param {String} named (optional) Allows for creation of named reusable flyweights to
11454 * prevent conflicts (e.g. internally Roo uses "_internal")
11456 * @return {Element} The shared Element object
11458 El.fly = function(el, named){
11459 named = named || '_global';
11460 el = Roo.getDom(el);
11464 if(!El._flyweights[named]){
11465 El._flyweights[named] = new El.Flyweight();
11467 El._flyweights[named].dom = el;
11468 return El._flyweights[named];
11472 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
11473 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
11474 * Shorthand of {@link Roo.Element#get}
11475 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
11476 * @return {Element} The Element object
11482 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
11483 * the dom node can be overwritten by other code.
11484 * Shorthand of {@link Roo.Element#fly}
11485 * @param {String/HTMLElement} el The dom node or id
11486 * @param {String} named (optional) Allows for creation of named reusable flyweights to
11487 * prevent conflicts (e.g. internally Roo uses "_internal")
11489 * @return {Element} The shared Element object
11495 // speedy lookup for elements never to box adjust
11496 var noBoxAdjust = Roo.isStrict ? {
11499 input:1, select:1, textarea:1
11501 if(Roo.isIE || Roo.isGecko){
11502 noBoxAdjust['button'] = 1;
11506 Roo.EventManager.on(window, 'unload', function(){
11508 delete El._flyweights;
11516 Roo.Element.selectorFunction = Roo.DomQuery.select;
11519 Roo.Element.select = function(selector, unique, root){
11521 if(typeof selector == "string"){
11522 els = Roo.Element.selectorFunction(selector, root);
11523 }else if(selector.length !== undefined){
11526 throw "Invalid selector";
11528 if(unique === true){
11529 return new Roo.CompositeElement(els);
11531 return new Roo.CompositeElementLite(els);
11535 * Selects elements based on the passed CSS selector to enable working on them as 1.
11536 * @param {String/Array} selector The CSS selector or an array of elements
11537 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
11538 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
11539 * @return {CompositeElementLite/CompositeElement}
11543 Roo.select = Roo.Element.select;
11560 * Ext JS Library 1.1.1
11561 * Copyright(c) 2006-2007, Ext JS, LLC.
11563 * Originally Released Under LGPL - original licence link has changed is not relivant.
11566 * <script type="text/javascript">
11571 //Notifies Element that fx methods are available
11572 Roo.enableFx = true;
11576 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
11577 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
11578 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
11579 * Element effects to work.</p><br/>
11581 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
11582 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
11583 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
11584 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
11585 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
11586 * expected results and should be done with care.</p><br/>
11588 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
11589 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
11592 ----- -----------------------------
11593 tl The top left corner
11594 t The center of the top edge
11595 tr The top right corner
11596 l The center of the left edge
11597 r The center of the right edge
11598 bl The bottom left corner
11599 b The center of the bottom edge
11600 br The bottom right corner
11602 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
11603 * below are common options that can be passed to any Fx method.</b>
11604 * @cfg {Function} callback A function called when the effect is finished
11605 * @cfg {Object} scope The scope of the effect function
11606 * @cfg {String} easing A valid Easing value for the effect
11607 * @cfg {String} afterCls A css class to apply after the effect
11608 * @cfg {Number} duration The length of time (in seconds) that the effect should last
11609 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
11610 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
11611 * effects that end with the element being visually hidden, ignored otherwise)
11612 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
11613 * a function which returns such a specification that will be applied to the Element after the effect finishes
11614 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
11615 * @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
11616 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
11620 * Slides the element into view. An anchor point can be optionally passed to set the point of
11621 * origin for the slide effect. This function automatically handles wrapping the element with
11622 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
11625 // default: slide the element in from the top
11628 // custom: slide the element in from the right with a 2-second duration
11629 el.slideIn('r', { duration: 2 });
11631 // common config options shown with default values
11637 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11638 * @param {Object} options (optional) Object literal with any of the Fx config options
11639 * @return {Roo.Element} The Element
11641 slideIn : function(anchor, o){
11642 var el = this.getFxEl();
11645 el.queueFx(o, function(){
11647 anchor = anchor || "t";
11649 // fix display to visibility
11652 // restore values after effect
11653 var r = this.getFxRestore();
11654 var b = this.getBox();
11655 // fixed size for slide
11659 var wrap = this.fxWrap(r.pos, o, "hidden");
11661 var st = this.dom.style;
11662 st.visibility = "visible";
11663 st.position = "absolute";
11665 // clear out temp styles after slide and unwrap
11666 var after = function(){
11667 el.fxUnwrap(wrap, r.pos, o);
11668 st.width = r.width;
11669 st.height = r.height;
11672 // time to calc the positions
11673 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
11675 switch(anchor.toLowerCase()){
11677 wrap.setSize(b.width, 0);
11678 st.left = st.bottom = "0";
11682 wrap.setSize(0, b.height);
11683 st.right = st.top = "0";
11687 wrap.setSize(0, b.height);
11688 wrap.setX(b.right);
11689 st.left = st.top = "0";
11690 a = {width: bw, points: pt};
11693 wrap.setSize(b.width, 0);
11694 wrap.setY(b.bottom);
11695 st.left = st.top = "0";
11696 a = {height: bh, points: pt};
11699 wrap.setSize(0, 0);
11700 st.right = st.bottom = "0";
11701 a = {width: bw, height: bh};
11704 wrap.setSize(0, 0);
11705 wrap.setY(b.y+b.height);
11706 st.right = st.top = "0";
11707 a = {width: bw, height: bh, points: pt};
11710 wrap.setSize(0, 0);
11711 wrap.setXY([b.right, b.bottom]);
11712 st.left = st.top = "0";
11713 a = {width: bw, height: bh, points: pt};
11716 wrap.setSize(0, 0);
11717 wrap.setX(b.x+b.width);
11718 st.left = st.bottom = "0";
11719 a = {width: bw, height: bh, points: pt};
11722 this.dom.style.visibility = "visible";
11725 arguments.callee.anim = wrap.fxanim(a,
11735 * Slides the element out of view. An anchor point can be optionally passed to set the end point
11736 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
11737 * 'hidden') but block elements will still take up space in the document. The element must be removed
11738 * from the DOM using the 'remove' config option if desired. This function automatically handles
11739 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
11742 // default: slide the element out to the top
11745 // custom: slide the element out to the right with a 2-second duration
11746 el.slideOut('r', { duration: 2 });
11748 // common config options shown with default values
11756 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11757 * @param {Object} options (optional) Object literal with any of the Fx config options
11758 * @return {Roo.Element} The Element
11760 slideOut : function(anchor, o){
11761 var el = this.getFxEl();
11764 el.queueFx(o, function(){
11766 anchor = anchor || "t";
11768 // restore values after effect
11769 var r = this.getFxRestore();
11771 var b = this.getBox();
11772 // fixed size for slide
11776 var wrap = this.fxWrap(r.pos, o, "visible");
11778 var st = this.dom.style;
11779 st.visibility = "visible";
11780 st.position = "absolute";
11784 var after = function(){
11786 el.setDisplayed(false);
11791 el.fxUnwrap(wrap, r.pos, o);
11793 st.width = r.width;
11794 st.height = r.height;
11799 var a, zero = {to: 0};
11800 switch(anchor.toLowerCase()){
11802 st.left = st.bottom = "0";
11803 a = {height: zero};
11806 st.right = st.top = "0";
11810 st.left = st.top = "0";
11811 a = {width: zero, points: {to:[b.right, b.y]}};
11814 st.left = st.top = "0";
11815 a = {height: zero, points: {to:[b.x, b.bottom]}};
11818 st.right = st.bottom = "0";
11819 a = {width: zero, height: zero};
11822 st.right = st.top = "0";
11823 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
11826 st.left = st.top = "0";
11827 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
11830 st.left = st.bottom = "0";
11831 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
11835 arguments.callee.anim = wrap.fxanim(a,
11845 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
11846 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
11847 * The element must be removed from the DOM using the 'remove' config option if desired.
11853 // common config options shown with default values
11861 * @param {Object} options (optional) Object literal with any of the Fx config options
11862 * @return {Roo.Element} The Element
11864 puff : function(o){
11865 var el = this.getFxEl();
11868 el.queueFx(o, function(){
11869 this.clearOpacity();
11872 // restore values after effect
11873 var r = this.getFxRestore();
11874 var st = this.dom.style;
11876 var after = function(){
11878 el.setDisplayed(false);
11885 el.setPositioning(r.pos);
11886 st.width = r.width;
11887 st.height = r.height;
11892 var width = this.getWidth();
11893 var height = this.getHeight();
11895 arguments.callee.anim = this.fxanim({
11896 width : {to: this.adjustWidth(width * 2)},
11897 height : {to: this.adjustHeight(height * 2)},
11898 points : {by: [-(width * .5), -(height * .5)]},
11900 fontSize: {to:200, unit: "%"}
11911 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
11912 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
11913 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
11919 // all config options shown with default values
11927 * @param {Object} options (optional) Object literal with any of the Fx config options
11928 * @return {Roo.Element} The Element
11930 switchOff : function(o){
11931 var el = this.getFxEl();
11934 el.queueFx(o, function(){
11935 this.clearOpacity();
11938 // restore values after effect
11939 var r = this.getFxRestore();
11940 var st = this.dom.style;
11942 var after = function(){
11944 el.setDisplayed(false);
11950 el.setPositioning(r.pos);
11951 st.width = r.width;
11952 st.height = r.height;
11957 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
11958 this.clearOpacity();
11962 points:{by:[0, this.getHeight() * .5]}
11963 }, o, 'motion', 0.3, 'easeIn', after);
11964 }).defer(100, this);
11971 * Highlights the Element by setting a color (applies to the background-color by default, but can be
11972 * changed using the "attr" config option) and then fading back to the original color. If no original
11973 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
11976 // default: highlight background to yellow
11979 // custom: highlight foreground text to blue for 2 seconds
11980 el.highlight("0000ff", { attr: 'color', duration: 2 });
11982 // common config options shown with default values
11983 el.highlight("ffff9c", {
11984 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
11985 endColor: (current color) or "ffffff",
11990 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
11991 * @param {Object} options (optional) Object literal with any of the Fx config options
11992 * @return {Roo.Element} The Element
11994 highlight : function(color, o){
11995 var el = this.getFxEl();
11998 el.queueFx(o, function(){
11999 color = color || "ffff9c";
12000 attr = o.attr || "backgroundColor";
12002 this.clearOpacity();
12005 var origColor = this.getColor(attr);
12006 var restoreColor = this.dom.style[attr];
12007 endColor = (o.endColor || origColor) || "ffffff";
12009 var after = function(){
12010 el.dom.style[attr] = restoreColor;
12015 a[attr] = {from: color, to: endColor};
12016 arguments.callee.anim = this.fxanim(a,
12026 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
12029 // default: a single light blue ripple
12032 // custom: 3 red ripples lasting 3 seconds total
12033 el.frame("ff0000", 3, { duration: 3 });
12035 // common config options shown with default values
12036 el.frame("C3DAF9", 1, {
12037 duration: 1 //duration of entire animation (not each individual ripple)
12038 // Note: Easing is not configurable and will be ignored if included
12041 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
12042 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
12043 * @param {Object} options (optional) Object literal with any of the Fx config options
12044 * @return {Roo.Element} The Element
12046 frame : function(color, count, o){
12047 var el = this.getFxEl();
12050 el.queueFx(o, function(){
12051 color = color || "#C3DAF9";
12052 if(color.length == 6){
12053 color = "#" + color;
12055 count = count || 1;
12056 duration = o.duration || 1;
12059 var b = this.getBox();
12060 var animFn = function(){
12061 var proxy = this.createProxy({
12064 visbility:"hidden",
12065 position:"absolute",
12066 "z-index":"35000", // yee haw
12067 border:"0px solid " + color
12070 var scale = Roo.isBorderBox ? 2 : 1;
12072 top:{from:b.y, to:b.y - 20},
12073 left:{from:b.x, to:b.x - 20},
12074 borderWidth:{from:0, to:10},
12075 opacity:{from:1, to:0},
12076 height:{from:b.height, to:(b.height + (20*scale))},
12077 width:{from:b.width, to:(b.width + (20*scale))}
12078 }, duration, function(){
12082 animFn.defer((duration/2)*1000, this);
12093 * Creates a pause before any subsequent queued effects begin. If there are
12094 * no effects queued after the pause it will have no effect.
12099 * @param {Number} seconds The length of time to pause (in seconds)
12100 * @return {Roo.Element} The Element
12102 pause : function(seconds){
12103 var el = this.getFxEl();
12106 el.queueFx(o, function(){
12107 setTimeout(function(){
12109 }, seconds * 1000);
12115 * Fade an element in (from transparent to opaque). The ending opacity can be specified
12116 * using the "endOpacity" config option.
12119 // default: fade in from opacity 0 to 100%
12122 // custom: fade in from opacity 0 to 75% over 2 seconds
12123 el.fadeIn({ endOpacity: .75, duration: 2});
12125 // common config options shown with default values
12127 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
12132 * @param {Object} options (optional) Object literal with any of the Fx config options
12133 * @return {Roo.Element} The Element
12135 fadeIn : function(o){
12136 var el = this.getFxEl();
12138 el.queueFx(o, function(){
12139 this.setOpacity(0);
12141 this.dom.style.visibility = 'visible';
12142 var to = o.endOpacity || 1;
12143 arguments.callee.anim = this.fxanim({opacity:{to:to}},
12144 o, null, .5, "easeOut", function(){
12146 this.clearOpacity();
12155 * Fade an element out (from opaque to transparent). The ending opacity can be specified
12156 * using the "endOpacity" config option.
12159 // default: fade out from the element's current opacity to 0
12162 // custom: fade out from the element's current opacity to 25% over 2 seconds
12163 el.fadeOut({ endOpacity: .25, duration: 2});
12165 // common config options shown with default values
12167 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
12174 * @param {Object} options (optional) Object literal with any of the Fx config options
12175 * @return {Roo.Element} The Element
12177 fadeOut : function(o){
12178 var el = this.getFxEl();
12180 el.queueFx(o, function(){
12181 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
12182 o, null, .5, "easeOut", function(){
12183 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
12184 this.dom.style.display = "none";
12186 this.dom.style.visibility = "hidden";
12188 this.clearOpacity();
12196 * Animates the transition of an element's dimensions from a starting height/width
12197 * to an ending height/width.
12200 // change height and width to 100x100 pixels
12201 el.scale(100, 100);
12203 // common config options shown with default values. The height and width will default to
12204 // the element's existing values if passed as null.
12207 [element's height], {
12212 * @param {Number} width The new width (pass undefined to keep the original width)
12213 * @param {Number} height The new height (pass undefined to keep the original height)
12214 * @param {Object} options (optional) Object literal with any of the Fx config options
12215 * @return {Roo.Element} The Element
12217 scale : function(w, h, o){
12218 this.shift(Roo.apply({}, o, {
12226 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
12227 * Any of these properties not specified in the config object will not be changed. This effect
12228 * requires that at least one new dimension, position or opacity setting must be passed in on
12229 * the config object in order for the function to have any effect.
12232 // slide the element horizontally to x position 200 while changing the height and opacity
12233 el.shift({ x: 200, height: 50, opacity: .8 });
12235 // common config options shown with default values.
12237 width: [element's width],
12238 height: [element's height],
12239 x: [element's x position],
12240 y: [element's y position],
12241 opacity: [element's opacity],
12246 * @param {Object} options Object literal with any of the Fx config options
12247 * @return {Roo.Element} The Element
12249 shift : function(o){
12250 var el = this.getFxEl();
12252 el.queueFx(o, function(){
12253 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
12254 if(w !== undefined){
12255 a.width = {to: this.adjustWidth(w)};
12257 if(h !== undefined){
12258 a.height = {to: this.adjustHeight(h)};
12260 if(x !== undefined || y !== undefined){
12262 x !== undefined ? x : this.getX(),
12263 y !== undefined ? y : this.getY()
12266 if(op !== undefined){
12267 a.opacity = {to: op};
12269 if(o.xy !== undefined){
12270 a.points = {to: o.xy};
12272 arguments.callee.anim = this.fxanim(a,
12273 o, 'motion', .35, "easeOut", function(){
12281 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
12282 * ending point of the effect.
12285 // default: slide the element downward while fading out
12288 // custom: slide the element out to the right with a 2-second duration
12289 el.ghost('r', { duration: 2 });
12291 // common config options shown with default values
12299 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
12300 * @param {Object} options (optional) Object literal with any of the Fx config options
12301 * @return {Roo.Element} The Element
12303 ghost : function(anchor, o){
12304 var el = this.getFxEl();
12307 el.queueFx(o, function(){
12308 anchor = anchor || "b";
12310 // restore values after effect
12311 var r = this.getFxRestore();
12312 var w = this.getWidth(),
12313 h = this.getHeight();
12315 var st = this.dom.style;
12317 var after = function(){
12319 el.setDisplayed(false);
12325 el.setPositioning(r.pos);
12326 st.width = r.width;
12327 st.height = r.height;
12332 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
12333 switch(anchor.toLowerCase()){
12360 arguments.callee.anim = this.fxanim(a,
12370 * Ensures that all effects queued after syncFx is called on the element are
12371 * run concurrently. This is the opposite of {@link #sequenceFx}.
12372 * @return {Roo.Element} The Element
12374 syncFx : function(){
12375 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
12384 * Ensures that all effects queued after sequenceFx is called on the element are
12385 * run in sequence. This is the opposite of {@link #syncFx}.
12386 * @return {Roo.Element} The Element
12388 sequenceFx : function(){
12389 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
12391 concurrent : false,
12398 nextFx : function(){
12399 var ef = this.fxQueue[0];
12406 * Returns true if the element has any effects actively running or queued, else returns false.
12407 * @return {Boolean} True if element has active effects, else false
12409 hasActiveFx : function(){
12410 return this.fxQueue && this.fxQueue[0];
12414 * Stops any running effects and clears the element's internal effects queue if it contains
12415 * any additional effects that haven't started yet.
12416 * @return {Roo.Element} The Element
12418 stopFx : function(){
12419 if(this.hasActiveFx()){
12420 var cur = this.fxQueue[0];
12421 if(cur && cur.anim && cur.anim.isAnimated()){
12422 this.fxQueue = [cur]; // clear out others
12423 cur.anim.stop(true);
12430 beforeFx : function(o){
12431 if(this.hasActiveFx() && !o.concurrent){
12442 * Returns true if the element is currently blocking so that no other effect can be queued
12443 * until this effect is finished, else returns false if blocking is not set. This is commonly
12444 * used to ensure that an effect initiated by a user action runs to completion prior to the
12445 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
12446 * @return {Boolean} True if blocking, else false
12448 hasFxBlock : function(){
12449 var q = this.fxQueue;
12450 return q && q[0] && q[0].block;
12454 queueFx : function(o, fn){
12458 if(!this.hasFxBlock()){
12459 Roo.applyIf(o, this.fxDefaults);
12461 var run = this.beforeFx(o);
12462 fn.block = o.block;
12463 this.fxQueue.push(fn);
12475 fxWrap : function(pos, o, vis){
12477 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
12480 wrapXY = this.getXY();
12482 var div = document.createElement("div");
12483 div.style.visibility = vis;
12484 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
12485 wrap.setPositioning(pos);
12486 if(wrap.getStyle("position") == "static"){
12487 wrap.position("relative");
12489 this.clearPositioning('auto');
12491 wrap.dom.appendChild(this.dom);
12493 wrap.setXY(wrapXY);
12500 fxUnwrap : function(wrap, pos, o){
12501 this.clearPositioning();
12502 this.setPositioning(pos);
12504 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
12510 getFxRestore : function(){
12511 var st = this.dom.style;
12512 return {pos: this.getPositioning(), width: st.width, height : st.height};
12516 afterFx : function(o){
12518 this.applyStyles(o.afterStyle);
12521 this.addClass(o.afterCls);
12523 if(o.remove === true){
12526 Roo.callback(o.callback, o.scope, [this]);
12528 this.fxQueue.shift();
12534 getFxEl : function(){ // support for composite element fx
12535 return Roo.get(this.dom);
12539 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
12540 animType = animType || 'run';
12542 var anim = Roo.lib.Anim[animType](
12544 (opt.duration || defaultDur) || .35,
12545 (opt.easing || defaultEase) || 'easeOut',
12547 Roo.callback(cb, this);
12556 // backwords compat
12557 Roo.Fx.resize = Roo.Fx.scale;
12559 //When included, Roo.Fx is automatically applied to Element so that all basic
12560 //effects are available directly via the Element API
12561 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
12563 * Ext JS Library 1.1.1
12564 * Copyright(c) 2006-2007, Ext JS, LLC.
12566 * Originally Released Under LGPL - original licence link has changed is not relivant.
12569 * <script type="text/javascript">
12574 * @class Roo.CompositeElement
12575 * Standard composite class. Creates a Roo.Element for every element in the collection.
12577 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12578 * actions will be performed on all the elements in this collection.</b>
12580 * All methods return <i>this</i> and can be chained.
12582 var els = Roo.select("#some-el div.some-class", true);
12583 // or select directly from an existing element
12584 var el = Roo.get('some-el');
12585 el.select('div.some-class', true);
12587 els.setWidth(100); // all elements become 100 width
12588 els.hide(true); // all elements fade out and hide
12590 els.setWidth(100).hide(true);
12593 Roo.CompositeElement = function(els){
12594 this.elements = [];
12595 this.addElements(els);
12597 Roo.CompositeElement.prototype = {
12599 addElements : function(els){
12603 if(typeof els == "string"){
12604 els = Roo.Element.selectorFunction(els);
12606 var yels = this.elements;
12607 var index = yels.length-1;
12608 for(var i = 0, len = els.length; i < len; i++) {
12609 yels[++index] = Roo.get(els[i]);
12615 * Clears this composite and adds the elements returned by the passed selector.
12616 * @param {String/Array} els A string CSS selector, an array of elements or an element
12617 * @return {CompositeElement} this
12619 fill : function(els){
12620 this.elements = [];
12626 * Filters this composite to only elements that match the passed selector.
12627 * @param {String} selector A string CSS selector
12628 * @param {Boolean} inverse return inverse filter (not matches)
12629 * @return {CompositeElement} this
12631 filter : function(selector, inverse){
12633 inverse = inverse || false;
12634 this.each(function(el){
12635 var match = inverse ? !el.is(selector) : el.is(selector);
12637 els[els.length] = el.dom;
12644 invoke : function(fn, args){
12645 var els = this.elements;
12646 for(var i = 0, len = els.length; i < len; i++) {
12647 Roo.Element.prototype[fn].apply(els[i], args);
12652 * Adds elements to this composite.
12653 * @param {String/Array} els A string CSS selector, an array of elements or an element
12654 * @return {CompositeElement} this
12656 add : function(els){
12657 if(typeof els == "string"){
12658 this.addElements(Roo.Element.selectorFunction(els));
12659 }else if(els.length !== undefined){
12660 this.addElements(els);
12662 this.addElements([els]);
12667 * Calls the passed function passing (el, this, index) for each element in this composite.
12668 * @param {Function} fn The function to call
12669 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12670 * @return {CompositeElement} this
12672 each : function(fn, scope){
12673 var els = this.elements;
12674 for(var i = 0, len = els.length; i < len; i++){
12675 if(fn.call(scope || els[i], els[i], this, i) === false) {
12683 * Returns the Element object at the specified index
12684 * @param {Number} index
12685 * @return {Roo.Element}
12687 item : function(index){
12688 return this.elements[index] || null;
12692 * Returns the first Element
12693 * @return {Roo.Element}
12695 first : function(){
12696 return this.item(0);
12700 * Returns the last Element
12701 * @return {Roo.Element}
12704 return this.item(this.elements.length-1);
12708 * Returns the number of elements in this composite
12711 getCount : function(){
12712 return this.elements.length;
12716 * Returns true if this composite contains the passed element
12719 contains : function(el){
12720 return this.indexOf(el) !== -1;
12724 * Returns true if this composite contains the passed element
12727 indexOf : function(el){
12728 return this.elements.indexOf(Roo.get(el));
12733 * Removes the specified element(s).
12734 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
12735 * or an array of any of those.
12736 * @param {Boolean} removeDom (optional) True to also remove the element from the document
12737 * @return {CompositeElement} this
12739 removeElement : function(el, removeDom){
12740 if(el instanceof Array){
12741 for(var i = 0, len = el.length; i < len; i++){
12742 this.removeElement(el[i]);
12746 var index = typeof el == 'number' ? el : this.indexOf(el);
12749 var d = this.elements[index];
12753 d.parentNode.removeChild(d);
12756 this.elements.splice(index, 1);
12762 * Replaces the specified element with the passed element.
12763 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
12765 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
12766 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
12767 * @return {CompositeElement} this
12769 replaceElement : function(el, replacement, domReplace){
12770 var index = typeof el == 'number' ? el : this.indexOf(el);
12773 this.elements[index].replaceWith(replacement);
12775 this.elements.splice(index, 1, Roo.get(replacement))
12782 * Removes all elements.
12784 clear : function(){
12785 this.elements = [];
12789 Roo.CompositeElement.createCall = function(proto, fnName){
12790 if(!proto[fnName]){
12791 proto[fnName] = function(){
12792 return this.invoke(fnName, arguments);
12796 for(var fnName in Roo.Element.prototype){
12797 if(typeof Roo.Element.prototype[fnName] == "function"){
12798 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
12804 * Ext JS Library 1.1.1
12805 * Copyright(c) 2006-2007, Ext JS, LLC.
12807 * Originally Released Under LGPL - original licence link has changed is not relivant.
12810 * <script type="text/javascript">
12814 * @class Roo.CompositeElementLite
12815 * @extends Roo.CompositeElement
12816 * Flyweight composite class. Reuses the same Roo.Element for element operations.
12818 var els = Roo.select("#some-el div.some-class");
12819 // or select directly from an existing element
12820 var el = Roo.get('some-el');
12821 el.select('div.some-class');
12823 els.setWidth(100); // all elements become 100 width
12824 els.hide(true); // all elements fade out and hide
12826 els.setWidth(100).hide(true);
12827 </code></pre><br><br>
12828 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12829 * actions will be performed on all the elements in this collection.</b>
12831 Roo.CompositeElementLite = function(els){
12832 Roo.CompositeElementLite.superclass.constructor.call(this, els);
12833 this.el = new Roo.Element.Flyweight();
12835 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
12836 addElements : function(els){
12838 if(els instanceof Array){
12839 this.elements = this.elements.concat(els);
12841 var yels = this.elements;
12842 var index = yels.length-1;
12843 for(var i = 0, len = els.length; i < len; i++) {
12844 yels[++index] = els[i];
12850 invoke : function(fn, args){
12851 var els = this.elements;
12853 for(var i = 0, len = els.length; i < len; i++) {
12855 Roo.Element.prototype[fn].apply(el, args);
12860 * Returns a flyweight Element of the dom element object at the specified index
12861 * @param {Number} index
12862 * @return {Roo.Element}
12864 item : function(index){
12865 if(!this.elements[index]){
12868 this.el.dom = this.elements[index];
12872 // fixes scope with flyweight
12873 addListener : function(eventName, handler, scope, opt){
12874 var els = this.elements;
12875 for(var i = 0, len = els.length; i < len; i++) {
12876 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
12882 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
12883 * passed is the flyweight (shared) Roo.Element instance, so if you require a
12884 * a reference to the dom node, use el.dom.</b>
12885 * @param {Function} fn The function to call
12886 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12887 * @return {CompositeElement} this
12889 each : function(fn, scope){
12890 var els = this.elements;
12892 for(var i = 0, len = els.length; i < len; i++){
12894 if(fn.call(scope || el, el, this, i) === false){
12901 indexOf : function(el){
12902 return this.elements.indexOf(Roo.getDom(el));
12905 replaceElement : function(el, replacement, domReplace){
12906 var index = typeof el == 'number' ? el : this.indexOf(el);
12908 replacement = Roo.getDom(replacement);
12910 var d = this.elements[index];
12911 d.parentNode.insertBefore(replacement, d);
12912 d.parentNode.removeChild(d);
12914 this.elements.splice(index, 1, replacement);
12919 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
12923 * Ext JS Library 1.1.1
12924 * Copyright(c) 2006-2007, Ext JS, LLC.
12926 * Originally Released Under LGPL - original licence link has changed is not relivant.
12929 * <script type="text/javascript">
12935 * @class Roo.data.Connection
12936 * @extends Roo.util.Observable
12937 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
12938 * either to a configured URL, or to a URL specified at request time.
12940 * Requests made by this class are asynchronous, and will return immediately. No data from
12941 * the server will be available to the statement immediately following the {@link #request} call.
12942 * To process returned data, use a callback in the request options object, or an event listener.
12944 * Note: If you are doing a file upload, you will not get a normal response object sent back to
12945 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
12946 * The response object is created using the innerHTML of the IFRAME's document as the responseText
12947 * property and, if present, the IFRAME's XML document as the responseXML property.
12949 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
12950 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
12951 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
12952 * standard DOM methods.
12954 * @param {Object} config a configuration object.
12956 Roo.data.Connection = function(config){
12957 Roo.apply(this, config);
12960 * @event beforerequest
12961 * Fires before a network request is made to retrieve a data object.
12962 * @param {Connection} conn This Connection object.
12963 * @param {Object} options The options config object passed to the {@link #request} method.
12965 "beforerequest" : true,
12967 * @event requestcomplete
12968 * Fires if the request was successfully completed.
12969 * @param {Connection} conn This Connection object.
12970 * @param {Object} response The XHR object containing the response data.
12971 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12972 * @param {Object} options The options config object passed to the {@link #request} method.
12974 "requestcomplete" : true,
12976 * @event requestexception
12977 * Fires if an error HTTP status was returned from the server.
12978 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
12979 * @param {Connection} conn This Connection object.
12980 * @param {Object} response The XHR object containing the response data.
12981 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12982 * @param {Object} options The options config object passed to the {@link #request} method.
12984 "requestexception" : true
12986 Roo.data.Connection.superclass.constructor.call(this);
12989 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
12991 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12994 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12995 * extra parameters to each request made by this object. (defaults to undefined)
12998 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12999 * to each request made by this object. (defaults to undefined)
13002 * @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)
13005 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
13009 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
13015 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
13018 disableCaching: true,
13021 * Sends an HTTP request to a remote server.
13022 * @param {Object} options An object which may contain the following properties:<ul>
13023 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
13024 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
13025 * request, a url encoded string or a function to call to get either.</li>
13026 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
13027 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
13028 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
13029 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
13030 * <li>options {Object} The parameter to the request call.</li>
13031 * <li>success {Boolean} True if the request succeeded.</li>
13032 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
13034 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
13035 * The callback is passed the following parameters:<ul>
13036 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
13037 * <li>options {Object} The parameter to the request call.</li>
13039 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
13040 * The callback is passed the following parameters:<ul>
13041 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
13042 * <li>options {Object} The parameter to the request call.</li>
13044 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
13045 * for the callback function. Defaults to the browser window.</li>
13046 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
13047 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
13048 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
13049 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
13050 * params for the post data. Any params will be appended to the URL.</li>
13051 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
13053 * @return {Number} transactionId
13055 request : function(o){
13056 if(this.fireEvent("beforerequest", this, o) !== false){
13059 if(typeof p == "function"){
13060 p = p.call(o.scope||window, o);
13062 if(typeof p == "object"){
13063 p = Roo.urlEncode(o.params);
13065 if(this.extraParams){
13066 var extras = Roo.urlEncode(this.extraParams);
13067 p = p ? (p + '&' + extras) : extras;
13070 var url = o.url || this.url;
13071 if(typeof url == 'function'){
13072 url = url.call(o.scope||window, o);
13076 var form = Roo.getDom(o.form);
13077 url = url || form.action;
13079 var enctype = form.getAttribute("enctype");
13082 return this.doFormDataUpload(o, url);
13085 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
13086 return this.doFormUpload(o, p, url);
13088 var f = Roo.lib.Ajax.serializeForm(form);
13089 p = p ? (p + '&' + f) : f;
13092 if (!o.form && o.formData) {
13093 o.formData = o.formData === true ? new FormData() : o.formData;
13094 for (var k in o.params) {
13095 o.formData.append(k,o.params[k]);
13098 return this.doFormDataUpload(o, url);
13102 var hs = o.headers;
13103 if(this.defaultHeaders){
13104 hs = Roo.apply(hs || {}, this.defaultHeaders);
13111 success: this.handleResponse,
13112 failure: this.handleFailure,
13114 argument: {options: o},
13115 timeout : o.timeout || this.timeout
13118 var method = o.method||this.method||(p ? "POST" : "GET");
13120 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
13121 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
13124 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
13128 }else if(this.autoAbort !== false){
13132 if((method == 'GET' && p) || o.xmlData){
13133 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
13136 Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
13137 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
13138 Roo.lib.Ajax.useDefaultHeader == true;
13139 return this.transId;
13141 Roo.callback(o.callback, o.scope, [o, null, null]);
13147 * Determine whether this object has a request outstanding.
13148 * @param {Number} transactionId (Optional) defaults to the last transaction
13149 * @return {Boolean} True if there is an outstanding request.
13151 isLoading : function(transId){
13153 return Roo.lib.Ajax.isCallInProgress(transId);
13155 return this.transId ? true : false;
13160 * Aborts any outstanding request.
13161 * @param {Number} transactionId (Optional) defaults to the last transaction
13163 abort : function(transId){
13164 if(transId || this.isLoading()){
13165 Roo.lib.Ajax.abort(transId || this.transId);
13170 handleResponse : function(response){
13171 this.transId = false;
13172 var options = response.argument.options;
13173 response.argument = options ? options.argument : null;
13174 this.fireEvent("requestcomplete", this, response, options);
13175 Roo.callback(options.success, options.scope, [response, options]);
13176 Roo.callback(options.callback, options.scope, [options, true, response]);
13180 handleFailure : function(response, e){
13181 this.transId = false;
13182 var options = response.argument.options;
13183 response.argument = options ? options.argument : null;
13184 this.fireEvent("requestexception", this, response, options, e);
13185 Roo.callback(options.failure, options.scope, [response, options]);
13186 Roo.callback(options.callback, options.scope, [options, false, response]);
13190 doFormUpload : function(o, ps, url){
13192 var frame = document.createElement('iframe');
13195 frame.className = 'x-hidden';
13197 frame.src = Roo.SSL_SECURE_URL;
13199 document.body.appendChild(frame);
13202 document.frames[id].name = id;
13205 var form = Roo.getDom(o.form);
13207 form.method = 'POST';
13208 form.enctype = form.encoding = 'multipart/form-data';
13214 if(ps){ // add dynamic params
13216 ps = Roo.urlDecode(ps, false);
13218 if(ps.hasOwnProperty(k)){
13219 hd = document.createElement('input');
13220 hd.type = 'hidden';
13223 form.appendChild(hd);
13230 var r = { // bogus response object
13235 r.argument = o ? o.argument : null;
13240 doc = frame.contentWindow.document;
13242 doc = (frame.contentDocument || window.frames[id].document);
13244 if(doc && doc.body){
13245 r.responseText = doc.body.innerHTML;
13247 if(doc && doc.XMLDocument){
13248 r.responseXML = doc.XMLDocument;
13250 r.responseXML = doc;
13257 Roo.EventManager.removeListener(frame, 'load', cb, this);
13259 this.fireEvent("requestcomplete", this, r, o);
13260 Roo.callback(o.success, o.scope, [r, o]);
13261 Roo.callback(o.callback, o.scope, [o, true, r]);
13263 setTimeout(function(){document.body.removeChild(frame);}, 100);
13266 Roo.EventManager.on(frame, 'load', cb, this);
13269 if(hiddens){ // remove dynamic params
13270 for(var i = 0, len = hiddens.length; i < len; i++){
13271 form.removeChild(hiddens[i]);
13275 // this is a 'formdata version???'
13278 doFormDataUpload : function(o, url)
13282 var form = Roo.getDom(o.form);
13283 form.enctype = form.encoding = 'multipart/form-data';
13284 formData = o.formData === true ? new FormData(form) : o.formData;
13286 formData = o.formData === true ? new FormData() : o.formData;
13291 success: this.handleResponse,
13292 failure: this.handleFailure,
13294 argument: {options: o},
13295 timeout : o.timeout || this.timeout
13298 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
13302 }else if(this.autoAbort !== false){
13306 //Roo.lib.Ajax.defaultPostHeader = null;
13307 Roo.lib.Ajax.useDefaultHeader = false;
13308 this.transId = Roo.lib.Ajax.request( "POST", url, cb, formData, o);
13309 Roo.lib.Ajax.useDefaultHeader = true;
13317 * Ext JS Library 1.1.1
13318 * Copyright(c) 2006-2007, Ext JS, LLC.
13320 * Originally Released Under LGPL - original licence link has changed is not relivant.
13323 * <script type="text/javascript">
13327 * Global Ajax request class.
13330 * @extends Roo.data.Connection
13333 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
13334 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
13335 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
13336 * @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)
13337 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
13338 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
13339 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
13341 Roo.Ajax = new Roo.data.Connection({
13350 * Serialize the passed form into a url encoded string
13352 * @param {String/HTMLElement} form
13355 serializeForm : function(form){
13356 return Roo.lib.Ajax.serializeForm(form);
13360 * Ext JS Library 1.1.1
13361 * Copyright(c) 2006-2007, Ext JS, LLC.
13363 * Originally Released Under LGPL - original licence link has changed is not relivant.
13366 * <script type="text/javascript">
13371 * @class Roo.UpdateManager
13372 * @extends Roo.util.Observable
13373 * Provides AJAX-style update for Element object.<br><br>
13376 * // Get it from a Roo.Element object
13377 * var el = Roo.get("foo");
13378 * var mgr = el.getUpdateManager();
13379 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
13381 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
13383 * // or directly (returns the same UpdateManager instance)
13384 * var mgr = new Roo.UpdateManager("myElementId");
13385 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
13386 * mgr.on("update", myFcnNeedsToKnow);
13388 // short handed call directly from the element object
13389 Roo.get("foo").load({
13393 text: "Loading Foo..."
13397 * Create new UpdateManager directly.
13398 * @param {String/HTMLElement/Roo.Element} el The element to update
13399 * @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).
13401 Roo.UpdateManager = function(el, forceNew){
13403 if(!forceNew && el.updateManager){
13404 return el.updateManager;
13407 * The Element object
13408 * @type Roo.Element
13412 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
13415 this.defaultUrl = null;
13419 * @event beforeupdate
13420 * Fired before an update is made, return false from your handler and the update is cancelled.
13421 * @param {Roo.Element} el
13422 * @param {String/Object/Function} url
13423 * @param {String/Object} params
13425 "beforeupdate": true,
13428 * Fired after successful update is made.
13429 * @param {Roo.Element} el
13430 * @param {Object} oResponseObject The response Object
13435 * Fired on update failure.
13436 * @param {Roo.Element} el
13437 * @param {Object} oResponseObject The response Object
13441 var d = Roo.UpdateManager.defaults;
13443 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
13446 this.sslBlankUrl = d.sslBlankUrl;
13448 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
13451 this.disableCaching = d.disableCaching;
13453 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
13456 this.indicatorText = d.indicatorText;
13458 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
13461 this.showLoadIndicator = d.showLoadIndicator;
13463 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
13466 this.timeout = d.timeout;
13469 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
13472 this.loadScripts = d.loadScripts;
13475 * Transaction object of current executing transaction
13477 this.transaction = null;
13482 this.autoRefreshProcId = null;
13484 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
13487 this.refreshDelegate = this.refresh.createDelegate(this);
13489 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
13492 this.updateDelegate = this.update.createDelegate(this);
13494 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
13497 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
13501 this.successDelegate = this.processSuccess.createDelegate(this);
13505 this.failureDelegate = this.processFailure.createDelegate(this);
13507 if(!this.renderer){
13509 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
13511 this.renderer = new Roo.UpdateManager.BasicRenderer();
13514 Roo.UpdateManager.superclass.constructor.call(this);
13517 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
13519 * Get the Element this UpdateManager is bound to
13520 * @return {Roo.Element} The element
13522 getEl : function(){
13526 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
13527 * @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:
13530 url: "your-url.php",<br/>
13531 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
13532 callback: yourFunction,<br/>
13533 scope: yourObject, //(optional scope) <br/>
13534 discardUrl: false, <br/>
13535 nocache: false,<br/>
13536 text: "Loading...",<br/>
13538 scripts: false<br/>
13541 * The only required property is url. The optional properties nocache, text and scripts
13542 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
13543 * @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}
13544 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13545 * @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.
13547 update : function(url, params, callback, discardUrl){
13548 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
13549 var method = this.method,
13551 if(typeof url == "object"){ // must be config object
13554 params = params || cfg.params;
13555 callback = callback || cfg.callback;
13556 discardUrl = discardUrl || cfg.discardUrl;
13557 if(callback && cfg.scope){
13558 callback = callback.createDelegate(cfg.scope);
13560 if(typeof cfg.method != "undefined"){method = cfg.method;};
13561 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
13562 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
13563 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
13564 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
13566 this.showLoading();
13568 this.defaultUrl = url;
13570 if(typeof url == "function"){
13571 url = url.call(this);
13574 method = method || (params ? "POST" : "GET");
13575 if(method == "GET"){
13576 url = this.prepareUrl(url);
13579 var o = Roo.apply(cfg ||{}, {
13582 success: this.successDelegate,
13583 failure: this.failureDelegate,
13584 callback: undefined,
13585 timeout: (this.timeout*1000),
13586 argument: {"url": url, "form": null, "callback": callback, "params": params}
13588 Roo.log("updated manager called with timeout of " + o.timeout);
13589 this.transaction = Roo.Ajax.request(o);
13594 * 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.
13595 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
13596 * @param {String/HTMLElement} form The form Id or form element
13597 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
13598 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
13599 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13601 formUpdate : function(form, url, reset, callback){
13602 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
13603 if(typeof url == "function"){
13604 url = url.call(this);
13606 form = Roo.getDom(form);
13607 this.transaction = Roo.Ajax.request({
13610 success: this.successDelegate,
13611 failure: this.failureDelegate,
13612 timeout: (this.timeout*1000),
13613 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
13615 this.showLoading.defer(1, this);
13620 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
13621 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13623 refresh : function(callback){
13624 if(this.defaultUrl == null){
13627 this.update(this.defaultUrl, null, callback, true);
13631 * Set this element to auto refresh.
13632 * @param {Number} interval How often to update (in seconds).
13633 * @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)
13634 * @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}
13635 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13636 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
13638 startAutoRefresh : function(interval, url, params, callback, refreshNow){
13640 this.update(url || this.defaultUrl, params, callback, true);
13642 if(this.autoRefreshProcId){
13643 clearInterval(this.autoRefreshProcId);
13645 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
13649 * Stop auto refresh on this element.
13651 stopAutoRefresh : function(){
13652 if(this.autoRefreshProcId){
13653 clearInterval(this.autoRefreshProcId);
13654 delete this.autoRefreshProcId;
13658 isAutoRefreshing : function(){
13659 return this.autoRefreshProcId ? true : false;
13662 * Called to update the element to "Loading" state. Override to perform custom action.
13664 showLoading : function(){
13665 if(this.showLoadIndicator){
13666 this.el.update(this.indicatorText);
13671 * Adds unique parameter to query string if disableCaching = true
13674 prepareUrl : function(url){
13675 if(this.disableCaching){
13676 var append = "_dc=" + (new Date().getTime());
13677 if(url.indexOf("?") !== -1){
13678 url += "&" + append;
13680 url += "?" + append;
13689 processSuccess : function(response){
13690 this.transaction = null;
13691 if(response.argument.form && response.argument.reset){
13692 try{ // put in try/catch since some older FF releases had problems with this
13693 response.argument.form.reset();
13696 if(this.loadScripts){
13697 this.renderer.render(this.el, response, this,
13698 this.updateComplete.createDelegate(this, [response]));
13700 this.renderer.render(this.el, response, this);
13701 this.updateComplete(response);
13705 updateComplete : function(response){
13706 this.fireEvent("update", this.el, response);
13707 if(typeof response.argument.callback == "function"){
13708 response.argument.callback(this.el, true, response);
13715 processFailure : function(response){
13716 this.transaction = null;
13717 this.fireEvent("failure", this.el, response);
13718 if(typeof response.argument.callback == "function"){
13719 response.argument.callback(this.el, false, response);
13724 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
13725 * @param {Object} renderer The object implementing the render() method
13727 setRenderer : function(renderer){
13728 this.renderer = renderer;
13731 getRenderer : function(){
13732 return this.renderer;
13736 * Set the defaultUrl used for updates
13737 * @param {String/Function} defaultUrl The url or a function to call to get the url
13739 setDefaultUrl : function(defaultUrl){
13740 this.defaultUrl = defaultUrl;
13744 * Aborts the executing transaction
13746 abort : function(){
13747 if(this.transaction){
13748 Roo.Ajax.abort(this.transaction);
13753 * Returns true if an update is in progress
13754 * @return {Boolean}
13756 isUpdating : function(){
13757 if(this.transaction){
13758 return Roo.Ajax.isLoading(this.transaction);
13765 * @class Roo.UpdateManager.defaults
13766 * @static (not really - but it helps the doc tool)
13767 * The defaults collection enables customizing the default properties of UpdateManager
13769 Roo.UpdateManager.defaults = {
13771 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
13777 * True to process scripts by default (Defaults to false).
13780 loadScripts : false,
13783 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
13786 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
13788 * Whether to append unique parameter on get request to disable caching (Defaults to false).
13791 disableCaching : false,
13793 * Whether to show indicatorText when loading (Defaults to true).
13796 showLoadIndicator : true,
13798 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
13801 indicatorText : '<div class="loading-indicator">Loading...</div>'
13805 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
13807 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
13808 * @param {String/HTMLElement/Roo.Element} el The element to update
13809 * @param {String} url The url
13810 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
13811 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
13814 * @member Roo.UpdateManager
13816 Roo.UpdateManager.updateElement = function(el, url, params, options){
13817 var um = Roo.get(el, true).getUpdateManager();
13818 Roo.apply(um, options);
13819 um.update(url, params, options ? options.callback : null);
13821 // alias for backwards compat
13822 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
13824 * @class Roo.UpdateManager.BasicRenderer
13825 * Default Content renderer. Updates the elements innerHTML with the responseText.
13827 Roo.UpdateManager.BasicRenderer = function(){};
13829 Roo.UpdateManager.BasicRenderer.prototype = {
13831 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
13832 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
13833 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
13834 * @param {Roo.Element} el The element being rendered
13835 * @param {Object} response The YUI Connect response object
13836 * @param {UpdateManager} updateManager The calling update manager
13837 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
13839 render : function(el, response, updateManager, callback){
13840 el.update(response.responseText, updateManager.loadScripts, callback);
13846 * (c)) Alan Knowles
13852 * @class Roo.DomTemplate
13853 * @extends Roo.Template
13854 * An effort at a dom based template engine..
13856 * Similar to XTemplate, except it uses dom parsing to create the template..
13858 * Supported features:
13863 {a_variable} - output encoded.
13864 {a_variable.format:("Y-m-d")} - call a method on the variable
13865 {a_variable:raw} - unencoded output
13866 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
13867 {a_variable:this.method_on_template(...)} - call a method on the template object.
13872 <div roo-for="a_variable or condition.."></div>
13873 <div roo-if="a_variable or condition"></div>
13874 <div roo-exec="some javascript"></div>
13875 <div roo-name="named_template"></div>
13880 Roo.DomTemplate = function()
13882 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
13889 Roo.extend(Roo.DomTemplate, Roo.Template, {
13891 * id counter for sub templates.
13895 * flag to indicate if dom parser is inside a pre,
13896 * it will strip whitespace if not.
13901 * The various sub templates
13909 * basic tag replacing syntax
13912 * // you can fake an object call by doing this
13916 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
13917 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
13919 iterChild : function (node, method) {
13921 var oldPre = this.inPre;
13922 if (node.tagName == 'PRE') {
13925 for( var i = 0; i < node.childNodes.length; i++) {
13926 method.call(this, node.childNodes[i]);
13928 this.inPre = oldPre;
13934 * compile the template
13936 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
13939 compile: function()
13943 // covert the html into DOM...
13947 doc = document.implementation.createHTMLDocument("");
13948 doc.documentElement.innerHTML = this.html ;
13949 div = doc.documentElement;
13951 // old IE... - nasty -- it causes all sorts of issues.. with
13952 // images getting pulled from server..
13953 div = document.createElement('div');
13954 div.innerHTML = this.html;
13956 //doc.documentElement.innerHTML = htmlBody
13962 this.iterChild(div, function(n) {_t.compileNode(n, true); });
13964 var tpls = this.tpls;
13966 // create a top level template from the snippet..
13968 //Roo.log(div.innerHTML);
13975 body : div.innerHTML,
13988 Roo.each(tpls, function(tp){
13989 this.compileTpl(tp);
13990 this.tpls[tp.id] = tp;
13993 this.master = tpls[0];
13999 compileNode : function(node, istop) {
14004 // skip anything not a tag..
14005 if (node.nodeType != 1) {
14006 if (node.nodeType == 3 && !this.inPre) {
14007 // reduce white space..
14008 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
14031 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
14032 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
14033 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
14034 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
14040 // just itterate children..
14041 this.iterChild(node,this.compileNode);
14044 tpl.uid = this.id++;
14045 tpl.value = node.getAttribute('roo-' + tpl.attr);
14046 node.removeAttribute('roo-'+ tpl.attr);
14047 if (tpl.attr != 'name') {
14048 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
14049 node.parentNode.replaceChild(placeholder, node);
14052 var placeholder = document.createElement('span');
14053 placeholder.className = 'roo-tpl-' + tpl.value;
14054 node.parentNode.replaceChild(placeholder, node);
14057 // parent now sees '{domtplXXXX}
14058 this.iterChild(node,this.compileNode);
14060 // we should now have node body...
14061 var div = document.createElement('div');
14062 div.appendChild(node);
14064 // this has the unfortunate side effect of converting tagged attributes
14065 // eg. href="{...}" into %7C...%7D
14066 // this has been fixed by searching for those combo's although it's a bit hacky..
14069 tpl.body = div.innerHTML;
14076 switch (tpl.value) {
14077 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
14078 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
14079 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
14084 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
14088 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
14092 tpl.id = tpl.value; // replace non characters???
14098 this.tpls.push(tpl);
14108 * Compile a segment of the template into a 'sub-template'
14114 compileTpl : function(tpl)
14116 var fm = Roo.util.Format;
14117 var useF = this.disableFormats !== true;
14119 var sep = Roo.isGecko ? "+\n" : ",\n";
14121 var undef = function(str) {
14122 Roo.debug && Roo.log("Property not found :" + str);
14126 //Roo.log(tpl.body);
14130 var fn = function(m, lbrace, name, format, args)
14133 //Roo.log(arguments);
14134 args = args ? args.replace(/\\'/g,"'") : args;
14135 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
14136 if (typeof(format) == 'undefined') {
14137 format = 'htmlEncode';
14139 if (format == 'raw' ) {
14143 if(name.substr(0, 6) == 'domtpl'){
14144 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
14147 // build an array of options to determine if value is undefined..
14149 // basically get 'xxxx.yyyy' then do
14150 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
14151 // (function () { Roo.log("Property not found"); return ''; })() :
14156 Roo.each(name.split('.'), function(st) {
14157 lookfor += (lookfor.length ? '.': '') + st;
14158 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
14161 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
14164 if(format && useF){
14166 args = args ? ',' + args : "";
14168 if(format.substr(0, 5) != "this."){
14169 format = "fm." + format + '(';
14171 format = 'this.call("'+ format.substr(5) + '", ';
14175 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
14178 if (args && args.length) {
14179 // called with xxyx.yuu:(test,test)
14181 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
14183 // raw.. - :raw modifier..
14184 return "'"+ sep + udef_st + name + ")"+sep+"'";
14188 // branched to use + in gecko and [].join() in others
14190 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
14191 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
14194 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
14195 body.push(tpl.body.replace(/(\r\n|\n)/g,
14196 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
14197 body.push("'].join('');};};");
14198 body = body.join('');
14201 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
14203 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
14210 * same as applyTemplate, except it's done to one of the subTemplates
14211 * when using named templates, you can do:
14213 * var str = pl.applySubTemplate('your-name', values);
14216 * @param {Number} id of the template
14217 * @param {Object} values to apply to template
14218 * @param {Object} parent (normaly the instance of this object)
14220 applySubTemplate : function(id, values, parent)
14224 var t = this.tpls[id];
14228 if(t.ifCall && !t.ifCall.call(this, values, parent)){
14229 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
14233 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
14240 if(t.execCall && t.execCall.call(this, values, parent)){
14244 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
14250 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
14251 parent = t.target ? values : parent;
14252 if(t.forCall && vs instanceof Array){
14254 for(var i = 0, len = vs.length; i < len; i++){
14256 buf[buf.length] = t.compiled.call(this, vs[i], parent);
14258 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
14260 //Roo.log(t.compiled);
14264 return buf.join('');
14267 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
14272 return t.compiled.call(this, vs, parent);
14274 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
14276 //Roo.log(t.compiled);
14284 applyTemplate : function(values){
14285 return this.master.compiled.call(this, values, {});
14286 //var s = this.subs;
14289 apply : function(){
14290 return this.applyTemplate.apply(this, arguments);
14295 Roo.DomTemplate.from = function(el){
14296 el = Roo.getDom(el);
14297 return new Roo.Domtemplate(el.value || el.innerHTML);
14300 * Ext JS Library 1.1.1
14301 * Copyright(c) 2006-2007, Ext JS, LLC.
14303 * Originally Released Under LGPL - original licence link has changed is not relivant.
14306 * <script type="text/javascript">
14310 * @class Roo.util.DelayedTask
14311 * Provides a convenient method of performing setTimeout where a new
14312 * timeout cancels the old timeout. An example would be performing validation on a keypress.
14313 * You can use this class to buffer
14314 * the keypress events for a certain number of milliseconds, and perform only if they stop
14315 * for that amount of time.
14316 * @constructor The parameters to this constructor serve as defaults and are not required.
14317 * @param {Function} fn (optional) The default function to timeout
14318 * @param {Object} scope (optional) The default scope of that timeout
14319 * @param {Array} args (optional) The default Array of arguments
14321 Roo.util.DelayedTask = function(fn, scope, args){
14322 var id = null, d, t;
14324 var call = function(){
14325 var now = new Date().getTime();
14329 fn.apply(scope, args || []);
14333 * Cancels any pending timeout and queues a new one
14334 * @param {Number} delay The milliseconds to delay
14335 * @param {Function} newFn (optional) Overrides function passed to constructor
14336 * @param {Object} newScope (optional) Overrides scope passed to constructor
14337 * @param {Array} newArgs (optional) Overrides args passed to constructor
14339 this.delay = function(delay, newFn, newScope, newArgs){
14340 if(id && delay != d){
14344 t = new Date().getTime();
14346 scope = newScope || scope;
14347 args = newArgs || args;
14349 id = setInterval(call, d);
14354 * Cancel the last queued timeout
14356 this.cancel = function(){
14364 * Ext JS Library 1.1.1
14365 * Copyright(c) 2006-2007, Ext JS, LLC.
14367 * Originally Released Under LGPL - original licence link has changed is not relivant.
14370 * <script type="text/javascript">
14373 * @class Roo.util.TaskRunner
14374 * Manage background tasks - not sure why this is better that setInterval?
14379 Roo.util.TaskRunner = function(interval){
14380 interval = interval || 10;
14381 var tasks = [], removeQueue = [];
14383 var running = false;
14385 var stopThread = function(){
14391 var startThread = function(){
14394 id = setInterval(runTasks, interval);
14398 var removeTask = function(task){
14399 removeQueue.push(task);
14405 var runTasks = function(){
14406 if(removeQueue.length > 0){
14407 for(var i = 0, len = removeQueue.length; i < len; i++){
14408 tasks.remove(removeQueue[i]);
14411 if(tasks.length < 1){
14416 var now = new Date().getTime();
14417 for(var i = 0, len = tasks.length; i < len; ++i){
14419 var itime = now - t.taskRunTime;
14420 if(t.interval <= itime){
14421 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
14422 t.taskRunTime = now;
14423 if(rt === false || t.taskRunCount === t.repeat){
14428 if(t.duration && t.duration <= (now - t.taskStartTime)){
14435 * Queues a new task.
14436 * @param {Object} task
14438 * Task property : interval = how frequent to run.
14439 * Task object should implement
14441 * Task object may implement
14442 * function onStop()
14444 this.start = function(task){
14446 task.taskStartTime = new Date().getTime();
14447 task.taskRunTime = 0;
14448 task.taskRunCount = 0;
14454 * @param {Object} task
14456 this.stop = function(task){
14463 this.stopAll = function(){
14465 for(var i = 0, len = tasks.length; i < len; i++){
14466 if(tasks[i].onStop){
14475 Roo.TaskMgr = new Roo.util.TaskRunner();/*
14477 * Ext JS Library 1.1.1
14478 * Copyright(c) 2006-2007, Ext JS, LLC.
14480 * Originally Released Under LGPL - original licence link has changed is not relivant.
14483 * <script type="text/javascript">
14488 * @class Roo.util.MixedCollection
14489 * @extends Roo.util.Observable
14490 * A Collection class that maintains both numeric indexes and keys and exposes events.
14492 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
14493 * collection (defaults to false)
14494 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
14495 * and return the key value for that item. This is used when available to look up the key on items that
14496 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
14497 * equivalent to providing an implementation for the {@link #getKey} method.
14499 Roo.util.MixedCollection = function(allowFunctions, keyFn){
14507 * Fires when the collection is cleared.
14512 * Fires when an item is added to the collection.
14513 * @param {Number} index The index at which the item was added.
14514 * @param {Object} o The item added.
14515 * @param {String} key The key associated with the added item.
14520 * Fires when an item is replaced in the collection.
14521 * @param {String} key he key associated with the new added.
14522 * @param {Object} old The item being replaced.
14523 * @param {Object} new The new item.
14528 * Fires when an item is removed from the collection.
14529 * @param {Object} o The item being removed.
14530 * @param {String} key (optional) The key associated with the removed item.
14535 this.allowFunctions = allowFunctions === true;
14537 this.getKey = keyFn;
14539 Roo.util.MixedCollection.superclass.constructor.call(this);
14542 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
14543 allowFunctions : false,
14546 * Adds an item to the collection.
14547 * @param {String} key The key to associate with the item
14548 * @param {Object} o The item to add.
14549 * @return {Object} The item added.
14551 add : function(key, o){
14552 if(arguments.length == 1){
14554 key = this.getKey(o);
14556 if(typeof key == "undefined" || key === null){
14558 this.items.push(o);
14559 this.keys.push(null);
14561 var old = this.map[key];
14563 return this.replace(key, o);
14566 this.items.push(o);
14568 this.keys.push(key);
14570 this.fireEvent("add", this.length-1, o, key);
14575 * MixedCollection has a generic way to fetch keys if you implement getKey.
14578 var mc = new Roo.util.MixedCollection();
14579 mc.add(someEl.dom.id, someEl);
14580 mc.add(otherEl.dom.id, otherEl);
14584 var mc = new Roo.util.MixedCollection();
14585 mc.getKey = function(el){
14591 // or via the constructor
14592 var mc = new Roo.util.MixedCollection(false, function(el){
14598 * @param o {Object} The item for which to find the key.
14599 * @return {Object} The key for the passed item.
14601 getKey : function(o){
14606 * Replaces an item in the collection.
14607 * @param {String} key The key associated with the item to replace, or the item to replace.
14608 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
14609 * @return {Object} The new item.
14611 replace : function(key, o){
14612 if(arguments.length == 1){
14614 key = this.getKey(o);
14616 var old = this.item(key);
14617 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
14618 return this.add(key, o);
14620 var index = this.indexOfKey(key);
14621 this.items[index] = o;
14623 this.fireEvent("replace", key, old, o);
14628 * Adds all elements of an Array or an Object to the collection.
14629 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
14630 * an Array of values, each of which are added to the collection.
14632 addAll : function(objs){
14633 if(arguments.length > 1 || objs instanceof Array){
14634 var args = arguments.length > 1 ? arguments : objs;
14635 for(var i = 0, len = args.length; i < len; i++){
14639 for(var key in objs){
14640 if(this.allowFunctions || typeof objs[key] != "function"){
14641 this.add(key, objs[key]);
14648 * Executes the specified function once for every item in the collection, passing each
14649 * item as the first and only parameter. returning false from the function will stop the iteration.
14650 * @param {Function} fn The function to execute for each item.
14651 * @param {Object} scope (optional) The scope in which to execute the function.
14653 each : function(fn, scope){
14654 var items = [].concat(this.items); // each safe for removal
14655 for(var i = 0, len = items.length; i < len; i++){
14656 if(fn.call(scope || items[i], items[i], i, len) === false){
14663 * Executes the specified function once for every key in the collection, passing each
14664 * key, and its associated item as the first two parameters.
14665 * @param {Function} fn The function to execute for each item.
14666 * @param {Object} scope (optional) The scope in which to execute the function.
14668 eachKey : function(fn, scope){
14669 for(var i = 0, len = this.keys.length; i < len; i++){
14670 fn.call(scope || window, this.keys[i], this.items[i], i, len);
14675 * Returns the first item in the collection which elicits a true return value from the
14676 * passed selection function.
14677 * @param {Function} fn The selection function to execute for each item.
14678 * @param {Object} scope (optional) The scope in which to execute the function.
14679 * @return {Object} The first item in the collection which returned true from the selection function.
14681 find : function(fn, scope){
14682 for(var i = 0, len = this.items.length; i < len; i++){
14683 if(fn.call(scope || window, this.items[i], this.keys[i])){
14684 return this.items[i];
14691 * Inserts an item at the specified index in the collection.
14692 * @param {Number} index The index to insert the item at.
14693 * @param {String} key The key to associate with the new item, or the item itself.
14694 * @param {Object} o (optional) If the second parameter was a key, the new item.
14695 * @return {Object} The item inserted.
14697 insert : function(index, key, o){
14698 if(arguments.length == 2){
14700 key = this.getKey(o);
14702 if(index >= this.length){
14703 return this.add(key, o);
14706 this.items.splice(index, 0, o);
14707 if(typeof key != "undefined" && key != null){
14710 this.keys.splice(index, 0, key);
14711 this.fireEvent("add", index, o, key);
14716 * Removed an item from the collection.
14717 * @param {Object} o The item to remove.
14718 * @return {Object} The item removed.
14720 remove : function(o){
14721 return this.removeAt(this.indexOf(o));
14725 * Remove an item from a specified index in the collection.
14726 * @param {Number} index The index within the collection of the item to remove.
14728 removeAt : function(index){
14729 if(index < this.length && index >= 0){
14731 var o = this.items[index];
14732 this.items.splice(index, 1);
14733 var key = this.keys[index];
14734 if(typeof key != "undefined"){
14735 delete this.map[key];
14737 this.keys.splice(index, 1);
14738 this.fireEvent("remove", o, key);
14743 * Removed an item associated with the passed key fom the collection.
14744 * @param {String} key The key of the item to remove.
14746 removeKey : function(key){
14747 return this.removeAt(this.indexOfKey(key));
14751 * Returns the number of items in the collection.
14752 * @return {Number} the number of items in the collection.
14754 getCount : function(){
14755 return this.length;
14759 * Returns index within the collection of the passed Object.
14760 * @param {Object} o The item to find the index of.
14761 * @return {Number} index of the item.
14763 indexOf : function(o){
14764 if(!this.items.indexOf){
14765 for(var i = 0, len = this.items.length; i < len; i++){
14766 if(this.items[i] == o) {
14772 return this.items.indexOf(o);
14777 * Returns index within the collection of the passed key.
14778 * @param {String} key The key to find the index of.
14779 * @return {Number} index of the key.
14781 indexOfKey : function(key){
14782 if(!this.keys.indexOf){
14783 for(var i = 0, len = this.keys.length; i < len; i++){
14784 if(this.keys[i] == key) {
14790 return this.keys.indexOf(key);
14795 * Returns the item associated with the passed key OR index. Key has priority over index.
14796 * @param {String/Number} key The key or index of the item.
14797 * @return {Object} The item associated with the passed key.
14799 item : function(key){
14800 if (key === 'length') {
14803 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
14804 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
14808 * Returns the item at the specified index.
14809 * @param {Number} index The index of the item.
14812 itemAt : function(index){
14813 return this.items[index];
14817 * Returns the item associated with the passed key.
14818 * @param {String/Number} key The key of the item.
14819 * @return {Object} The item associated with the passed key.
14821 key : function(key){
14822 return this.map[key];
14826 * Returns true if the collection contains the passed Object as an item.
14827 * @param {Object} o The Object to look for in the collection.
14828 * @return {Boolean} True if the collection contains the Object as an item.
14830 contains : function(o){
14831 return this.indexOf(o) != -1;
14835 * Returns true if the collection contains the passed Object as a key.
14836 * @param {String} key The key to look for in the collection.
14837 * @return {Boolean} True if the collection contains the Object as a key.
14839 containsKey : function(key){
14840 return typeof this.map[key] != "undefined";
14844 * Removes all items from the collection.
14846 clear : function(){
14851 this.fireEvent("clear");
14855 * Returns the first item in the collection.
14856 * @return {Object} the first item in the collection..
14858 first : function(){
14859 return this.items[0];
14863 * Returns the last item in the collection.
14864 * @return {Object} the last item in the collection..
14867 return this.items[this.length-1];
14870 _sort : function(property, dir, fn){
14871 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
14872 fn = fn || function(a, b){
14875 var c = [], k = this.keys, items = this.items;
14876 for(var i = 0, len = items.length; i < len; i++){
14877 c[c.length] = {key: k[i], value: items[i], index: i};
14879 c.sort(function(a, b){
14880 var v = fn(a[property], b[property]) * dsc;
14882 v = (a.index < b.index ? -1 : 1);
14886 for(var i = 0, len = c.length; i < len; i++){
14887 items[i] = c[i].value;
14890 this.fireEvent("sort", this);
14894 * Sorts this collection with the passed comparison function
14895 * @param {String} direction (optional) "ASC" or "DESC"
14896 * @param {Function} fn (optional) comparison function
14898 sort : function(dir, fn){
14899 this._sort("value", dir, fn);
14903 * Sorts this collection by keys
14904 * @param {String} direction (optional) "ASC" or "DESC"
14905 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
14907 keySort : function(dir, fn){
14908 this._sort("key", dir, fn || function(a, b){
14909 return String(a).toUpperCase()-String(b).toUpperCase();
14914 * Returns a range of items in this collection
14915 * @param {Number} startIndex (optional) defaults to 0
14916 * @param {Number} endIndex (optional) default to the last item
14917 * @return {Array} An array of items
14919 getRange : function(start, end){
14920 var items = this.items;
14921 if(items.length < 1){
14924 start = start || 0;
14925 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
14928 for(var i = start; i <= end; i++) {
14929 r[r.length] = items[i];
14932 for(var i = start; i >= end; i--) {
14933 r[r.length] = items[i];
14940 * Filter the <i>objects</i> in this collection by a specific property.
14941 * Returns a new collection that has been filtered.
14942 * @param {String} property A property on your objects
14943 * @param {String/RegExp} value Either string that the property values
14944 * should start with or a RegExp to test against the property
14945 * @return {MixedCollection} The new filtered collection
14947 filter : function(property, value){
14948 if(!value.exec){ // not a regex
14949 value = String(value);
14950 if(value.length == 0){
14951 return this.clone();
14953 value = new RegExp("^" + Roo.escapeRe(value), "i");
14955 return this.filterBy(function(o){
14956 return o && value.test(o[property]);
14961 * Filter by a function. * Returns a new collection that has been filtered.
14962 * The passed function will be called with each
14963 * object in the collection. If the function returns true, the value is included
14964 * otherwise it is filtered.
14965 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
14966 * @param {Object} scope (optional) The scope of the function (defaults to this)
14967 * @return {MixedCollection} The new filtered collection
14969 filterBy : function(fn, scope){
14970 var r = new Roo.util.MixedCollection();
14971 r.getKey = this.getKey;
14972 var k = this.keys, it = this.items;
14973 for(var i = 0, len = it.length; i < len; i++){
14974 if(fn.call(scope||this, it[i], k[i])){
14975 r.add(k[i], it[i]);
14982 * Creates a duplicate of this collection
14983 * @return {MixedCollection}
14985 clone : function(){
14986 var r = new Roo.util.MixedCollection();
14987 var k = this.keys, it = this.items;
14988 for(var i = 0, len = it.length; i < len; i++){
14989 r.add(k[i], it[i]);
14991 r.getKey = this.getKey;
14996 * Returns the item associated with the passed key or index.
14998 * @param {String/Number} key The key or index of the item.
14999 * @return {Object} The item associated with the passed key.
15001 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
15003 * Ext JS Library 1.1.1
15004 * Copyright(c) 2006-2007, Ext JS, LLC.
15006 * Originally Released Under LGPL - original licence link has changed is not relivant.
15009 * <script type="text/javascript">
15012 * @class Roo.util.JSON
15013 * Modified version of Douglas Crockford"s json.js that doesn"t
15014 * mess with the Object prototype
15015 * http://www.json.org/js.html
15018 Roo.util.JSON = new (function(){
15019 var useHasOwn = {}.hasOwnProperty ? true : false;
15021 // crashes Safari in some instances
15022 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
15024 var pad = function(n) {
15025 return n < 10 ? "0" + n : n;
15038 var encodeString = function(s){
15039 if (/["\\\x00-\x1f]/.test(s)) {
15040 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
15045 c = b.charCodeAt();
15047 Math.floor(c / 16).toString(16) +
15048 (c % 16).toString(16);
15051 return '"' + s + '"';
15054 var encodeArray = function(o){
15055 var a = ["["], b, i, l = o.length, v;
15056 for (i = 0; i < l; i += 1) {
15058 switch (typeof v) {
15067 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
15075 var encodeDate = function(o){
15076 return '"' + o.getFullYear() + "-" +
15077 pad(o.getMonth() + 1) + "-" +
15078 pad(o.getDate()) + "T" +
15079 pad(o.getHours()) + ":" +
15080 pad(o.getMinutes()) + ":" +
15081 pad(o.getSeconds()) + '"';
15085 * Encodes an Object, Array or other value
15086 * @param {Mixed} o The variable to encode
15087 * @return {String} The JSON string
15089 this.encode = function(o)
15091 // should this be extended to fully wrap stringify..
15093 if(typeof o == "undefined" || o === null){
15095 }else if(o instanceof Array){
15096 return encodeArray(o);
15097 }else if(o instanceof Date){
15098 return encodeDate(o);
15099 }else if(typeof o == "string"){
15100 return encodeString(o);
15101 }else if(typeof o == "number"){
15102 return isFinite(o) ? String(o) : "null";
15103 }else if(typeof o == "boolean"){
15106 var a = ["{"], b, i, v;
15108 if(!useHasOwn || o.hasOwnProperty(i)) {
15110 switch (typeof v) {
15119 a.push(this.encode(i), ":",
15120 v === null ? "null" : this.encode(v));
15131 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
15132 * @param {String} json The JSON string
15133 * @return {Object} The resulting object
15135 this.decode = function(json){
15137 return /** eval:var:json */ eval("(" + json + ')');
15141 * Shorthand for {@link Roo.util.JSON#encode}
15142 * @member Roo encode
15144 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
15146 * Shorthand for {@link Roo.util.JSON#decode}
15147 * @member Roo decode
15149 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
15152 * Ext JS Library 1.1.1
15153 * Copyright(c) 2006-2007, Ext JS, LLC.
15155 * Originally Released Under LGPL - original licence link has changed is not relivant.
15158 * <script type="text/javascript">
15162 * @class Roo.util.Format
15163 * Reusable data formatting functions
15166 Roo.util.Format = function(){
15167 var trimRe = /^\s+|\s+$/g;
15170 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
15171 * @param {String} value The string to truncate
15172 * @param {Number} length The maximum length to allow before truncating
15173 * @return {String} The converted text
15175 ellipsis : function(value, len){
15176 if(value && value.length > len){
15177 return value.substr(0, len-3)+"...";
15183 * Checks a reference and converts it to empty string if it is undefined
15184 * @param {Mixed} value Reference to check
15185 * @return {Mixed} Empty string if converted, otherwise the original value
15187 undef : function(value){
15188 return typeof value != "undefined" ? value : "";
15192 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
15193 * @param {String} value The string to encode
15194 * @return {String} The encoded text
15196 htmlEncode : function(value){
15197 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
15201 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
15202 * @param {String} value The string to decode
15203 * @return {String} The decoded text
15205 htmlDecode : function(value){
15206 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
15210 * Trims any whitespace from either side of a string
15211 * @param {String} value The text to trim
15212 * @return {String} The trimmed text
15214 trim : function(value){
15215 return String(value).replace(trimRe, "");
15219 * Returns a substring from within an original string
15220 * @param {String} value The original text
15221 * @param {Number} start The start index of the substring
15222 * @param {Number} length The length of the substring
15223 * @return {String} The substring
15225 substr : function(value, start, length){
15226 return String(value).substr(start, length);
15230 * Converts a string to all lower case letters
15231 * @param {String} value The text to convert
15232 * @return {String} The converted text
15234 lowercase : function(value){
15235 return String(value).toLowerCase();
15239 * Converts a string to all upper case letters
15240 * @param {String} value The text to convert
15241 * @return {String} The converted text
15243 uppercase : function(value){
15244 return String(value).toUpperCase();
15248 * Converts the first character only of a string to upper case
15249 * @param {String} value The text to convert
15250 * @return {String} The converted text
15252 capitalize : function(value){
15253 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
15257 call : function(value, fn){
15258 if(arguments.length > 2){
15259 var args = Array.prototype.slice.call(arguments, 2);
15260 args.unshift(value);
15262 return /** eval:var:value */ eval(fn).apply(window, args);
15264 /** eval:var:value */
15265 return /** eval:var:value */ eval(fn).call(window, value);
15271 * safer version of Math.toFixed..??/
15272 * @param {Number/String} value The numeric value to format
15273 * @param {Number/String} value Decimal places
15274 * @return {String} The formatted currency string
15276 toFixed : function(v, n)
15278 // why not use to fixed - precision is buggered???
15280 return Math.round(v-0);
15282 var fact = Math.pow(10,n+1);
15283 v = (Math.round((v-0)*fact))/fact;
15284 var z = (''+fact).substring(2);
15285 if (v == Math.floor(v)) {
15286 return Math.floor(v) + '.' + z;
15289 // now just padd decimals..
15290 var ps = String(v).split('.');
15291 var fd = (ps[1] + z);
15292 var r = fd.substring(0,n);
15293 var rm = fd.substring(n);
15295 return ps[0] + '.' + r;
15297 r*=1; // turn it into a number;
15299 if (String(r).length != n) {
15302 r = String(r).substring(1); // chop the end off.
15305 return ps[0] + '.' + r;
15310 * Format a number as US currency
15311 * @param {Number/String} value The numeric value to format
15312 * @return {String} The formatted currency string
15314 usMoney : function(v){
15315 return '$' + Roo.util.Format.number(v);
15320 * eventually this should probably emulate php's number_format
15321 * @param {Number/String} value The numeric value to format
15322 * @param {Number} decimals number of decimal places
15323 * @param {String} delimiter for thousands (default comma)
15324 * @return {String} The formatted currency string
15326 number : function(v, decimals, thousandsDelimiter)
15328 // multiply and round.
15329 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
15330 thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
15332 var mul = Math.pow(10, decimals);
15333 var zero = String(mul).substring(1);
15334 v = (Math.round((v-0)*mul))/mul;
15336 // if it's '0' number.. then
15338 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
15340 var ps = v.split('.');
15343 var r = /(\d+)(\d{3})/;
15346 if(thousandsDelimiter.length != 0) {
15347 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
15352 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
15353 // does not have decimals
15354 (decimals ? ('.' + zero) : '');
15357 return whole + sub ;
15361 * Parse a value into a formatted date using the specified format pattern.
15362 * @param {Mixed} value The value to format
15363 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
15364 * @return {String} The formatted date string
15366 date : function(v, format){
15370 if(!(v instanceof Date)){
15371 v = new Date(Date.parse(v));
15373 return v.dateFormat(format || Roo.util.Format.defaults.date);
15377 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
15378 * @param {String} format Any valid date format string
15379 * @return {Function} The date formatting function
15381 dateRenderer : function(format){
15382 return function(v){
15383 return Roo.util.Format.date(v, format);
15388 stripTagsRE : /<\/?[^>]+>/gi,
15391 * Strips all HTML tags
15392 * @param {Mixed} value The text from which to strip tags
15393 * @return {String} The stripped text
15395 stripTags : function(v){
15396 return !v ? v : String(v).replace(this.stripTagsRE, "");
15400 * Size in Mb,Gb etc.
15401 * @param {Number} value The number to be formated
15402 * @param {number} decimals how many decimal places
15403 * @return {String} the formated string
15405 size : function(value, decimals)
15407 var sizes = ['b', 'k', 'M', 'G', 'T'];
15411 var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
15412 return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals) + sizes[i];
15419 Roo.util.Format.defaults = {
15423 * Ext JS Library 1.1.1
15424 * Copyright(c) 2006-2007, Ext JS, LLC.
15426 * Originally Released Under LGPL - original licence link has changed is not relivant.
15429 * <script type="text/javascript">
15436 * @class Roo.MasterTemplate
15437 * @extends Roo.Template
15438 * Provides a template that can have child templates. The syntax is:
15440 var t = new Roo.MasterTemplate(
15441 '<select name="{name}">',
15442 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
15445 t.add('options', {value: 'foo', text: 'bar'});
15446 // or you can add multiple child elements in one shot
15447 t.addAll('options', [
15448 {value: 'foo', text: 'bar'},
15449 {value: 'foo2', text: 'bar2'},
15450 {value: 'foo3', text: 'bar3'}
15452 // then append, applying the master template values
15453 t.append('my-form', {name: 'my-select'});
15455 * A name attribute for the child template is not required if you have only one child
15456 * template or you want to refer to them by index.
15458 Roo.MasterTemplate = function(){
15459 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
15460 this.originalHtml = this.html;
15462 var m, re = this.subTemplateRe;
15465 while(m = re.exec(this.html)){
15466 var name = m[1], content = m[2];
15471 tpl : new Roo.Template(content)
15474 st[name] = st[subIndex];
15476 st[subIndex].tpl.compile();
15477 st[subIndex].tpl.call = this.call.createDelegate(this);
15480 this.subCount = subIndex;
15483 Roo.extend(Roo.MasterTemplate, Roo.Template, {
15485 * The regular expression used to match sub templates
15489 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
15492 * Applies the passed values to a child template.
15493 * @param {String/Number} name (optional) The name or index of the child template
15494 * @param {Array/Object} values The values to be applied to the template
15495 * @return {MasterTemplate} this
15497 add : function(name, values){
15498 if(arguments.length == 1){
15499 values = arguments[0];
15502 var s = this.subs[name];
15503 s.buffer[s.buffer.length] = s.tpl.apply(values);
15508 * Applies all the passed values to a child template.
15509 * @param {String/Number} name (optional) The name or index of the child template
15510 * @param {Array} values The values to be applied to the template, this should be an array of objects.
15511 * @param {Boolean} reset (optional) True to reset the template first
15512 * @return {MasterTemplate} this
15514 fill : function(name, values, reset){
15516 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
15524 for(var i = 0, len = values.length; i < len; i++){
15525 this.add(name, values[i]);
15531 * Resets the template for reuse
15532 * @return {MasterTemplate} this
15534 reset : function(){
15536 for(var i = 0; i < this.subCount; i++){
15542 applyTemplate : function(values){
15544 var replaceIndex = -1;
15545 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
15546 return s[++replaceIndex].buffer.join("");
15548 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
15551 apply : function(){
15552 return this.applyTemplate.apply(this, arguments);
15555 compile : function(){return this;}
15559 * Alias for fill().
15562 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
15564 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
15565 * var tpl = Roo.MasterTemplate.from('element-id');
15566 * @param {String/HTMLElement} el
15567 * @param {Object} config
15570 Roo.MasterTemplate.from = function(el, config){
15571 el = Roo.getDom(el);
15572 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
15575 * Ext JS Library 1.1.1
15576 * Copyright(c) 2006-2007, Ext JS, LLC.
15578 * Originally Released Under LGPL - original licence link has changed is not relivant.
15581 * <script type="text/javascript">
15586 * @class Roo.util.CSS
15587 * Utility class for manipulating CSS rules
15591 Roo.util.CSS = function(){
15593 var doc = document;
15595 var camelRe = /(-[a-z])/gi;
15596 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
15600 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
15601 * tag and appended to the HEAD of the document.
15602 * @param {String|Object} cssText The text containing the css rules
15603 * @param {String} id An id to add to the stylesheet for later removal
15604 * @return {StyleSheet}
15606 createStyleSheet : function(cssText, id){
15608 var head = doc.getElementsByTagName("head")[0];
15609 var nrules = doc.createElement("style");
15610 nrules.setAttribute("type", "text/css");
15612 nrules.setAttribute("id", id);
15614 if (typeof(cssText) != 'string') {
15615 // support object maps..
15616 // not sure if this a good idea..
15617 // perhaps it should be merged with the general css handling
15618 // and handle js style props.
15619 var cssTextNew = [];
15620 for(var n in cssText) {
15622 for(var k in cssText[n]) {
15623 citems.push( k + ' : ' +cssText[n][k] + ';' );
15625 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
15628 cssText = cssTextNew.join("\n");
15634 head.appendChild(nrules);
15635 ss = nrules.styleSheet;
15636 ss.cssText = cssText;
15639 nrules.appendChild(doc.createTextNode(cssText));
15641 nrules.cssText = cssText;
15643 head.appendChild(nrules);
15644 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
15646 this.cacheStyleSheet(ss);
15651 * Removes a style or link tag by id
15652 * @param {String} id The id of the tag
15654 removeStyleSheet : function(id){
15655 var existing = doc.getElementById(id);
15657 existing.parentNode.removeChild(existing);
15662 * Dynamically swaps an existing stylesheet reference for a new one
15663 * @param {String} id The id of an existing link tag to remove
15664 * @param {String} url The href of the new stylesheet to include
15666 swapStyleSheet : function(id, url){
15667 this.removeStyleSheet(id);
15668 var ss = doc.createElement("link");
15669 ss.setAttribute("rel", "stylesheet");
15670 ss.setAttribute("type", "text/css");
15671 ss.setAttribute("id", id);
15672 ss.setAttribute("href", url);
15673 doc.getElementsByTagName("head")[0].appendChild(ss);
15677 * Refresh the rule cache if you have dynamically added stylesheets
15678 * @return {Object} An object (hash) of rules indexed by selector
15680 refreshCache : function(){
15681 return this.getRules(true);
15685 cacheStyleSheet : function(stylesheet){
15689 try{// try catch for cross domain access issue
15690 var ssRules = stylesheet.cssRules || stylesheet.rules;
15691 for(var j = ssRules.length-1; j >= 0; --j){
15692 rules[ssRules[j].selectorText] = ssRules[j];
15698 * Gets all css rules for the document
15699 * @param {Boolean} refreshCache true to refresh the internal cache
15700 * @return {Object} An object (hash) of rules indexed by selector
15702 getRules : function(refreshCache){
15703 if(rules == null || refreshCache){
15705 var ds = doc.styleSheets;
15706 for(var i =0, len = ds.length; i < len; i++){
15708 this.cacheStyleSheet(ds[i]);
15716 * Gets an an individual CSS rule by selector(s)
15717 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
15718 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
15719 * @return {CSSRule} The CSS rule or null if one is not found
15721 getRule : function(selector, refreshCache){
15722 var rs = this.getRules(refreshCache);
15723 if(!(selector instanceof Array)){
15724 return rs[selector];
15726 for(var i = 0; i < selector.length; i++){
15727 if(rs[selector[i]]){
15728 return rs[selector[i]];
15736 * Updates a rule property
15737 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
15738 * @param {String} property The css property
15739 * @param {String} value The new value for the property
15740 * @return {Boolean} true If a rule was found and updated
15742 updateRule : function(selector, property, value){
15743 if(!(selector instanceof Array)){
15744 var rule = this.getRule(selector);
15746 rule.style[property.replace(camelRe, camelFn)] = value;
15750 for(var i = 0; i < selector.length; i++){
15751 if(this.updateRule(selector[i], property, value)){
15761 * Ext JS Library 1.1.1
15762 * Copyright(c) 2006-2007, Ext JS, LLC.
15764 * Originally Released Under LGPL - original licence link has changed is not relivant.
15767 * <script type="text/javascript">
15773 * @class Roo.util.ClickRepeater
15774 * @extends Roo.util.Observable
15776 * A wrapper class which can be applied to any element. Fires a "click" event while the
15777 * mouse is pressed. The interval between firings may be specified in the config but
15778 * defaults to 10 milliseconds.
15780 * Optionally, a CSS class may be applied to the element during the time it is pressed.
15782 * @cfg {String/HTMLElement/Element} el The element to act as a button.
15783 * @cfg {Number} delay The initial delay before the repeating event begins firing.
15784 * Similar to an autorepeat key delay.
15785 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
15786 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
15787 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
15788 * "interval" and "delay" are ignored. "immediate" is honored.
15789 * @cfg {Boolean} preventDefault True to prevent the default click event
15790 * @cfg {Boolean} stopDefault True to stop the default click event
15793 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
15794 * 2007-02-02 jvs Renamed to ClickRepeater
15795 * 2007-02-03 jvs Modifications for FF Mac and Safari
15798 * @param {String/HTMLElement/Element} el The element to listen on
15799 * @param {Object} config
15801 Roo.util.ClickRepeater = function(el, config)
15803 this.el = Roo.get(el);
15804 this.el.unselectable();
15806 Roo.apply(this, config);
15811 * Fires when the mouse button is depressed.
15812 * @param {Roo.util.ClickRepeater} this
15814 "mousedown" : true,
15817 * Fires on a specified interval during the time the element is pressed.
15818 * @param {Roo.util.ClickRepeater} this
15823 * Fires when the mouse key is released.
15824 * @param {Roo.util.ClickRepeater} this
15829 this.el.on("mousedown", this.handleMouseDown, this);
15830 if(this.preventDefault || this.stopDefault){
15831 this.el.on("click", function(e){
15832 if(this.preventDefault){
15833 e.preventDefault();
15835 if(this.stopDefault){
15841 // allow inline handler
15843 this.on("click", this.handler, this.scope || this);
15846 Roo.util.ClickRepeater.superclass.constructor.call(this);
15849 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
15852 preventDefault : true,
15853 stopDefault : false,
15857 handleMouseDown : function(){
15858 clearTimeout(this.timer);
15860 if(this.pressClass){
15861 this.el.addClass(this.pressClass);
15863 this.mousedownTime = new Date();
15865 Roo.get(document).on("mouseup", this.handleMouseUp, this);
15866 this.el.on("mouseout", this.handleMouseOut, this);
15868 this.fireEvent("mousedown", this);
15869 this.fireEvent("click", this);
15871 this.timer = this.click.defer(this.delay || this.interval, this);
15875 click : function(){
15876 this.fireEvent("click", this);
15877 this.timer = this.click.defer(this.getInterval(), this);
15881 getInterval: function(){
15882 if(!this.accelerate){
15883 return this.interval;
15885 var pressTime = this.mousedownTime.getElapsed();
15886 if(pressTime < 500){
15888 }else if(pressTime < 1700){
15890 }else if(pressTime < 2600){
15892 }else if(pressTime < 3500){
15894 }else if(pressTime < 4400){
15896 }else if(pressTime < 5300){
15898 }else if(pressTime < 6200){
15906 handleMouseOut : function(){
15907 clearTimeout(this.timer);
15908 if(this.pressClass){
15909 this.el.removeClass(this.pressClass);
15911 this.el.on("mouseover", this.handleMouseReturn, this);
15915 handleMouseReturn : function(){
15916 this.el.un("mouseover", this.handleMouseReturn);
15917 if(this.pressClass){
15918 this.el.addClass(this.pressClass);
15924 handleMouseUp : function(){
15925 clearTimeout(this.timer);
15926 this.el.un("mouseover", this.handleMouseReturn);
15927 this.el.un("mouseout", this.handleMouseOut);
15928 Roo.get(document).un("mouseup", this.handleMouseUp);
15929 this.el.removeClass(this.pressClass);
15930 this.fireEvent("mouseup", this);
15933 * @class Roo.util.Clipboard
15939 Roo.util.Clipboard = {
15941 * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
15942 * @param {String} text to copy to clipboard
15944 write : function(text) {
15945 // navigator clipboard api needs a secure context (https)
15946 if (navigator.clipboard && window.isSecureContext) {
15947 // navigator clipboard api method'
15948 navigator.clipboard.writeText(text);
15951 // text area method
15952 var ta = document.createElement("textarea");
15954 // make the textarea out of viewport
15955 ta.style.position = "fixed";
15956 ta.style.left = "-999999px";
15957 ta.style.top = "-999999px";
15958 document.body.appendChild(ta);
15961 document.execCommand('copy');
15971 * Ext JS Library 1.1.1
15972 * Copyright(c) 2006-2007, Ext JS, LLC.
15974 * Originally Released Under LGPL - original licence link has changed is not relivant.
15977 * <script type="text/javascript">
15982 * @class Roo.KeyNav
15983 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
15984 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
15985 * way to implement custom navigation schemes for any UI component.</p>
15986 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
15987 * pageUp, pageDown, del, home, end. Usage:</p>
15989 var nav = new Roo.KeyNav("my-element", {
15990 "left" : function(e){
15991 this.moveLeft(e.ctrlKey);
15993 "right" : function(e){
15994 this.moveRight(e.ctrlKey);
15996 "enter" : function(e){
16003 * @param {String/HTMLElement/Roo.Element} el The element to bind to
16004 * @param {Object} config The config
16006 Roo.KeyNav = function(el, config){
16007 this.el = Roo.get(el);
16008 Roo.apply(this, config);
16009 if(!this.disabled){
16010 this.disabled = true;
16015 Roo.KeyNav.prototype = {
16017 * @cfg {Boolean} disabled
16018 * True to disable this KeyNav instance (defaults to false)
16022 * @cfg {String} defaultEventAction
16023 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
16024 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
16025 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
16027 defaultEventAction: "stopEvent",
16029 * @cfg {Boolean} forceKeyDown
16030 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
16031 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
16032 * handle keydown instead of keypress.
16034 forceKeyDown : false,
16037 prepareEvent : function(e){
16038 var k = e.getKey();
16039 var h = this.keyToHandler[k];
16040 //if(h && this[h]){
16041 // e.stopPropagation();
16043 if(Roo.isSafari && h && k >= 37 && k <= 40){
16049 relay : function(e){
16050 var k = e.getKey();
16051 var h = this.keyToHandler[k];
16053 if(this.doRelay(e, this[h], h) !== true){
16054 e[this.defaultEventAction]();
16060 doRelay : function(e, h, hname){
16061 return h.call(this.scope || this, e);
16064 // possible handlers
16078 // quick lookup hash
16095 * Enable this KeyNav
16097 enable: function(){
16099 // ie won't do special keys on keypress, no one else will repeat keys with keydown
16100 // the EventObject will normalize Safari automatically
16101 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
16102 this.el.on("keydown", this.relay, this);
16104 this.el.on("keydown", this.prepareEvent, this);
16105 this.el.on("keypress", this.relay, this);
16107 this.disabled = false;
16112 * Disable this KeyNav
16114 disable: function(){
16115 if(!this.disabled){
16116 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
16117 this.el.un("keydown", this.relay);
16119 this.el.un("keydown", this.prepareEvent);
16120 this.el.un("keypress", this.relay);
16122 this.disabled = true;
16127 * Ext JS Library 1.1.1
16128 * Copyright(c) 2006-2007, Ext JS, LLC.
16130 * Originally Released Under LGPL - original licence link has changed is not relivant.
16133 * <script type="text/javascript">
16138 * @class Roo.KeyMap
16139 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
16140 * The constructor accepts the same config object as defined by {@link #addBinding}.
16141 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
16142 * combination it will call the function with this signature (if the match is a multi-key
16143 * combination the callback will still be called only once): (String key, Roo.EventObject e)
16144 * A KeyMap can also handle a string representation of keys.<br />
16147 // map one key by key code
16148 var map = new Roo.KeyMap("my-element", {
16149 key: 13, // or Roo.EventObject.ENTER
16154 // map multiple keys to one action by string
16155 var map = new Roo.KeyMap("my-element", {
16161 // map multiple keys to multiple actions by strings and array of codes
16162 var map = new Roo.KeyMap("my-element", [
16165 fn: function(){ alert("Return was pressed"); }
16168 fn: function(){ alert('a, b or c was pressed'); }
16173 fn: function(){ alert('Control + shift + tab was pressed.'); }
16177 * <b>Note: A KeyMap starts enabled</b>
16179 * @param {String/HTMLElement/Roo.Element} el The element to bind to
16180 * @param {Object} config The config (see {@link #addBinding})
16181 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
16183 Roo.KeyMap = function(el, config, eventName){
16184 this.el = Roo.get(el);
16185 this.eventName = eventName || "keydown";
16186 this.bindings = [];
16188 this.addBinding(config);
16193 Roo.KeyMap.prototype = {
16195 * True to stop the event from bubbling and prevent the default browser action if the
16196 * key was handled by the KeyMap (defaults to false)
16202 * Add a new binding to this KeyMap. The following config object properties are supported:
16204 Property Type Description
16205 ---------- --------------- ----------------------------------------------------------------------
16206 key String/Array A single keycode or an array of keycodes to handle
16207 shift Boolean True to handle key only when shift is pressed (defaults to false)
16208 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
16209 alt Boolean True to handle key only when alt is pressed (defaults to false)
16210 fn Function The function to call when KeyMap finds the expected key combination
16211 scope Object The scope of the callback function
16217 var map = new Roo.KeyMap(document, {
16218 key: Roo.EventObject.ENTER,
16223 //Add a new binding to the existing KeyMap later
16231 * @param {Object/Array} config A single KeyMap config or an array of configs
16233 addBinding : function(config){
16234 if(config instanceof Array){
16235 for(var i = 0, len = config.length; i < len; i++){
16236 this.addBinding(config[i]);
16240 var keyCode = config.key,
16241 shift = config.shift,
16242 ctrl = config.ctrl,
16245 scope = config.scope;
16246 if(typeof keyCode == "string"){
16248 var keyString = keyCode.toUpperCase();
16249 for(var j = 0, len = keyString.length; j < len; j++){
16250 ks.push(keyString.charCodeAt(j));
16254 var keyArray = keyCode instanceof Array;
16255 var handler = function(e){
16256 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
16257 var k = e.getKey();
16259 for(var i = 0, len = keyCode.length; i < len; i++){
16260 if(keyCode[i] == k){
16261 if(this.stopEvent){
16264 fn.call(scope || window, k, e);
16270 if(this.stopEvent){
16273 fn.call(scope || window, k, e);
16278 this.bindings.push(handler);
16282 * Shorthand for adding a single key listener
16283 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
16284 * following options:
16285 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
16286 * @param {Function} fn The function to call
16287 * @param {Object} scope (optional) The scope of the function
16289 on : function(key, fn, scope){
16290 var keyCode, shift, ctrl, alt;
16291 if(typeof key == "object" && !(key instanceof Array)){
16310 handleKeyDown : function(e){
16311 if(this.enabled){ //just in case
16312 var b = this.bindings;
16313 for(var i = 0, len = b.length; i < len; i++){
16314 b[i].call(this, e);
16320 * Returns true if this KeyMap is enabled
16321 * @return {Boolean}
16323 isEnabled : function(){
16324 return this.enabled;
16328 * Enables this KeyMap
16330 enable: function(){
16332 this.el.on(this.eventName, this.handleKeyDown, this);
16333 this.enabled = true;
16338 * Disable this KeyMap
16340 disable: function(){
16342 this.el.removeListener(this.eventName, this.handleKeyDown, this);
16343 this.enabled = false;
16348 * Ext JS Library 1.1.1
16349 * Copyright(c) 2006-2007, Ext JS, LLC.
16351 * Originally Released Under LGPL - original licence link has changed is not relivant.
16354 * <script type="text/javascript">
16359 * @class Roo.util.TextMetrics
16360 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
16361 * wide, in pixels, a given block of text will be.
16364 Roo.util.TextMetrics = function(){
16368 * Measures the size of the specified text
16369 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
16370 * that can affect the size of the rendered text
16371 * @param {String} text The text to measure
16372 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
16373 * in order to accurately measure the text height
16374 * @return {Object} An object containing the text's size {width: (width), height: (height)}
16376 measure : function(el, text, fixedWidth){
16378 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
16381 shared.setFixedWidth(fixedWidth || 'auto');
16382 return shared.getSize(text);
16386 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
16387 * the overhead of multiple calls to initialize the style properties on each measurement.
16388 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
16389 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
16390 * in order to accurately measure the text height
16391 * @return {Roo.util.TextMetrics.Instance} instance The new instance
16393 createInstance : function(el, fixedWidth){
16394 return Roo.util.TextMetrics.Instance(el, fixedWidth);
16400 * @class Roo.util.TextMetrics.Instance
16401 * Instance of TextMetrics Calcuation
16403 * Create a new TextMetrics Instance
16404 * @param {Object} bindto
16405 * @param {Boolean} fixedWidth
16408 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth)
16410 var ml = new Roo.Element(document.createElement('div'));
16411 document.body.appendChild(ml.dom);
16412 ml.position('absolute');
16413 ml.setLeftTop(-1000, -1000);
16417 ml.setWidth(fixedWidth);
16422 * Returns the size of the specified text based on the internal element's style and width properties
16423 * @param {String} text The text to measure
16424 * @return {Object} An object containing the text's size {width: (width), height: (height)}
16426 getSize : function(text){
16428 var s = ml.getSize();
16434 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
16435 * that can affect the size of the rendered text
16436 * @param {String/HTMLElement} el The element, dom node or id
16438 bind : function(el){
16440 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
16445 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
16446 * to set a fixed width in order to accurately measure the text height.
16447 * @param {Number} width The width to set on the element
16449 setFixedWidth : function(width){
16450 ml.setWidth(width);
16454 * Returns the measured width of the specified text
16455 * @param {String} text The text to measure
16456 * @return {Number} width The width in pixels
16458 getWidth : function(text){
16459 ml.dom.style.width = 'auto';
16460 return this.getSize(text).width;
16464 * Returns the measured height of the specified text. For multiline text, be sure to call
16465 * {@link #setFixedWidth} if necessary.
16466 * @param {String} text The text to measure
16467 * @return {Number} height The height in pixels
16469 getHeight : function(text){
16470 return this.getSize(text).height;
16474 instance.bind(bindTo);
16479 // backwards compat
16480 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
16482 * Ext JS Library 1.1.1
16483 * Copyright(c) 2006-2007, Ext JS, LLC.
16485 * Originally Released Under LGPL - original licence link has changed is not relivant.
16488 * <script type="text/javascript">
16492 * @class Roo.state.Provider
16493 * Abstract base class for state provider implementations. This class provides methods
16494 * for encoding and decoding <b>typed</b> variables including dates and defines the
16495 * Provider interface.
16497 Roo.state.Provider = function(){
16499 * @event statechange
16500 * Fires when a state change occurs.
16501 * @param {Provider} this This state provider
16502 * @param {String} key The state key which was changed
16503 * @param {String} value The encoded value for the state
16506 "statechange": true
16509 Roo.state.Provider.superclass.constructor.call(this);
16511 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
16513 * Returns the current value for a key
16514 * @param {String} name The key name
16515 * @param {Mixed} defaultValue A default value to return if the key's value is not found
16516 * @return {Mixed} The state data
16518 get : function(name, defaultValue){
16519 return typeof this.state[name] == "undefined" ?
16520 defaultValue : this.state[name];
16524 * Clears a value from the state
16525 * @param {String} name The key name
16527 clear : function(name){
16528 delete this.state[name];
16529 this.fireEvent("statechange", this, name, null);
16533 * Sets the value for a key
16534 * @param {String} name The key name
16535 * @param {Mixed} value The value to set
16537 set : function(name, value){
16538 this.state[name] = value;
16539 this.fireEvent("statechange", this, name, value);
16543 * Decodes a string previously encoded with {@link #encodeValue}.
16544 * @param {String} value The value to decode
16545 * @return {Mixed} The decoded value
16547 decodeValue : function(cookie){
16548 var re = /^(a|n|d|b|s|o)\:(.*)$/;
16549 var matches = re.exec(unescape(cookie));
16550 if(!matches || !matches[1]) {
16551 return; // non state cookie
16553 var type = matches[1];
16554 var v = matches[2];
16557 return parseFloat(v);
16559 return new Date(Date.parse(v));
16564 var values = v.split("^");
16565 for(var i = 0, len = values.length; i < len; i++){
16566 all.push(this.decodeValue(values[i]));
16571 var values = v.split("^");
16572 for(var i = 0, len = values.length; i < len; i++){
16573 var kv = values[i].split("=");
16574 all[kv[0]] = this.decodeValue(kv[1]);
16583 * Encodes a value including type information. Decode with {@link #decodeValue}.
16584 * @param {Mixed} value The value to encode
16585 * @return {String} The encoded value
16587 encodeValue : function(v){
16589 if(typeof v == "number"){
16591 }else if(typeof v == "boolean"){
16592 enc = "b:" + (v ? "1" : "0");
16593 }else if(v instanceof Date){
16594 enc = "d:" + v.toGMTString();
16595 }else if(v instanceof Array){
16597 for(var i = 0, len = v.length; i < len; i++){
16598 flat += this.encodeValue(v[i]);
16604 }else if(typeof v == "object"){
16607 if(typeof v[key] != "function"){
16608 flat += key + "=" + this.encodeValue(v[key]) + "^";
16611 enc = "o:" + flat.substring(0, flat.length-1);
16615 return escape(enc);
16621 * Ext JS Library 1.1.1
16622 * Copyright(c) 2006-2007, Ext JS, LLC.
16624 * Originally Released Under LGPL - original licence link has changed is not relivant.
16627 * <script type="text/javascript">
16630 * @class Roo.state.Manager
16631 * This is the global state manager. By default all components that are "state aware" check this class
16632 * for state information if you don't pass them a custom state provider. In order for this class
16633 * to be useful, it must be initialized with a provider when your application initializes.
16635 // in your initialization function
16637 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
16639 // supposed you have a {@link Roo.layout.Border}
16640 var layout = new Roo.layout.Border(...);
16641 layout.restoreState();
16642 // or a {Roo.BasicDialog}
16643 var dialog = new Roo.BasicDialog(...);
16644 dialog.restoreState();
16648 Roo.state.Manager = function(){
16649 var provider = new Roo.state.Provider();
16653 * Configures the default state provider for your application
16654 * @param {Provider} stateProvider The state provider to set
16656 setProvider : function(stateProvider){
16657 provider = stateProvider;
16661 * Returns the current value for a key
16662 * @param {String} name The key name
16663 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
16664 * @return {Mixed} The state data
16666 get : function(key, defaultValue){
16667 return provider.get(key, defaultValue);
16671 * Sets the value for a key
16672 * @param {String} name The key name
16673 * @param {Mixed} value The state data
16675 set : function(key, value){
16676 provider.set(key, value);
16680 * Clears a value from the state
16681 * @param {String} name The key name
16683 clear : function(key){
16684 provider.clear(key);
16688 * Gets the currently configured state provider
16689 * @return {Provider} The state provider
16691 getProvider : function(){
16698 * Ext JS Library 1.1.1
16699 * Copyright(c) 2006-2007, Ext JS, LLC.
16701 * Originally Released Under LGPL - original licence link has changed is not relivant.
16704 * <script type="text/javascript">
16707 * @class Roo.state.CookieProvider
16708 * @extends Roo.state.Provider
16709 * The default Provider implementation which saves state via cookies.
16712 var cp = new Roo.state.CookieProvider({
16714 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
16715 domain: "roojs.com"
16717 Roo.state.Manager.setProvider(cp);
16719 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
16720 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
16721 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
16722 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
16723 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
16724 * domain the page is running on including the 'www' like 'www.roojs.com')
16725 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
16727 * Create a new CookieProvider
16728 * @param {Object} config The configuration object
16730 Roo.state.CookieProvider = function(config){
16731 Roo.state.CookieProvider.superclass.constructor.call(this);
16733 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
16734 this.domain = null;
16735 this.secure = false;
16736 Roo.apply(this, config);
16737 this.state = this.readCookies();
16740 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
16742 set : function(name, value){
16743 if(typeof value == "undefined" || value === null){
16747 this.setCookie(name, value);
16748 Roo.state.CookieProvider.superclass.set.call(this, name, value);
16752 clear : function(name){
16753 this.clearCookie(name);
16754 Roo.state.CookieProvider.superclass.clear.call(this, name);
16758 readCookies : function(){
16760 var c = document.cookie + ";";
16761 var re = /\s?(.*?)=(.*?);/g;
16763 while((matches = re.exec(c)) != null){
16764 var name = matches[1];
16765 var value = matches[2];
16766 if(name && name.substring(0,3) == "ys-"){
16767 cookies[name.substr(3)] = this.decodeValue(value);
16774 setCookie : function(name, value){
16775 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
16776 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
16777 ((this.path == null) ? "" : ("; path=" + this.path)) +
16778 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16779 ((this.secure == true) ? "; secure" : "");
16783 clearCookie : function(name){
16784 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
16785 ((this.path == null) ? "" : ("; path=" + this.path)) +
16786 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16787 ((this.secure == true) ? "; secure" : "");
16791 * Ext JS Library 1.1.1
16792 * Copyright(c) 2006-2007, Ext JS, LLC.
16794 * Originally Released Under LGPL - original licence link has changed is not relivant.
16797 * <script type="text/javascript">
16802 * @class Roo.ComponentMgr
16803 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
16806 Roo.ComponentMgr = function(){
16807 var all = new Roo.util.MixedCollection();
16811 * Registers a component.
16812 * @param {Roo.Component} c The component
16814 register : function(c){
16819 * Unregisters a component.
16820 * @param {Roo.Component} c The component
16822 unregister : function(c){
16827 * Returns a component by id
16828 * @param {String} id The component id
16830 get : function(id){
16831 return all.get(id);
16835 * Registers a function that will be called when a specified component is added to ComponentMgr
16836 * @param {String} id The component id
16837 * @param {Funtction} fn The callback function
16838 * @param {Object} scope The scope of the callback
16840 onAvailable : function(id, fn, scope){
16841 all.on("add", function(index, o){
16843 fn.call(scope || o, o);
16844 all.un("add", fn, scope);
16851 * Ext JS Library 1.1.1
16852 * Copyright(c) 2006-2007, Ext JS, LLC.
16854 * Originally Released Under LGPL - original licence link has changed is not relivant.
16857 * <script type="text/javascript">
16861 * @class Roo.Component
16862 * @extends Roo.util.Observable
16863 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
16864 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
16865 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
16866 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
16867 * All visual components (widgets) that require rendering into a layout should subclass Component.
16869 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
16870 * 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
16871 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
16873 Roo.Component = function(config){
16874 config = config || {};
16875 if(config.tagName || config.dom || typeof config == "string"){ // element object
16876 config = {el: config, id: config.id || config};
16878 this.initialConfig = config;
16880 Roo.apply(this, config);
16884 * Fires after the component is disabled.
16885 * @param {Roo.Component} this
16890 * Fires after the component is enabled.
16891 * @param {Roo.Component} this
16895 * @event beforeshow
16896 * Fires before the component is shown. Return false to stop the show.
16897 * @param {Roo.Component} this
16902 * Fires after the component is shown.
16903 * @param {Roo.Component} this
16907 * @event beforehide
16908 * Fires before the component is hidden. Return false to stop the hide.
16909 * @param {Roo.Component} this
16914 * Fires after the component is hidden.
16915 * @param {Roo.Component} this
16919 * @event beforerender
16920 * Fires before the component is rendered. Return false to stop the render.
16921 * @param {Roo.Component} this
16923 beforerender : true,
16926 * Fires after the component is rendered.
16927 * @param {Roo.Component} this
16931 * @event beforedestroy
16932 * Fires before the component is destroyed. Return false to stop the destroy.
16933 * @param {Roo.Component} this
16935 beforedestroy : true,
16938 * Fires after the component is destroyed.
16939 * @param {Roo.Component} this
16944 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
16946 Roo.ComponentMgr.register(this);
16947 Roo.Component.superclass.constructor.call(this);
16948 this.initComponent();
16949 if(this.renderTo){ // not supported by all components yet. use at your own risk!
16950 this.render(this.renderTo);
16951 delete this.renderTo;
16956 Roo.Component.AUTO_ID = 1000;
16958 Roo.extend(Roo.Component, Roo.util.Observable, {
16960 * @scope Roo.Component.prototype
16962 * true if this component is hidden. Read-only.
16967 * true if this component is disabled. Read-only.
16972 * true if this component has been rendered. Read-only.
16976 /** @cfg {String} disableClass
16977 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
16979 disabledClass : "x-item-disabled",
16980 /** @cfg {Boolean} allowDomMove
16981 * Whether the component can move the Dom node when rendering (defaults to true).
16983 allowDomMove : true,
16984 /** @cfg {String} hideMode (display|visibility)
16985 * How this component should hidden. Supported values are
16986 * "visibility" (css visibility), "offsets" (negative offset position) and
16987 * "display" (css display) - defaults to "display".
16989 hideMode: 'display',
16992 ctype : "Roo.Component",
16995 * @cfg {String} actionMode
16996 * which property holds the element that used for hide() / show() / disable() / enable()
16997 * default is 'el' for forms you probably want to set this to fieldEl
17002 * @cfg {String} style
17003 * css styles to add to component
17004 * eg. text-align:right;
17009 getActionEl : function(){
17010 return this[this.actionMode];
17013 initComponent : Roo.emptyFn,
17015 * If this is a lazy rendering component, render it to its container element.
17016 * @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.
17018 render : function(container, position){
17024 if(this.fireEvent("beforerender", this) === false){
17028 if(!container && this.el){
17029 this.el = Roo.get(this.el);
17030 container = this.el.dom.parentNode;
17031 this.allowDomMove = false;
17033 this.container = Roo.get(container);
17034 this.rendered = true;
17035 if(position !== undefined){
17036 if(typeof position == 'number'){
17037 position = this.container.dom.childNodes[position];
17039 position = Roo.getDom(position);
17042 this.onRender(this.container, position || null);
17044 this.el.addClass(this.cls);
17048 this.el.applyStyles(this.style);
17051 this.fireEvent("render", this);
17052 this.afterRender(this.container);
17065 // default function is not really useful
17066 onRender : function(ct, position){
17068 this.el = Roo.get(this.el);
17069 if(this.allowDomMove !== false){
17070 ct.dom.insertBefore(this.el.dom, position);
17076 getAutoCreate : function(){
17077 var cfg = typeof this.autoCreate == "object" ?
17078 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
17079 if(this.id && !cfg.id){
17086 afterRender : Roo.emptyFn,
17089 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
17090 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
17092 destroy : function(){
17093 if(this.fireEvent("beforedestroy", this) !== false){
17094 this.purgeListeners();
17095 this.beforeDestroy();
17097 this.el.removeAllListeners();
17099 if(this.actionMode == "container"){
17100 this.container.remove();
17104 Roo.ComponentMgr.unregister(this);
17105 this.fireEvent("destroy", this);
17110 beforeDestroy : function(){
17115 onDestroy : function(){
17120 * Returns the underlying {@link Roo.Element}.
17121 * @return {Roo.Element} The element
17123 getEl : function(){
17128 * Returns the id of this component.
17131 getId : function(){
17136 * Try to focus this component.
17137 * @param {Boolean} selectText True to also select the text in this component (if applicable)
17138 * @return {Roo.Component} this
17140 focus : function(selectText){
17143 if(selectText === true){
17144 this.el.dom.select();
17159 * Disable this component.
17160 * @return {Roo.Component} this
17162 disable : function(){
17166 this.disabled = true;
17167 this.fireEvent("disable", this);
17172 onDisable : function(){
17173 this.getActionEl().addClass(this.disabledClass);
17174 this.el.dom.disabled = true;
17178 * Enable this component.
17179 * @return {Roo.Component} this
17181 enable : function(){
17185 this.disabled = false;
17186 this.fireEvent("enable", this);
17191 onEnable : function(){
17192 this.getActionEl().removeClass(this.disabledClass);
17193 this.el.dom.disabled = false;
17197 * Convenience function for setting disabled/enabled by boolean.
17198 * @param {Boolean} disabled
17200 setDisabled : function(disabled){
17201 this[disabled ? "disable" : "enable"]();
17205 * Show this component.
17206 * @return {Roo.Component} this
17209 if(this.fireEvent("beforeshow", this) !== false){
17210 this.hidden = false;
17214 this.fireEvent("show", this);
17220 onShow : function(){
17221 var ae = this.getActionEl();
17222 if(this.hideMode == 'visibility'){
17223 ae.dom.style.visibility = "visible";
17224 }else if(this.hideMode == 'offsets'){
17225 ae.removeClass('x-hidden');
17227 ae.dom.style.display = "";
17232 * Hide this component.
17233 * @return {Roo.Component} this
17236 if(this.fireEvent("beforehide", this) !== false){
17237 this.hidden = true;
17241 this.fireEvent("hide", this);
17247 onHide : function(){
17248 var ae = this.getActionEl();
17249 if(this.hideMode == 'visibility'){
17250 ae.dom.style.visibility = "hidden";
17251 }else if(this.hideMode == 'offsets'){
17252 ae.addClass('x-hidden');
17254 ae.dom.style.display = "none";
17259 * Convenience function to hide or show this component by boolean.
17260 * @param {Boolean} visible True to show, false to hide
17261 * @return {Roo.Component} this
17263 setVisible: function(visible){
17273 * Returns true if this component is visible.
17275 isVisible : function(){
17276 return this.getActionEl().isVisible();
17279 cloneConfig : function(overrides){
17280 overrides = overrides || {};
17281 var id = overrides.id || Roo.id();
17282 var cfg = Roo.applyIf(overrides, this.initialConfig);
17283 cfg.id = id; // prevent dup id
17284 return new this.constructor(cfg);
17288 * Ext JS Library 1.1.1
17289 * Copyright(c) 2006-2007, Ext JS, LLC.
17291 * Originally Released Under LGPL - original licence link has changed is not relivant.
17294 * <script type="text/javascript">
17298 * @class Roo.BoxComponent
17299 * @extends Roo.Component
17300 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
17301 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
17302 * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
17303 * layout containers.
17305 * @param {Roo.Element/String/Object} config The configuration options.
17307 Roo.BoxComponent = function(config){
17308 Roo.Component.call(this, config);
17312 * Fires after the component is resized.
17313 * @param {Roo.Component} this
17314 * @param {Number} adjWidth The box-adjusted width that was set
17315 * @param {Number} adjHeight The box-adjusted height that was set
17316 * @param {Number} rawWidth The width that was originally specified
17317 * @param {Number} rawHeight The height that was originally specified
17322 * Fires after the component is moved.
17323 * @param {Roo.Component} this
17324 * @param {Number} x The new x position
17325 * @param {Number} y The new y position
17331 Roo.extend(Roo.BoxComponent, Roo.Component, {
17332 // private, set in afterRender to signify that the component has been rendered
17334 // private, used to defer height settings to subclasses
17335 deferHeight: false,
17336 /** @cfg {Number} width
17337 * width (optional) size of component
17339 /** @cfg {Number} height
17340 * height (optional) size of component
17344 * Sets the width and height of the component. This method fires the resize event. This method can accept
17345 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
17346 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
17347 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
17348 * @return {Roo.BoxComponent} this
17350 setSize : function(w, h){
17351 // support for standard size objects
17352 if(typeof w == 'object'){
17357 if(!this.boxReady){
17363 // prevent recalcs when not needed
17364 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
17367 this.lastSize = {width: w, height: h};
17369 var adj = this.adjustSize(w, h);
17370 var aw = adj.width, ah = adj.height;
17371 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
17372 var rz = this.getResizeEl();
17373 if(!this.deferHeight && aw !== undefined && ah !== undefined){
17374 rz.setSize(aw, ah);
17375 }else if(!this.deferHeight && ah !== undefined){
17377 }else if(aw !== undefined){
17380 this.onResize(aw, ah, w, h);
17381 this.fireEvent('resize', this, aw, ah, w, h);
17387 * Gets the current size of the component's underlying element.
17388 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
17390 getSize : function(){
17391 return this.el.getSize();
17395 * Gets the current XY position of the component's underlying element.
17396 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
17397 * @return {Array} The XY position of the element (e.g., [100, 200])
17399 getPosition : function(local){
17400 if(local === true){
17401 return [this.el.getLeft(true), this.el.getTop(true)];
17403 return this.xy || this.el.getXY();
17407 * Gets the current box measurements of the component's underlying element.
17408 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
17409 * @returns {Object} box An object in the format {x, y, width, height}
17411 getBox : function(local){
17412 var s = this.el.getSize();
17414 s.x = this.el.getLeft(true);
17415 s.y = this.el.getTop(true);
17417 var xy = this.xy || this.el.getXY();
17425 * Sets the current box measurements of the component's underlying element.
17426 * @param {Object} box An object in the format {x, y, width, height}
17427 * @returns {Roo.BoxComponent} this
17429 updateBox : function(box){
17430 this.setSize(box.width, box.height);
17431 this.setPagePosition(box.x, box.y);
17436 getResizeEl : function(){
17437 return this.resizeEl || this.el;
17441 getPositionEl : function(){
17442 return this.positionEl || this.el;
17446 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
17447 * This method fires the move event.
17448 * @param {Number} left The new left
17449 * @param {Number} top The new top
17450 * @returns {Roo.BoxComponent} this
17452 setPosition : function(x, y){
17455 if(!this.boxReady){
17458 var adj = this.adjustPosition(x, y);
17459 var ax = adj.x, ay = adj.y;
17461 var el = this.getPositionEl();
17462 if(ax !== undefined || ay !== undefined){
17463 if(ax !== undefined && ay !== undefined){
17464 el.setLeftTop(ax, ay);
17465 }else if(ax !== undefined){
17467 }else if(ay !== undefined){
17470 this.onPosition(ax, ay);
17471 this.fireEvent('move', this, ax, ay);
17477 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
17478 * This method fires the move event.
17479 * @param {Number} x The new x position
17480 * @param {Number} y The new y position
17481 * @returns {Roo.BoxComponent} this
17483 setPagePosition : function(x, y){
17486 if(!this.boxReady){
17489 if(x === undefined || y === undefined){ // cannot translate undefined points
17492 var p = this.el.translatePoints(x, y);
17493 this.setPosition(p.left, p.top);
17498 onRender : function(ct, position){
17499 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
17501 this.resizeEl = Roo.get(this.resizeEl);
17503 if(this.positionEl){
17504 this.positionEl = Roo.get(this.positionEl);
17509 afterRender : function(){
17510 Roo.BoxComponent.superclass.afterRender.call(this);
17511 this.boxReady = true;
17512 this.setSize(this.width, this.height);
17513 if(this.x || this.y){
17514 this.setPosition(this.x, this.y);
17516 if(this.pageX || this.pageY){
17517 this.setPagePosition(this.pageX, this.pageY);
17522 * Force the component's size to recalculate based on the underlying element's current height and width.
17523 * @returns {Roo.BoxComponent} this
17525 syncSize : function(){
17526 delete this.lastSize;
17527 this.setSize(this.el.getWidth(), this.el.getHeight());
17532 * Called after the component is resized, this method is empty by default but can be implemented by any
17533 * subclass that needs to perform custom logic after a resize occurs.
17534 * @param {Number} adjWidth The box-adjusted width that was set
17535 * @param {Number} adjHeight The box-adjusted height that was set
17536 * @param {Number} rawWidth The width that was originally specified
17537 * @param {Number} rawHeight The height that was originally specified
17539 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
17544 * Called after the component is moved, this method is empty by default but can be implemented by any
17545 * subclass that needs to perform custom logic after a move occurs.
17546 * @param {Number} x The new x position
17547 * @param {Number} y The new y position
17549 onPosition : function(x, y){
17554 adjustSize : function(w, h){
17555 if(this.autoWidth){
17558 if(this.autoHeight){
17561 return {width : w, height: h};
17565 adjustPosition : function(x, y){
17566 return {x : x, y: y};
17570 * Ext JS Library 1.1.1
17571 * Copyright(c) 2006-2007, Ext JS, LLC.
17573 * Originally Released Under LGPL - original licence link has changed is not relivant.
17576 * <script type="text/javascript">
17581 * @extends Roo.Element
17582 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
17583 * automatic maintaining of shadow/shim positions.
17584 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
17585 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
17586 * you can pass a string with a CSS class name. False turns off the shadow.
17587 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
17588 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
17589 * @cfg {String} cls CSS class to add to the element
17590 * @cfg {Number} zindex Starting z-index (defaults to 11000)
17591 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
17593 * @param {Object} config An object with config options.
17594 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
17597 Roo.Layer = function(config, existingEl){
17598 config = config || {};
17599 var dh = Roo.DomHelper;
17600 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
17602 this.dom = Roo.getDom(existingEl);
17605 var o = config.dh || {tag: "div", cls: "x-layer"};
17606 this.dom = dh.append(pel, o);
17609 this.addClass(config.cls);
17611 this.constrain = config.constrain !== false;
17612 this.visibilityMode = Roo.Element.VISIBILITY;
17614 this.id = this.dom.id = config.id;
17616 this.id = Roo.id(this.dom);
17618 this.zindex = config.zindex || this.getZIndex();
17619 this.position("absolute", this.zindex);
17621 this.shadowOffset = config.shadowOffset || 4;
17622 this.shadow = new Roo.Shadow({
17623 offset : this.shadowOffset,
17624 mode : config.shadow
17627 this.shadowOffset = 0;
17629 this.useShim = config.shim !== false && Roo.useShims;
17630 this.useDisplay = config.useDisplay;
17634 var supr = Roo.Element.prototype;
17636 // shims are shared among layer to keep from having 100 iframes
17639 Roo.extend(Roo.Layer, Roo.Element, {
17641 getZIndex : function(){
17642 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
17645 getShim : function(){
17652 var shim = shims.shift();
17654 shim = this.createShim();
17655 shim.enableDisplayMode('block');
17656 shim.dom.style.display = 'none';
17657 shim.dom.style.visibility = 'visible';
17659 var pn = this.dom.parentNode;
17660 if(shim.dom.parentNode != pn){
17661 pn.insertBefore(shim.dom, this.dom);
17663 shim.setStyle('z-index', this.getZIndex()-2);
17668 hideShim : function(){
17670 this.shim.setDisplayed(false);
17671 shims.push(this.shim);
17676 disableShadow : function(){
17678 this.shadowDisabled = true;
17679 this.shadow.hide();
17680 this.lastShadowOffset = this.shadowOffset;
17681 this.shadowOffset = 0;
17685 enableShadow : function(show){
17687 this.shadowDisabled = false;
17688 this.shadowOffset = this.lastShadowOffset;
17689 delete this.lastShadowOffset;
17697 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
17698 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
17699 sync : function(doShow){
17700 var sw = this.shadow;
17701 if(!this.updating && this.isVisible() && (sw || this.useShim)){
17702 var sh = this.getShim();
17704 var w = this.getWidth(),
17705 h = this.getHeight();
17707 var l = this.getLeft(true),
17708 t = this.getTop(true);
17710 if(sw && !this.shadowDisabled){
17711 if(doShow && !sw.isVisible()){
17714 sw.realign(l, t, w, h);
17720 // fit the shim behind the shadow, so it is shimmed too
17721 var a = sw.adjusts, s = sh.dom.style;
17722 s.left = (Math.min(l, l+a.l))+"px";
17723 s.top = (Math.min(t, t+a.t))+"px";
17724 s.width = (w+a.w)+"px";
17725 s.height = (h+a.h)+"px";
17732 sh.setLeftTop(l, t);
17739 destroy : function(){
17742 this.shadow.hide();
17744 this.removeAllListeners();
17745 var pn = this.dom.parentNode;
17747 pn.removeChild(this.dom);
17749 Roo.Element.uncache(this.id);
17752 remove : function(){
17757 beginUpdate : function(){
17758 this.updating = true;
17762 endUpdate : function(){
17763 this.updating = false;
17768 hideUnders : function(negOffset){
17770 this.shadow.hide();
17776 constrainXY : function(){
17777 if(this.constrain){
17778 var vw = Roo.lib.Dom.getViewWidth(),
17779 vh = Roo.lib.Dom.getViewHeight();
17780 var s = Roo.get(document).getScroll();
17782 var xy = this.getXY();
17783 var x = xy[0], y = xy[1];
17784 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
17785 // only move it if it needs it
17787 // first validate right/bottom
17788 if((x + w) > vw+s.left){
17789 x = vw - w - this.shadowOffset;
17792 if((y + h) > vh+s.top){
17793 y = vh - h - this.shadowOffset;
17796 // then make sure top/left isn't negative
17807 var ay = this.avoidY;
17808 if(y <= ay && (y+h) >= ay){
17814 supr.setXY.call(this, xy);
17820 isVisible : function(){
17821 return this.visible;
17825 showAction : function(){
17826 this.visible = true; // track visibility to prevent getStyle calls
17827 if(this.useDisplay === true){
17828 this.setDisplayed("");
17829 }else if(this.lastXY){
17830 supr.setXY.call(this, this.lastXY);
17831 }else if(this.lastLT){
17832 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
17837 hideAction : function(){
17838 this.visible = false;
17839 if(this.useDisplay === true){
17840 this.setDisplayed(false);
17842 this.setLeftTop(-10000,-10000);
17846 // overridden Element method
17847 setVisible : function(v, a, d, c, e){
17852 var cb = function(){
17857 }.createDelegate(this);
17858 supr.setVisible.call(this, true, true, d, cb, e);
17861 this.hideUnders(true);
17870 }.createDelegate(this);
17872 supr.setVisible.call(this, v, a, d, cb, e);
17881 storeXY : function(xy){
17882 delete this.lastLT;
17886 storeLeftTop : function(left, top){
17887 delete this.lastXY;
17888 this.lastLT = [left, top];
17892 beforeFx : function(){
17893 this.beforeAction();
17894 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
17898 afterFx : function(){
17899 Roo.Layer.superclass.afterFx.apply(this, arguments);
17900 this.sync(this.isVisible());
17904 beforeAction : function(){
17905 if(!this.updating && this.shadow){
17906 this.shadow.hide();
17910 // overridden Element method
17911 setLeft : function(left){
17912 this.storeLeftTop(left, this.getTop(true));
17913 supr.setLeft.apply(this, arguments);
17917 setTop : function(top){
17918 this.storeLeftTop(this.getLeft(true), top);
17919 supr.setTop.apply(this, arguments);
17923 setLeftTop : function(left, top){
17924 this.storeLeftTop(left, top);
17925 supr.setLeftTop.apply(this, arguments);
17929 setXY : function(xy, a, d, c, e){
17931 this.beforeAction();
17933 var cb = this.createCB(c);
17934 supr.setXY.call(this, xy, a, d, cb, e);
17941 createCB : function(c){
17952 // overridden Element method
17953 setX : function(x, a, d, c, e){
17954 this.setXY([x, this.getY()], a, d, c, e);
17957 // overridden Element method
17958 setY : function(y, a, d, c, e){
17959 this.setXY([this.getX(), y], a, d, c, e);
17962 // overridden Element method
17963 setSize : function(w, h, a, d, c, e){
17964 this.beforeAction();
17965 var cb = this.createCB(c);
17966 supr.setSize.call(this, w, h, a, d, cb, e);
17972 // overridden Element method
17973 setWidth : function(w, a, d, c, e){
17974 this.beforeAction();
17975 var cb = this.createCB(c);
17976 supr.setWidth.call(this, w, a, d, cb, e);
17982 // overridden Element method
17983 setHeight : function(h, a, d, c, e){
17984 this.beforeAction();
17985 var cb = this.createCB(c);
17986 supr.setHeight.call(this, h, a, d, cb, e);
17992 // overridden Element method
17993 setBounds : function(x, y, w, h, a, d, c, e){
17994 this.beforeAction();
17995 var cb = this.createCB(c);
17997 this.storeXY([x, y]);
17998 supr.setXY.call(this, [x, y]);
17999 supr.setSize.call(this, w, h, a, d, cb, e);
18002 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
18008 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
18009 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
18010 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
18011 * @param {Number} zindex The new z-index to set
18012 * @return {this} The Layer
18014 setZIndex : function(zindex){
18015 this.zindex = zindex;
18016 this.setStyle("z-index", zindex + 2);
18018 this.shadow.setZIndex(zindex + 1);
18021 this.shim.setStyle("z-index", zindex);
18026 * Original code for Roojs - LGPL
18027 * <script type="text/javascript">
18031 * @class Roo.XComponent
18032 * A delayed Element creator...
18033 * Or a way to group chunks of interface together.
18034 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
18035 * used in conjunction with XComponent.build() it will create an instance of each element,
18036 * then call addxtype() to build the User interface.
18038 * Mypart.xyx = new Roo.XComponent({
18040 parent : 'Mypart.xyz', // empty == document.element.!!
18044 disabled : function() {}
18046 tree : function() { // return an tree of xtype declared components
18050 xtype : 'NestedLayoutPanel',
18057 * It can be used to build a big heiracy, with parent etc.
18058 * or you can just use this to render a single compoent to a dom element
18059 * MYPART.render(Roo.Element | String(id) | dom_element )
18066 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
18067 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
18069 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
18071 * When the top level is false, a 'Roo.layout.Border' is created and the element is flagged as 'topModule'
18072 * - if mulitple topModules exist, the last one is defined as the top module.
18076 * When the top level or multiple modules are to embedded into a existing HTML page,
18077 * the parent element can container '#id' of the element where the module will be drawn.
18081 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
18082 * it relies more on a include mechanism, where sub modules are included into an outer page.
18083 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
18085 * Bootstrap Roo Included elements
18087 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
18088 * hence confusing the component builder as it thinks there are multiple top level elements.
18090 * String Over-ride & Translations
18092 * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
18093 * and also the 'overlaying of string values - needed when different versions of the same application with different text content
18094 * are needed. @see Roo.XComponent.overlayString
18098 * @extends Roo.util.Observable
18100 * @param cfg {Object} configuration of component
18103 Roo.XComponent = function(cfg) {
18104 Roo.apply(this, cfg);
18108 * Fires when this the componnt is built
18109 * @param {Roo.XComponent} c the component
18114 this.region = this.region || 'center'; // default..
18115 Roo.XComponent.register(this);
18116 this.modules = false;
18117 this.el = false; // where the layout goes..
18121 Roo.extend(Roo.XComponent, Roo.util.Observable, {
18124 * The created element (with Roo.factory())
18125 * @type {Roo.Layout}
18131 * for BC - use el in new code
18132 * @type {Roo.Layout}
18138 * for BC - use el in new code
18139 * @type {Roo.Layout}
18144 * @cfg {Function|boolean} disabled
18145 * If this module is disabled by some rule, return true from the funtion
18150 * @cfg {String} parent
18151 * Name of parent element which it get xtype added to..
18156 * @cfg {String} order
18157 * Used to set the order in which elements are created (usefull for multiple tabs)
18162 * @cfg {String} name
18163 * String to display while loading.
18167 * @cfg {String} region
18168 * Region to render component to (defaults to center)
18173 * @cfg {Array} items
18174 * A single item array - the first element is the root of the tree..
18175 * It's done this way to stay compatible with the Xtype system...
18181 * The method that retuns the tree of parts that make up this compoennt
18188 * render element to dom or tree
18189 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
18192 render : function(el)
18196 var hp = this.parent ? 1 : 0;
18197 Roo.debug && Roo.log(this);
18199 var tree = this._tree ? this._tree() : this.tree();
18202 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
18203 // if parent is a '#.....' string, then let's use that..
18204 var ename = this.parent.substr(1);
18205 this.parent = false;
18206 Roo.debug && Roo.log(ename);
18208 case 'bootstrap-body':
18209 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
18210 // this is the BorderLayout standard?
18211 this.parent = { el : true };
18214 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
18215 // need to insert stuff...
18217 el : new Roo.bootstrap.layout.Border({
18218 el : document.body,
18224 tabPosition: 'top',
18225 //resizeTabs: true,
18226 alwaysShowTabs: true,
18236 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
18237 this.parent = { el : new Roo.bootstrap.Body() };
18238 Roo.debug && Roo.log("setting el to doc body");
18241 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
18245 this.parent = { el : true};
18248 el = Roo.get(ename);
18249 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
18250 this.parent = { el : true};
18257 if (!el && !this.parent) {
18258 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
18263 Roo.debug && Roo.log("EL:");
18264 Roo.debug && Roo.log(el);
18265 Roo.debug && Roo.log("this.parent.el:");
18266 Roo.debug && Roo.log(this.parent.el);
18269 // altertive root elements ??? - we need a better way to indicate these.
18270 var is_alt = Roo.XComponent.is_alt ||
18271 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
18272 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
18273 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
18277 if (!this.parent && is_alt) {
18278 //el = Roo.get(document.body);
18279 this.parent = { el : true };
18284 if (!this.parent) {
18286 Roo.debug && Roo.log("no parent - creating one");
18288 el = el ? Roo.get(el) : false;
18290 if (typeof(Roo.layout.Border) == 'undefined' ) {
18293 el : new Roo.bootstrap.layout.Border({
18294 el: el || document.body,
18300 tabPosition: 'top',
18301 //resizeTabs: true,
18302 alwaysShowTabs: false,
18305 overflow: 'visible'
18311 // it's a top level one..
18313 el : new Roo.layout.Border(el || document.body, {
18318 tabPosition: 'top',
18319 //resizeTabs: true,
18320 alwaysShowTabs: el && hp? false : true,
18321 hideTabs: el || !hp ? true : false,
18329 if (!this.parent.el) {
18330 // probably an old style ctor, which has been disabled.
18334 // The 'tree' method is '_tree now'
18336 tree.region = tree.region || this.region;
18337 var is_body = false;
18338 if (this.parent.el === true) {
18339 // bootstrap... - body..
18343 this.parent.el = Roo.factory(tree);
18347 this.el = this.parent.el.addxtype(tree, undefined, is_body);
18348 this.fireEvent('built', this);
18350 this.panel = this.el;
18351 this.layout = this.panel.layout;
18352 this.parentLayout = this.parent.layout || false;
18358 Roo.apply(Roo.XComponent, {
18360 * @property hideProgress
18361 * true to disable the building progress bar.. usefull on single page renders.
18364 hideProgress : false,
18366 * @property buildCompleted
18367 * True when the builder has completed building the interface.
18370 buildCompleted : false,
18373 * @property topModule
18374 * the upper most module - uses document.element as it's constructor.
18381 * @property modules
18382 * array of modules to be created by registration system.
18383 * @type {Array} of Roo.XComponent
18388 * @property elmodules
18389 * array of modules to be created by which use #ID
18390 * @type {Array} of Roo.XComponent
18397 * Is an alternative Root - normally used by bootstrap or other systems,
18398 * where the top element in the tree can wrap 'body'
18399 * @type {boolean} (default false)
18404 * @property build_from_html
18405 * Build elements from html - used by bootstrap HTML stuff
18406 * - this is cleared after build is completed
18407 * @type {boolean} (default false)
18410 build_from_html : false,
18412 * Register components to be built later.
18414 * This solves the following issues
18415 * - Building is not done on page load, but after an authentication process has occured.
18416 * - Interface elements are registered on page load
18417 * - Parent Interface elements may not be loaded before child, so this handles that..
18424 module : 'Pman.Tab.projectMgr',
18426 parent : 'Pman.layout',
18427 disabled : false, // or use a function..
18430 * * @param {Object} details about module
18432 register : function(obj) {
18434 Roo.XComponent.event.fireEvent('register', obj);
18435 switch(typeof(obj.disabled) ) {
18441 if ( obj.disabled() ) {
18447 if (obj.disabled || obj.region == '#disabled') {
18453 this.modules.push(obj);
18457 * convert a string to an object..
18458 * eg. 'AAA.BBB' -> finds AAA.BBB
18462 toObject : function(str)
18464 if (!str || typeof(str) == 'object') {
18467 if (str.substring(0,1) == '#') {
18471 var ar = str.split('.');
18476 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
18478 throw "Module not found : " + str;
18482 throw "Module not found : " + str;
18484 Roo.each(ar, function(e) {
18485 if (typeof(o[e]) == 'undefined') {
18486 throw "Module not found : " + str;
18497 * move modules into their correct place in the tree..
18500 preBuild : function ()
18503 Roo.each(this.modules , function (obj)
18505 Roo.XComponent.event.fireEvent('beforebuild', obj);
18507 var opar = obj.parent;
18509 obj.parent = this.toObject(opar);
18511 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
18516 Roo.debug && Roo.log("GOT top level module");
18517 Roo.debug && Roo.log(obj);
18518 obj.modules = new Roo.util.MixedCollection(false,
18519 function(o) { return o.order + '' }
18521 this.topModule = obj;
18524 // parent is a string (usually a dom element name..)
18525 if (typeof(obj.parent) == 'string') {
18526 this.elmodules.push(obj);
18529 if (obj.parent.constructor != Roo.XComponent) {
18530 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
18532 if (!obj.parent.modules) {
18533 obj.parent.modules = new Roo.util.MixedCollection(false,
18534 function(o) { return o.order + '' }
18537 if (obj.parent.disabled) {
18538 obj.disabled = true;
18540 obj.parent.modules.add(obj);
18545 * make a list of modules to build.
18546 * @return {Array} list of modules.
18549 buildOrder : function()
18552 var cmp = function(a,b) {
18553 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
18555 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
18556 throw "No top level modules to build";
18559 // make a flat list in order of modules to build.
18560 var mods = this.topModule ? [ this.topModule ] : [];
18563 // elmodules (is a list of DOM based modules )
18564 Roo.each(this.elmodules, function(e) {
18566 if (!this.topModule &&
18567 typeof(e.parent) == 'string' &&
18568 e.parent.substring(0,1) == '#' &&
18569 Roo.get(e.parent.substr(1))
18572 _this.topModule = e;
18578 // add modules to their parents..
18579 var addMod = function(m) {
18580 Roo.debug && Roo.log("build Order: add: " + m.name);
18583 if (m.modules && !m.disabled) {
18584 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
18585 m.modules.keySort('ASC', cmp );
18586 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
18588 m.modules.each(addMod);
18590 Roo.debug && Roo.log("build Order: no child modules");
18592 // not sure if this is used any more..
18594 m.finalize.name = m.name + " (clean up) ";
18595 mods.push(m.finalize);
18599 if (this.topModule && this.topModule.modules) {
18600 this.topModule.modules.keySort('ASC', cmp );
18601 this.topModule.modules.each(addMod);
18607 * Build the registered modules.
18608 * @param {Object} parent element.
18609 * @param {Function} optional method to call after module has been added.
18613 build : function(opts)
18616 if (typeof(opts) != 'undefined') {
18617 Roo.apply(this,opts);
18621 var mods = this.buildOrder();
18623 //this.allmods = mods;
18624 //Roo.debug && Roo.log(mods);
18626 if (!mods.length) { // should not happen
18627 throw "NO modules!!!";
18631 var msg = "Building Interface...";
18632 // flash it up as modal - so we store the mask!?
18633 if (!this.hideProgress && Roo.MessageBox) {
18634 Roo.MessageBox.show({ title: 'loading' });
18635 Roo.MessageBox.show({
18636 title: "Please wait...",
18646 var total = mods.length;
18649 var progressRun = function() {
18650 if (!mods.length) {
18651 Roo.debug && Roo.log('hide?');
18652 if (!this.hideProgress && Roo.MessageBox) {
18653 Roo.MessageBox.hide();
18655 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
18657 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
18663 var m = mods.shift();
18666 Roo.debug && Roo.log(m);
18667 // not sure if this is supported any more.. - modules that are are just function
18668 if (typeof(m) == 'function') {
18670 return progressRun.defer(10, _this);
18674 msg = "Building Interface " + (total - mods.length) +
18676 (m.name ? (' - ' + m.name) : '');
18677 Roo.debug && Roo.log(msg);
18678 if (!_this.hideProgress && Roo.MessageBox) {
18679 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
18683 // is the module disabled?
18684 var disabled = (typeof(m.disabled) == 'function') ?
18685 m.disabled.call(m.module.disabled) : m.disabled;
18689 return progressRun(); // we do not update the display!
18697 // it's 10 on top level, and 1 on others??? why...
18698 return progressRun.defer(10, _this);
18701 progressRun.defer(1, _this);
18707 * Overlay a set of modified strings onto a component
18708 * This is dependant on our builder exporting the strings and 'named strings' elements.
18710 * @param {Object} element to overlay on - eg. Pman.Dialog.Login
18711 * @param {Object} associative array of 'named' string and it's new value.
18714 overlayStrings : function( component, strings )
18716 if (typeof(component['_named_strings']) == 'undefined') {
18717 throw "ERROR: component does not have _named_strings";
18719 for ( var k in strings ) {
18720 var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
18721 if (md !== false) {
18722 component['_strings'][md] = strings[k];
18724 Roo.log('could not find named string: ' + k + ' in');
18725 Roo.log(component);
18740 * wrapper for event.on - aliased later..
18741 * Typically use to register a event handler for register:
18743 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
18752 Roo.XComponent.event = new Roo.util.Observable({
18756 * Fires when an Component is registered,
18757 * set the disable property on the Component to stop registration.
18758 * @param {Roo.XComponent} c the component being registerd.
18763 * @event beforebuild
18764 * Fires before each Component is built
18765 * can be used to apply permissions.
18766 * @param {Roo.XComponent} c the component being registerd.
18769 'beforebuild' : true,
18771 * @event buildcomplete
18772 * Fires on the top level element when all elements have been built
18773 * @param {Roo.XComponent} the top level component.
18775 'buildcomplete' : true
18780 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
18783 * marked - a markdown parser
18784 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
18785 * https://github.com/chjj/marked
18791 * Roo.Markdown - is a very crude wrapper around marked..
18795 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
18797 * Note: move the sample code to the bottom of this
18798 * file before uncommenting it.
18803 Roo.Markdown.toHtml = function(text) {
18805 var c = new Roo.Markdown.marked.setOptions({
18806 renderer: new Roo.Markdown.marked.Renderer(),
18817 text = text.replace(/\\\n/g,' ');
18818 return Roo.Markdown.marked(text);
18823 // Wraps all "globals" so that the only thing
18824 // exposed is makeHtml().
18830 * eval:var:unescape
18838 var escape = function (html, encode) {
18840 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
18841 .replace(/</g, '<')
18842 .replace(/>/g, '>')
18843 .replace(/"/g, '"')
18844 .replace(/'/g, ''');
18847 var unescape = function (html) {
18848 // explicitly match decimal, hex, and named HTML entities
18849 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
18850 n = n.toLowerCase();
18851 if (n === 'colon') { return ':'; }
18852 if (n.charAt(0) === '#') {
18853 return n.charAt(1) === 'x'
18854 ? String.fromCharCode(parseInt(n.substring(2), 16))
18855 : String.fromCharCode(+n.substring(1));
18861 var replace = function (regex, opt) {
18862 regex = regex.source;
18864 return function self(name, val) {
18865 if (!name) { return new RegExp(regex, opt); }
18866 val = val.source || val;
18867 val = val.replace(/(^|[^\[])\^/g, '$1');
18868 regex = regex.replace(name, val);
18877 var noop = function () {}
18883 var merge = function (obj) {
18888 for (; i < arguments.length; i++) {
18889 target = arguments[i];
18890 for (key in target) {
18891 if (Object.prototype.hasOwnProperty.call(target, key)) {
18892 obj[key] = target[key];
18902 * Block-Level Grammar
18910 code: /^( {4}[^\n]+\n*)+/,
18912 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
18913 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
18915 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
18916 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
18917 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
18918 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
18919 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
18921 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
18925 block.bullet = /(?:[*+-]|\d+\.)/;
18926 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
18927 block.item = replace(block.item, 'gm')
18928 (/bull/g, block.bullet)
18931 block.list = replace(block.list)
18932 (/bull/g, block.bullet)
18933 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
18934 ('def', '\\n+(?=' + block.def.source + ')')
18937 block.blockquote = replace(block.blockquote)
18941 block._tag = '(?!(?:'
18942 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
18943 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
18944 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
18946 block.html = replace(block.html)
18947 ('comment', /<!--[\s\S]*?-->/)
18948 ('closed', /<(tag)[\s\S]+?<\/\1>/)
18949 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
18950 (/tag/g, block._tag)
18953 block.paragraph = replace(block.paragraph)
18955 ('heading', block.heading)
18956 ('lheading', block.lheading)
18957 ('blockquote', block.blockquote)
18958 ('tag', '<' + block._tag)
18963 * Normal Block Grammar
18966 block.normal = merge({}, block);
18969 * GFM Block Grammar
18972 block.gfm = merge({}, block.normal, {
18973 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
18975 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
18978 block.gfm.paragraph = replace(block.paragraph)
18980 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
18981 + block.list.source.replace('\\1', '\\3') + '|')
18985 * GFM + Tables Block Grammar
18988 block.tables = merge({}, block.gfm, {
18989 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
18990 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
18997 var Lexer = function (options) {
18999 this.tokens.links = {};
19000 this.options = options || marked.defaults;
19001 this.rules = block.normal;
19003 if (this.options.gfm) {
19004 if (this.options.tables) {
19005 this.rules = block.tables;
19007 this.rules = block.gfm;
19013 * Expose Block Rules
19016 Lexer.rules = block;
19019 * Static Lex Method
19022 Lexer.lex = function(src, options) {
19023 var lexer = new Lexer(options);
19024 return lexer.lex(src);
19031 Lexer.prototype.lex = function(src) {
19033 .replace(/\r\n|\r/g, '\n')
19034 .replace(/\t/g, ' ')
19035 .replace(/\u00a0/g, ' ')
19036 .replace(/\u2424/g, '\n');
19038 return this.token(src, true);
19045 Lexer.prototype.token = function(src, top, bq) {
19046 var src = src.replace(/^ +$/gm, '')
19059 if (cap = this.rules.newline.exec(src)) {
19060 src = src.substring(cap[0].length);
19061 if (cap[0].length > 1) {
19069 if (cap = this.rules.code.exec(src)) {
19070 src = src.substring(cap[0].length);
19071 cap = cap[0].replace(/^ {4}/gm, '');
19074 text: !this.options.pedantic
19075 ? cap.replace(/\n+$/, '')
19082 if (cap = this.rules.fences.exec(src)) {
19083 src = src.substring(cap[0].length);
19093 if (cap = this.rules.heading.exec(src)) {
19094 src = src.substring(cap[0].length);
19097 depth: cap[1].length,
19103 // table no leading pipe (gfm)
19104 if (top && (cap = this.rules.nptable.exec(src))) {
19105 src = src.substring(cap[0].length);
19109 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
19110 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
19111 cells: cap[3].replace(/\n$/, '').split('\n')
19114 for (i = 0; i < item.align.length; i++) {
19115 if (/^ *-+: *$/.test(item.align[i])) {
19116 item.align[i] = 'right';
19117 } else if (/^ *:-+: *$/.test(item.align[i])) {
19118 item.align[i] = 'center';
19119 } else if (/^ *:-+ *$/.test(item.align[i])) {
19120 item.align[i] = 'left';
19122 item.align[i] = null;
19126 for (i = 0; i < item.cells.length; i++) {
19127 item.cells[i] = item.cells[i].split(/ *\| */);
19130 this.tokens.push(item);
19136 if (cap = this.rules.lheading.exec(src)) {
19137 src = src.substring(cap[0].length);
19140 depth: cap[2] === '=' ? 1 : 2,
19147 if (cap = this.rules.hr.exec(src)) {
19148 src = src.substring(cap[0].length);
19156 if (cap = this.rules.blockquote.exec(src)) {
19157 src = src.substring(cap[0].length);
19160 type: 'blockquote_start'
19163 cap = cap[0].replace(/^ *> ?/gm, '');
19165 // Pass `top` to keep the current
19166 // "toplevel" state. This is exactly
19167 // how markdown.pl works.
19168 this.token(cap, top, true);
19171 type: 'blockquote_end'
19178 if (cap = this.rules.list.exec(src)) {
19179 src = src.substring(cap[0].length);
19183 type: 'list_start',
19184 ordered: bull.length > 1
19187 // Get each top-level item.
19188 cap = cap[0].match(this.rules.item);
19194 for (; i < l; i++) {
19197 // Remove the list item's bullet
19198 // so it is seen as the next token.
19199 space = item.length;
19200 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
19202 // Outdent whatever the
19203 // list item contains. Hacky.
19204 if (~item.indexOf('\n ')) {
19205 space -= item.length;
19206 item = !this.options.pedantic
19207 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
19208 : item.replace(/^ {1,4}/gm, '');
19211 // Determine whether the next list item belongs here.
19212 // Backpedal if it does not belong in this list.
19213 if (this.options.smartLists && i !== l - 1) {
19214 b = block.bullet.exec(cap[i + 1])[0];
19215 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
19216 src = cap.slice(i + 1).join('\n') + src;
19221 // Determine whether item is loose or not.
19222 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
19223 // for discount behavior.
19224 loose = next || /\n\n(?!\s*$)/.test(item);
19226 next = item.charAt(item.length - 1) === '\n';
19227 if (!loose) { loose = next; }
19232 ? 'loose_item_start'
19233 : 'list_item_start'
19237 this.token(item, false, bq);
19240 type: 'list_item_end'
19252 if (cap = this.rules.html.exec(src)) {
19253 src = src.substring(cap[0].length);
19255 type: this.options.sanitize
19258 pre: !this.options.sanitizer
19259 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
19266 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
19267 src = src.substring(cap[0].length);
19268 this.tokens.links[cap[1].toLowerCase()] = {
19276 if (top && (cap = this.rules.table.exec(src))) {
19277 src = src.substring(cap[0].length);
19281 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
19282 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
19283 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
19286 for (i = 0; i < item.align.length; i++) {
19287 if (/^ *-+: *$/.test(item.align[i])) {
19288 item.align[i] = 'right';
19289 } else if (/^ *:-+: *$/.test(item.align[i])) {
19290 item.align[i] = 'center';
19291 } else if (/^ *:-+ *$/.test(item.align[i])) {
19292 item.align[i] = 'left';
19294 item.align[i] = null;
19298 for (i = 0; i < item.cells.length; i++) {
19299 item.cells[i] = item.cells[i]
19300 .replace(/^ *\| *| *\| *$/g, '')
19304 this.tokens.push(item);
19309 // top-level paragraph
19310 if (top && (cap = this.rules.paragraph.exec(src))) {
19311 src = src.substring(cap[0].length);
19314 text: cap[1].charAt(cap[1].length - 1) === '\n'
19315 ? cap[1].slice(0, -1)
19322 if (cap = this.rules.text.exec(src)) {
19323 // Top-level should never reach here.
19324 src = src.substring(cap[0].length);
19334 Error('Infinite loop on byte: ' + src.charCodeAt(0));
19338 return this.tokens;
19342 * Inline-Level Grammar
19346 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
19347 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
19349 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
19350 link: /^!?\[(inside)\]\(href\)/,
19351 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
19352 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
19353 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
19354 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
19355 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
19356 br: /^ {2,}\n(?!\s*$)/,
19358 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
19361 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
19362 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
19364 inline.link = replace(inline.link)
19365 ('inside', inline._inside)
19366 ('href', inline._href)
19369 inline.reflink = replace(inline.reflink)
19370 ('inside', inline._inside)
19374 * Normal Inline Grammar
19377 inline.normal = merge({}, inline);
19380 * Pedantic Inline Grammar
19383 inline.pedantic = merge({}, inline.normal, {
19384 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
19385 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
19389 * GFM Inline Grammar
19392 inline.gfm = merge({}, inline.normal, {
19393 escape: replace(inline.escape)('])', '~|])')(),
19394 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
19395 del: /^~~(?=\S)([\s\S]*?\S)~~/,
19396 text: replace(inline.text)
19398 ('|', '|https?://|')
19403 * GFM + Line Breaks Inline Grammar
19406 inline.breaks = merge({}, inline.gfm, {
19407 br: replace(inline.br)('{2,}', '*')(),
19408 text: replace(inline.gfm.text)('{2,}', '*')()
19412 * Inline Lexer & Compiler
19415 var InlineLexer = function (links, options) {
19416 this.options = options || marked.defaults;
19417 this.links = links;
19418 this.rules = inline.normal;
19419 this.renderer = this.options.renderer || new Renderer;
19420 this.renderer.options = this.options;
19424 Error('Tokens array requires a `links` property.');
19427 if (this.options.gfm) {
19428 if (this.options.breaks) {
19429 this.rules = inline.breaks;
19431 this.rules = inline.gfm;
19433 } else if (this.options.pedantic) {
19434 this.rules = inline.pedantic;
19439 * Expose Inline Rules
19442 InlineLexer.rules = inline;
19445 * Static Lexing/Compiling Method
19448 InlineLexer.output = function(src, links, options) {
19449 var inline = new InlineLexer(links, options);
19450 return inline.output(src);
19457 InlineLexer.prototype.output = function(src) {
19466 if (cap = this.rules.escape.exec(src)) {
19467 src = src.substring(cap[0].length);
19473 if (cap = this.rules.autolink.exec(src)) {
19474 src = src.substring(cap[0].length);
19475 if (cap[2] === '@') {
19476 text = cap[1].charAt(6) === ':'
19477 ? this.mangle(cap[1].substring(7))
19478 : this.mangle(cap[1]);
19479 href = this.mangle('mailto:') + text;
19481 text = escape(cap[1]);
19484 out += this.renderer.link(href, null, text);
19489 if (!this.inLink && (cap = this.rules.url.exec(src))) {
19490 src = src.substring(cap[0].length);
19491 text = escape(cap[1]);
19493 out += this.renderer.link(href, null, text);
19498 if (cap = this.rules.tag.exec(src)) {
19499 if (!this.inLink && /^<a /i.test(cap[0])) {
19500 this.inLink = true;
19501 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
19502 this.inLink = false;
19504 src = src.substring(cap[0].length);
19505 out += this.options.sanitize
19506 ? this.options.sanitizer
19507 ? this.options.sanitizer(cap[0])
19514 if (cap = this.rules.link.exec(src)) {
19515 src = src.substring(cap[0].length);
19516 this.inLink = true;
19517 out += this.outputLink(cap, {
19521 this.inLink = false;
19526 if ((cap = this.rules.reflink.exec(src))
19527 || (cap = this.rules.nolink.exec(src))) {
19528 src = src.substring(cap[0].length);
19529 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
19530 link = this.links[link.toLowerCase()];
19531 if (!link || !link.href) {
19532 out += cap[0].charAt(0);
19533 src = cap[0].substring(1) + src;
19536 this.inLink = true;
19537 out += this.outputLink(cap, link);
19538 this.inLink = false;
19543 if (cap = this.rules.strong.exec(src)) {
19544 src = src.substring(cap[0].length);
19545 out += this.renderer.strong(this.output(cap[2] || cap[1]));
19550 if (cap = this.rules.em.exec(src)) {
19551 src = src.substring(cap[0].length);
19552 out += this.renderer.em(this.output(cap[2] || cap[1]));
19557 if (cap = this.rules.code.exec(src)) {
19558 src = src.substring(cap[0].length);
19559 out += this.renderer.codespan(escape(cap[2], true));
19564 if (cap = this.rules.br.exec(src)) {
19565 src = src.substring(cap[0].length);
19566 out += this.renderer.br();
19571 if (cap = this.rules.del.exec(src)) {
19572 src = src.substring(cap[0].length);
19573 out += this.renderer.del(this.output(cap[1]));
19578 if (cap = this.rules.text.exec(src)) {
19579 src = src.substring(cap[0].length);
19580 out += this.renderer.text(escape(this.smartypants(cap[0])));
19586 Error('Infinite loop on byte: ' + src.charCodeAt(0));
19597 InlineLexer.prototype.outputLink = function(cap, link) {
19598 var href = escape(link.href)
19599 , title = link.title ? escape(link.title) : null;
19601 return cap[0].charAt(0) !== '!'
19602 ? this.renderer.link(href, title, this.output(cap[1]))
19603 : this.renderer.image(href, title, escape(cap[1]));
19607 * Smartypants Transformations
19610 InlineLexer.prototype.smartypants = function(text) {
19611 if (!this.options.smartypants) { return text; }
19614 .replace(/---/g, '\u2014')
19616 .replace(/--/g, '\u2013')
19618 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
19619 // closing singles & apostrophes
19620 .replace(/'/g, '\u2019')
19622 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
19624 .replace(/"/g, '\u201d')
19626 .replace(/\.{3}/g, '\u2026');
19633 InlineLexer.prototype.mangle = function(text) {
19634 if (!this.options.mangle) { return text; }
19640 for (; i < l; i++) {
19641 ch = text.charCodeAt(i);
19642 if (Math.random() > 0.5) {
19643 ch = 'x' + ch.toString(16);
19645 out += '&#' + ch + ';';
19656 * eval:var:Renderer
19659 var Renderer = function (options) {
19660 this.options = options || {};
19663 Renderer.prototype.code = function(code, lang, escaped) {
19664 if (this.options.highlight) {
19665 var out = this.options.highlight(code, lang);
19666 if (out != null && out !== code) {
19671 // hack!!! - it's already escapeD?
19676 return '<pre><code>'
19677 + (escaped ? code : escape(code, true))
19678 + '\n</code></pre>';
19681 return '<pre><code class="'
19682 + this.options.langPrefix
19683 + escape(lang, true)
19685 + (escaped ? code : escape(code, true))
19686 + '\n</code></pre>\n';
19689 Renderer.prototype.blockquote = function(quote) {
19690 return '<blockquote>\n' + quote + '</blockquote>\n';
19693 Renderer.prototype.html = function(html) {
19697 Renderer.prototype.heading = function(text, level, raw) {
19701 + this.options.headerPrefix
19702 + raw.toLowerCase().replace(/[^\w]+/g, '-')
19710 Renderer.prototype.hr = function() {
19711 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
19714 Renderer.prototype.list = function(body, ordered) {
19715 var type = ordered ? 'ol' : 'ul';
19716 return '<' + type + '>\n' + body + '</' + type + '>\n';
19719 Renderer.prototype.listitem = function(text) {
19720 return '<li>' + text + '</li>\n';
19723 Renderer.prototype.paragraph = function(text) {
19724 return '<p>' + text + '</p>\n';
19727 Renderer.prototype.table = function(header, body) {
19728 return '<table class="table table-striped">\n'
19738 Renderer.prototype.tablerow = function(content) {
19739 return '<tr>\n' + content + '</tr>\n';
19742 Renderer.prototype.tablecell = function(content, flags) {
19743 var type = flags.header ? 'th' : 'td';
19744 var tag = flags.align
19745 ? '<' + type + ' style="text-align:' + flags.align + '">'
19746 : '<' + type + '>';
19747 return tag + content + '</' + type + '>\n';
19750 // span level renderer
19751 Renderer.prototype.strong = function(text) {
19752 return '<strong>' + text + '</strong>';
19755 Renderer.prototype.em = function(text) {
19756 return '<em>' + text + '</em>';
19759 Renderer.prototype.codespan = function(text) {
19760 return '<code>' + text + '</code>';
19763 Renderer.prototype.br = function() {
19764 return this.options.xhtml ? '<br/>' : '<br>';
19767 Renderer.prototype.del = function(text) {
19768 return '<del>' + text + '</del>';
19771 Renderer.prototype.link = function(href, title, text) {
19772 if (this.options.sanitize) {
19774 var prot = decodeURIComponent(unescape(href))
19775 .replace(/[^\w:]/g, '')
19780 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
19784 var out = '<a href="' + href + '"';
19786 out += ' title="' + title + '"';
19788 out += '>' + text + '</a>';
19792 Renderer.prototype.image = function(href, title, text) {
19793 var out = '<img src="' + href + '" alt="' + text + '"';
19795 out += ' title="' + title + '"';
19797 out += this.options.xhtml ? '/>' : '>';
19801 Renderer.prototype.text = function(text) {
19806 * Parsing & Compiling
19812 var Parser= function (options) {
19815 this.options = options || marked.defaults;
19816 this.options.renderer = this.options.renderer || new Renderer;
19817 this.renderer = this.options.renderer;
19818 this.renderer.options = this.options;
19822 * Static Parse Method
19825 Parser.parse = function(src, options, renderer) {
19826 var parser = new Parser(options, renderer);
19827 return parser.parse(src);
19834 Parser.prototype.parse = function(src) {
19835 this.inline = new InlineLexer(src.links, this.options, this.renderer);
19836 this.tokens = src.reverse();
19839 while (this.next()) {
19850 Parser.prototype.next = function() {
19851 return this.token = this.tokens.pop();
19855 * Preview Next Token
19858 Parser.prototype.peek = function() {
19859 return this.tokens[this.tokens.length - 1] || 0;
19863 * Parse Text Tokens
19866 Parser.prototype.parseText = function() {
19867 var body = this.token.text;
19869 while (this.peek().type === 'text') {
19870 body += '\n' + this.next().text;
19873 return this.inline.output(body);
19877 * Parse Current Token
19880 Parser.prototype.tok = function() {
19881 switch (this.token.type) {
19886 return this.renderer.hr();
19889 return this.renderer.heading(
19890 this.inline.output(this.token.text),
19895 return this.renderer.code(this.token.text,
19897 this.token.escaped);
19910 for (i = 0; i < this.token.header.length; i++) {
19911 flags = { header: true, align: this.token.align[i] };
19912 cell += this.renderer.tablecell(
19913 this.inline.output(this.token.header[i]),
19914 { header: true, align: this.token.align[i] }
19917 header += this.renderer.tablerow(cell);
19919 for (i = 0; i < this.token.cells.length; i++) {
19920 row = this.token.cells[i];
19923 for (j = 0; j < row.length; j++) {
19924 cell += this.renderer.tablecell(
19925 this.inline.output(row[j]),
19926 { header: false, align: this.token.align[j] }
19930 body += this.renderer.tablerow(cell);
19932 return this.renderer.table(header, body);
19934 case 'blockquote_start': {
19937 while (this.next().type !== 'blockquote_end') {
19938 body += this.tok();
19941 return this.renderer.blockquote(body);
19943 case 'list_start': {
19945 , ordered = this.token.ordered;
19947 while (this.next().type !== 'list_end') {
19948 body += this.tok();
19951 return this.renderer.list(body, ordered);
19953 case 'list_item_start': {
19956 while (this.next().type !== 'list_item_end') {
19957 body += this.token.type === 'text'
19962 return this.renderer.listitem(body);
19964 case 'loose_item_start': {
19967 while (this.next().type !== 'list_item_end') {
19968 body += this.tok();
19971 return this.renderer.listitem(body);
19974 var html = !this.token.pre && !this.options.pedantic
19975 ? this.inline.output(this.token.text)
19977 return this.renderer.html(html);
19979 case 'paragraph': {
19980 return this.renderer.paragraph(this.inline.output(this.token.text));
19983 return this.renderer.paragraph(this.parseText());
19995 var marked = function (src, opt, callback) {
19996 if (callback || typeof opt === 'function') {
20002 opt = merge({}, marked.defaults, opt || {});
20004 var highlight = opt.highlight
20010 tokens = Lexer.lex(src, opt)
20012 return callback(e);
20015 pending = tokens.length;
20019 var done = function(err) {
20021 opt.highlight = highlight;
20022 return callback(err);
20028 out = Parser.parse(tokens, opt);
20033 opt.highlight = highlight;
20037 : callback(null, out);
20040 if (!highlight || highlight.length < 3) {
20044 delete opt.highlight;
20046 if (!pending) { return done(); }
20048 for (; i < tokens.length; i++) {
20050 if (token.type !== 'code') {
20051 return --pending || done();
20053 return highlight(token.text, token.lang, function(err, code) {
20054 if (err) { return done(err); }
20055 if (code == null || code === token.text) {
20056 return --pending || done();
20059 token.escaped = true;
20060 --pending || done();
20068 if (opt) { opt = merge({}, marked.defaults, opt); }
20069 return Parser.parse(Lexer.lex(src, opt), opt);
20071 e.message += '\nPlease report this to https://github.com/chjj/marked.';
20072 if ((opt || marked.defaults).silent) {
20073 return '<p>An error occured:</p><pre>'
20074 + escape(e.message + '', true)
20086 marked.setOptions = function(opt) {
20087 merge(marked.defaults, opt);
20091 marked.defaults = {
20102 langPrefix: 'lang-',
20103 smartypants: false,
20105 renderer: new Renderer,
20113 marked.Parser = Parser;
20114 marked.parser = Parser.parse;
20116 marked.Renderer = Renderer;
20118 marked.Lexer = Lexer;
20119 marked.lexer = Lexer.lex;
20121 marked.InlineLexer = InlineLexer;
20122 marked.inlineLexer = InlineLexer.output;
20124 marked.parse = marked;
20126 Roo.Markdown.marked = marked;
20130 * Ext JS Library 1.1.1
20131 * Copyright(c) 2006-2007, Ext JS, LLC.
20133 * Originally Released Under LGPL - original licence link has changed is not relivant.
20136 * <script type="text/javascript">
20142 * These classes are derivatives of the similarly named classes in the YUI Library.
20143 * The original license:
20144 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
20145 * Code licensed under the BSD License:
20146 * http://developer.yahoo.net/yui/license.txt
20151 var Event=Roo.EventManager;
20152 var Dom=Roo.lib.Dom;
20155 * @class Roo.dd.DragDrop
20156 * @extends Roo.util.Observable
20157 * Defines the interface and base operation of items that that can be
20158 * dragged or can be drop targets. It was designed to be extended, overriding
20159 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
20160 * Up to three html elements can be associated with a DragDrop instance:
20162 * <li>linked element: the element that is passed into the constructor.
20163 * This is the element which defines the boundaries for interaction with
20164 * other DragDrop objects.</li>
20165 * <li>handle element(s): The drag operation only occurs if the element that
20166 * was clicked matches a handle element. By default this is the linked
20167 * element, but there are times that you will want only a portion of the
20168 * linked element to initiate the drag operation, and the setHandleElId()
20169 * method provides a way to define this.</li>
20170 * <li>drag element: this represents the element that would be moved along
20171 * with the cursor during a drag operation. By default, this is the linked
20172 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
20173 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
20176 * This class should not be instantiated until the onload event to ensure that
20177 * the associated elements are available.
20178 * The following would define a DragDrop obj that would interact with any
20179 * other DragDrop obj in the "group1" group:
20181 * dd = new Roo.dd.DragDrop("div1", "group1");
20183 * Since none of the event handlers have been implemented, nothing would
20184 * actually happen if you were to run the code above. Normally you would
20185 * override this class or one of the default implementations, but you can
20186 * also override the methods you want on an instance of the class...
20188 * dd.onDragDrop = function(e, id) {
20189 * alert("dd was dropped on " + id);
20193 * @param {String} id of the element that is linked to this instance
20194 * @param {String} sGroup the group of related DragDrop objects
20195 * @param {object} config an object containing configurable attributes
20196 * Valid properties for DragDrop:
20197 * padding, isTarget, maintainOffset, primaryButtonOnly
20199 Roo.dd.DragDrop = function(id, sGroup, config) {
20201 this.init(id, sGroup, config);
20206 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
20209 * The id of the element associated with this object. This is what we
20210 * refer to as the "linked element" because the size and position of
20211 * this element is used to determine when the drag and drop objects have
20219 * Configuration attributes passed into the constructor
20226 * The id of the element that will be dragged. By default this is same
20227 * as the linked element , but could be changed to another element. Ex:
20229 * @property dragElId
20236 * the id of the element that initiates the drag operation. By default
20237 * this is the linked element, but could be changed to be a child of this
20238 * element. This lets us do things like only starting the drag when the
20239 * header element within the linked html element is clicked.
20240 * @property handleElId
20247 * An associative array of HTML tags that will be ignored if clicked.
20248 * @property invalidHandleTypes
20249 * @type {string: string}
20251 invalidHandleTypes: null,
20254 * An associative array of ids for elements that will be ignored if clicked
20255 * @property invalidHandleIds
20256 * @type {string: string}
20258 invalidHandleIds: null,
20261 * An indexted array of css class names for elements that will be ignored
20263 * @property invalidHandleClasses
20266 invalidHandleClasses: null,
20269 * The linked element's absolute X position at the time the drag was
20271 * @property startPageX
20278 * The linked element's absolute X position at the time the drag was
20280 * @property startPageY
20287 * The group defines a logical collection of DragDrop objects that are
20288 * related. Instances only get events when interacting with other
20289 * DragDrop object in the same group. This lets us define multiple
20290 * groups using a single DragDrop subclass if we want.
20292 * @type {string: string}
20297 * Individual drag/drop instances can be locked. This will prevent
20298 * onmousedown start drag.
20306 * Lock this instance
20309 lock: function() { this.locked = true; },
20312 * Unlock this instace
20315 unlock: function() { this.locked = false; },
20318 * By default, all insances can be a drop target. This can be disabled by
20319 * setting isTarget to false.
20326 * The padding configured for this drag and drop object for calculating
20327 * the drop zone intersection with this object.
20334 * Cached reference to the linked element
20335 * @property _domRef
20341 * Internal typeof flag
20342 * @property __ygDragDrop
20345 __ygDragDrop: true,
20348 * Set to true when horizontal contraints are applied
20349 * @property constrainX
20356 * Set to true when vertical contraints are applied
20357 * @property constrainY
20364 * The left constraint
20372 * The right constraint
20380 * The up constraint
20389 * The down constraint
20397 * Maintain offsets when we resetconstraints. Set to true when you want
20398 * the position of the element relative to its parent to stay the same
20399 * when the page changes
20401 * @property maintainOffset
20404 maintainOffset: false,
20407 * Array of pixel locations the element will snap to if we specified a
20408 * horizontal graduation/interval. This array is generated automatically
20409 * when you define a tick interval.
20416 * Array of pixel locations the element will snap to if we specified a
20417 * vertical graduation/interval. This array is generated automatically
20418 * when you define a tick interval.
20425 * By default the drag and drop instance will only respond to the primary
20426 * button click (left button for a right-handed mouse). Set to true to
20427 * allow drag and drop to start with any mouse click that is propogated
20429 * @property primaryButtonOnly
20432 primaryButtonOnly: true,
20435 * The availabe property is false until the linked dom element is accessible.
20436 * @property available
20442 * By default, drags can only be initiated if the mousedown occurs in the
20443 * region the linked element is. This is done in part to work around a
20444 * bug in some browsers that mis-report the mousedown if the previous
20445 * mouseup happened outside of the window. This property is set to true
20446 * if outer handles are defined.
20448 * @property hasOuterHandles
20452 hasOuterHandles: false,
20455 * Code that executes immediately before the startDrag event
20456 * @method b4StartDrag
20459 b4StartDrag: function(x, y) { },
20462 * Abstract method called after a drag/drop object is clicked
20463 * and the drag or mousedown time thresholds have beeen met.
20464 * @method startDrag
20465 * @param {int} X click location
20466 * @param {int} Y click location
20468 startDrag: function(x, y) { /* override this */ },
20471 * Code that executes immediately before the onDrag event
20475 b4Drag: function(e) { },
20478 * Abstract method called during the onMouseMove event while dragging an
20481 * @param {Event} e the mousemove event
20483 onDrag: function(e) { /* override this */ },
20486 * Abstract method called when this element fist begins hovering over
20487 * another DragDrop obj
20488 * @method onDragEnter
20489 * @param {Event} e the mousemove event
20490 * @param {String|DragDrop[]} id In POINT mode, the element
20491 * id this is hovering over. In INTERSECT mode, an array of one or more
20492 * dragdrop items being hovered over.
20494 onDragEnter: function(e, id) { /* override this */ },
20497 * Code that executes immediately before the onDragOver event
20498 * @method b4DragOver
20501 b4DragOver: function(e) { },
20504 * Abstract method called when this element is hovering over another
20506 * @method onDragOver
20507 * @param {Event} e the mousemove event
20508 * @param {String|DragDrop[]} id In POINT mode, the element
20509 * id this is hovering over. In INTERSECT mode, an array of dd items
20510 * being hovered over.
20512 onDragOver: function(e, id) { /* override this */ },
20515 * Code that executes immediately before the onDragOut event
20516 * @method b4DragOut
20519 b4DragOut: function(e) { },
20522 * Abstract method called when we are no longer hovering over an element
20523 * @method onDragOut
20524 * @param {Event} e the mousemove event
20525 * @param {String|DragDrop[]} id In POINT mode, the element
20526 * id this was hovering over. In INTERSECT mode, an array of dd items
20527 * that the mouse is no longer over.
20529 onDragOut: function(e, id) { /* override this */ },
20532 * Code that executes immediately before the onDragDrop event
20533 * @method b4DragDrop
20536 b4DragDrop: function(e) { },
20539 * Abstract method called when this item is dropped on another DragDrop
20541 * @method onDragDrop
20542 * @param {Event} e the mouseup event
20543 * @param {String|DragDrop[]} id In POINT mode, the element
20544 * id this was dropped on. In INTERSECT mode, an array of dd items this
20547 onDragDrop: function(e, id) { /* override this */ },
20550 * Abstract method called when this item is dropped on an area with no
20552 * @method onInvalidDrop
20553 * @param {Event} e the mouseup event
20555 onInvalidDrop: function(e) { /* override this */ },
20558 * Code that executes immediately before the endDrag event
20559 * @method b4EndDrag
20562 b4EndDrag: function(e) { },
20565 * Fired when we are done dragging the object
20567 * @param {Event} e the mouseup event
20569 endDrag: function(e) { /* override this */ },
20572 * Code executed immediately before the onMouseDown event
20573 * @method b4MouseDown
20574 * @param {Event} e the mousedown event
20577 b4MouseDown: function(e) { },
20580 * Event handler that fires when a drag/drop obj gets a mousedown
20581 * @method onMouseDown
20582 * @param {Event} e the mousedown event
20584 onMouseDown: function(e) { /* override this */ },
20587 * Event handler that fires when a drag/drop obj gets a mouseup
20588 * @method onMouseUp
20589 * @param {Event} e the mouseup event
20591 onMouseUp: function(e) { /* override this */ },
20594 * Override the onAvailable method to do what is needed after the initial
20595 * position was determined.
20596 * @method onAvailable
20598 onAvailable: function () {
20602 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
20605 defaultPadding : {left:0, right:0, top:0, bottom:0},
20608 * Initializes the drag drop object's constraints to restrict movement to a certain element.
20612 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
20613 { dragElId: "existingProxyDiv" });
20614 dd.startDrag = function(){
20615 this.constrainTo("parent-id");
20618 * Or you can initalize it using the {@link Roo.Element} object:
20620 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
20621 startDrag : function(){
20622 this.constrainTo("parent-id");
20626 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
20627 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
20628 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
20629 * an object containing the sides to pad. For example: {right:10, bottom:10}
20630 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
20632 constrainTo : function(constrainTo, pad, inContent){
20633 if(typeof pad == "number"){
20634 pad = {left: pad, right:pad, top:pad, bottom:pad};
20636 pad = pad || this.defaultPadding;
20637 var b = Roo.get(this.getEl()).getBox();
20638 var ce = Roo.get(constrainTo);
20639 var s = ce.getScroll();
20640 var c, cd = ce.dom;
20641 if(cd == document.body){
20642 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
20645 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
20649 var topSpace = b.y - c.y;
20650 var leftSpace = b.x - c.x;
20652 this.resetConstraints();
20653 this.setXConstraint(leftSpace - (pad.left||0), // left
20654 c.width - leftSpace - b.width - (pad.right||0) //right
20656 this.setYConstraint(topSpace - (pad.top||0), //top
20657 c.height - topSpace - b.height - (pad.bottom||0) //bottom
20662 * Returns a reference to the linked element
20664 * @return {HTMLElement} the html element
20666 getEl: function() {
20667 if (!this._domRef) {
20668 this._domRef = Roo.getDom(this.id);
20671 return this._domRef;
20675 * Returns a reference to the actual element to drag. By default this is
20676 * the same as the html element, but it can be assigned to another
20677 * element. An example of this can be found in Roo.dd.DDProxy
20678 * @method getDragEl
20679 * @return {HTMLElement} the html element
20681 getDragEl: function() {
20682 return Roo.getDom(this.dragElId);
20686 * Sets up the DragDrop object. Must be called in the constructor of any
20687 * Roo.dd.DragDrop subclass
20689 * @param id the id of the linked element
20690 * @param {String} sGroup the group of related items
20691 * @param {object} config configuration attributes
20693 init: function(id, sGroup, config) {
20694 this.initTarget(id, sGroup, config);
20695 if (!Roo.isTouch) {
20696 Event.on(this.id, "mousedown", this.handleMouseDown, this);
20698 Event.on(this.id, "touchstart", this.handleMouseDown, this);
20699 // Event.on(this.id, "selectstart", Event.preventDefault);
20703 * Initializes Targeting functionality only... the object does not
20704 * get a mousedown handler.
20705 * @method initTarget
20706 * @param id the id of the linked element
20707 * @param {String} sGroup the group of related items
20708 * @param {object} config configuration attributes
20710 initTarget: function(id, sGroup, config) {
20712 // configuration attributes
20713 this.config = config || {};
20715 // create a local reference to the drag and drop manager
20716 this.DDM = Roo.dd.DDM;
20717 // initialize the groups array
20720 // assume that we have an element reference instead of an id if the
20721 // parameter is not a string
20722 if (typeof id !== "string") {
20729 // add to an interaction group
20730 this.addToGroup((sGroup) ? sGroup : "default");
20732 // We don't want to register this as the handle with the manager
20733 // so we just set the id rather than calling the setter.
20734 this.handleElId = id;
20736 // the linked element is the element that gets dragged by default
20737 this.setDragElId(id);
20739 // by default, clicked anchors will not start drag operations.
20740 this.invalidHandleTypes = { A: "A" };
20741 this.invalidHandleIds = {};
20742 this.invalidHandleClasses = [];
20744 this.applyConfig();
20746 this.handleOnAvailable();
20750 * Applies the configuration parameters that were passed into the constructor.
20751 * This is supposed to happen at each level through the inheritance chain. So
20752 * a DDProxy implentation will execute apply config on DDProxy, DD, and
20753 * DragDrop in order to get all of the parameters that are available in
20755 * @method applyConfig
20757 applyConfig: function() {
20759 // configurable properties:
20760 // padding, isTarget, maintainOffset, primaryButtonOnly
20761 this.padding = this.config.padding || [0, 0, 0, 0];
20762 this.isTarget = (this.config.isTarget !== false);
20763 this.maintainOffset = (this.config.maintainOffset);
20764 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
20769 * Executed when the linked element is available
20770 * @method handleOnAvailable
20773 handleOnAvailable: function() {
20774 this.available = true;
20775 this.resetConstraints();
20776 this.onAvailable();
20780 * Configures the padding for the target zone in px. Effectively expands
20781 * (or reduces) the virtual object size for targeting calculations.
20782 * Supports css-style shorthand; if only one parameter is passed, all sides
20783 * will have that padding, and if only two are passed, the top and bottom
20784 * will have the first param, the left and right the second.
20785 * @method setPadding
20786 * @param {int} iTop Top pad
20787 * @param {int} iRight Right pad
20788 * @param {int} iBot Bot pad
20789 * @param {int} iLeft Left pad
20791 setPadding: function(iTop, iRight, iBot, iLeft) {
20792 // this.padding = [iLeft, iRight, iTop, iBot];
20793 if (!iRight && 0 !== iRight) {
20794 this.padding = [iTop, iTop, iTop, iTop];
20795 } else if (!iBot && 0 !== iBot) {
20796 this.padding = [iTop, iRight, iTop, iRight];
20798 this.padding = [iTop, iRight, iBot, iLeft];
20803 * Stores the initial placement of the linked element.
20804 * @method setInitialPosition
20805 * @param {int} diffX the X offset, default 0
20806 * @param {int} diffY the Y offset, default 0
20808 setInitPosition: function(diffX, diffY) {
20809 var el = this.getEl();
20811 if (!this.DDM.verifyEl(el)) {
20815 var dx = diffX || 0;
20816 var dy = diffY || 0;
20818 var p = Dom.getXY( el );
20820 this.initPageX = p[0] - dx;
20821 this.initPageY = p[1] - dy;
20823 this.lastPageX = p[0];
20824 this.lastPageY = p[1];
20827 this.setStartPosition(p);
20831 * Sets the start position of the element. This is set when the obj
20832 * is initialized, the reset when a drag is started.
20833 * @method setStartPosition
20834 * @param pos current position (from previous lookup)
20837 setStartPosition: function(pos) {
20838 var p = pos || Dom.getXY( this.getEl() );
20839 this.deltaSetXY = null;
20841 this.startPageX = p[0];
20842 this.startPageY = p[1];
20846 * Add this instance to a group of related drag/drop objects. All
20847 * instances belong to at least one group, and can belong to as many
20848 * groups as needed.
20849 * @method addToGroup
20850 * @param sGroup {string} the name of the group
20852 addToGroup: function(sGroup) {
20853 this.groups[sGroup] = true;
20854 this.DDM.regDragDrop(this, sGroup);
20858 * Remove's this instance from the supplied interaction group
20859 * @method removeFromGroup
20860 * @param {string} sGroup The group to drop
20862 removeFromGroup: function(sGroup) {
20863 if (this.groups[sGroup]) {
20864 delete this.groups[sGroup];
20867 this.DDM.removeDDFromGroup(this, sGroup);
20871 * Allows you to specify that an element other than the linked element
20872 * will be moved with the cursor during a drag
20873 * @method setDragElId
20874 * @param id {string} the id of the element that will be used to initiate the drag
20876 setDragElId: function(id) {
20877 this.dragElId = id;
20881 * Allows you to specify a child of the linked element that should be
20882 * used to initiate the drag operation. An example of this would be if
20883 * you have a content div with text and links. Clicking anywhere in the
20884 * content area would normally start the drag operation. Use this method
20885 * to specify that an element inside of the content div is the element
20886 * that starts the drag operation.
20887 * @method setHandleElId
20888 * @param id {string} the id of the element that will be used to
20889 * initiate the drag.
20891 setHandleElId: function(id) {
20892 if (typeof id !== "string") {
20895 this.handleElId = id;
20896 this.DDM.regHandle(this.id, id);
20900 * Allows you to set an element outside of the linked element as a drag
20902 * @method setOuterHandleElId
20903 * @param id the id of the element that will be used to initiate the drag
20905 setOuterHandleElId: function(id) {
20906 if (typeof id !== "string") {
20909 Event.on(id, "mousedown",
20910 this.handleMouseDown, this);
20911 this.setHandleElId(id);
20913 this.hasOuterHandles = true;
20917 * Remove all drag and drop hooks for this element
20920 unreg: function() {
20921 Event.un(this.id, "mousedown",
20922 this.handleMouseDown);
20923 Event.un(this.id, "touchstart",
20924 this.handleMouseDown);
20925 this._domRef = null;
20926 this.DDM._remove(this);
20929 destroy : function(){
20934 * Returns true if this instance is locked, or the drag drop mgr is locked
20935 * (meaning that all drag/drop is disabled on the page.)
20937 * @return {boolean} true if this obj or all drag/drop is locked, else
20940 isLocked: function() {
20941 return (this.DDM.isLocked() || this.locked);
20945 * Fired when this object is clicked
20946 * @method handleMouseDown
20948 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
20951 handleMouseDown: function(e, oDD){
20953 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
20954 //Roo.log('not touch/ button !=0');
20957 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
20958 return; // double touch..
20962 if (this.isLocked()) {
20963 //Roo.log('locked');
20967 this.DDM.refreshCache(this.groups);
20968 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
20969 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
20970 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
20971 //Roo.log('no outer handes or not over target');
20974 // Roo.log('check validator');
20975 if (this.clickValidator(e)) {
20976 // Roo.log('validate success');
20977 // set the initial element position
20978 this.setStartPosition();
20981 this.b4MouseDown(e);
20982 this.onMouseDown(e);
20984 this.DDM.handleMouseDown(e, this);
20986 this.DDM.stopEvent(e);
20994 clickValidator: function(e) {
20995 var target = e.getTarget();
20996 return ( this.isValidHandleChild(target) &&
20997 (this.id == this.handleElId ||
20998 this.DDM.handleWasClicked(target, this.id)) );
21002 * Allows you to specify a tag name that should not start a drag operation
21003 * when clicked. This is designed to facilitate embedding links within a
21004 * drag handle that do something other than start the drag.
21005 * @method addInvalidHandleType
21006 * @param {string} tagName the type of element to exclude
21008 addInvalidHandleType: function(tagName) {
21009 var type = tagName.toUpperCase();
21010 this.invalidHandleTypes[type] = type;
21014 * Lets you to specify an element id for a child of a drag handle
21015 * that should not initiate a drag
21016 * @method addInvalidHandleId
21017 * @param {string} id the element id of the element you wish to ignore
21019 addInvalidHandleId: function(id) {
21020 if (typeof id !== "string") {
21023 this.invalidHandleIds[id] = id;
21027 * Lets you specify a css class of elements that will not initiate a drag
21028 * @method addInvalidHandleClass
21029 * @param {string} cssClass the class of the elements you wish to ignore
21031 addInvalidHandleClass: function(cssClass) {
21032 this.invalidHandleClasses.push(cssClass);
21036 * Unsets an excluded tag name set by addInvalidHandleType
21037 * @method removeInvalidHandleType
21038 * @param {string} tagName the type of element to unexclude
21040 removeInvalidHandleType: function(tagName) {
21041 var type = tagName.toUpperCase();
21042 // this.invalidHandleTypes[type] = null;
21043 delete this.invalidHandleTypes[type];
21047 * Unsets an invalid handle id
21048 * @method removeInvalidHandleId
21049 * @param {string} id the id of the element to re-enable
21051 removeInvalidHandleId: function(id) {
21052 if (typeof id !== "string") {
21055 delete this.invalidHandleIds[id];
21059 * Unsets an invalid css class
21060 * @method removeInvalidHandleClass
21061 * @param {string} cssClass the class of the element(s) you wish to
21064 removeInvalidHandleClass: function(cssClass) {
21065 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
21066 if (this.invalidHandleClasses[i] == cssClass) {
21067 delete this.invalidHandleClasses[i];
21073 * Checks the tag exclusion list to see if this click should be ignored
21074 * @method isValidHandleChild
21075 * @param {HTMLElement} node the HTMLElement to evaluate
21076 * @return {boolean} true if this is a valid tag type, false if not
21078 isValidHandleChild: function(node) {
21081 // var n = (node.nodeName == "#text") ? node.parentNode : node;
21084 nodeName = node.nodeName.toUpperCase();
21086 nodeName = node.nodeName;
21088 valid = valid && !this.invalidHandleTypes[nodeName];
21089 valid = valid && !this.invalidHandleIds[node.id];
21091 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
21092 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
21101 * Create the array of horizontal tick marks if an interval was specified
21102 * in setXConstraint().
21103 * @method setXTicks
21106 setXTicks: function(iStartX, iTickSize) {
21108 this.xTickSize = iTickSize;
21112 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
21114 this.xTicks[this.xTicks.length] = i;
21119 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
21121 this.xTicks[this.xTicks.length] = i;
21126 this.xTicks.sort(this.DDM.numericSort) ;
21130 * Create the array of vertical tick marks if an interval was specified in
21131 * setYConstraint().
21132 * @method setYTicks
21135 setYTicks: function(iStartY, iTickSize) {
21137 this.yTickSize = iTickSize;
21141 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
21143 this.yTicks[this.yTicks.length] = i;
21148 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
21150 this.yTicks[this.yTicks.length] = i;
21155 this.yTicks.sort(this.DDM.numericSort) ;
21159 * By default, the element can be dragged any place on the screen. Use
21160 * this method to limit the horizontal travel of the element. Pass in
21161 * 0,0 for the parameters if you want to lock the drag to the y axis.
21162 * @method setXConstraint
21163 * @param {int} iLeft the number of pixels the element can move to the left
21164 * @param {int} iRight the number of pixels the element can move to the
21166 * @param {int} iTickSize optional parameter for specifying that the
21168 * should move iTickSize pixels at a time.
21170 setXConstraint: function(iLeft, iRight, iTickSize) {
21171 this.leftConstraint = iLeft;
21172 this.rightConstraint = iRight;
21174 this.minX = this.initPageX - iLeft;
21175 this.maxX = this.initPageX + iRight;
21176 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
21178 this.constrainX = true;
21182 * Clears any constraints applied to this instance. Also clears ticks
21183 * since they can't exist independent of a constraint at this time.
21184 * @method clearConstraints
21186 clearConstraints: function() {
21187 this.constrainX = false;
21188 this.constrainY = false;
21193 * Clears any tick interval defined for this instance
21194 * @method clearTicks
21196 clearTicks: function() {
21197 this.xTicks = null;
21198 this.yTicks = null;
21199 this.xTickSize = 0;
21200 this.yTickSize = 0;
21204 * By default, the element can be dragged any place on the screen. Set
21205 * this to limit the vertical travel of the element. Pass in 0,0 for the
21206 * parameters if you want to lock the drag to the x axis.
21207 * @method setYConstraint
21208 * @param {int} iUp the number of pixels the element can move up
21209 * @param {int} iDown the number of pixels the element can move down
21210 * @param {int} iTickSize optional parameter for specifying that the
21211 * element should move iTickSize pixels at a time.
21213 setYConstraint: function(iUp, iDown, iTickSize) {
21214 this.topConstraint = iUp;
21215 this.bottomConstraint = iDown;
21217 this.minY = this.initPageY - iUp;
21218 this.maxY = this.initPageY + iDown;
21219 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
21221 this.constrainY = true;
21226 * resetConstraints must be called if you manually reposition a dd element.
21227 * @method resetConstraints
21228 * @param {boolean} maintainOffset
21230 resetConstraints: function() {
21233 // Maintain offsets if necessary
21234 if (this.initPageX || this.initPageX === 0) {
21235 // figure out how much this thing has moved
21236 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
21237 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
21239 this.setInitPosition(dx, dy);
21241 // This is the first time we have detected the element's position
21243 this.setInitPosition();
21246 if (this.constrainX) {
21247 this.setXConstraint( this.leftConstraint,
21248 this.rightConstraint,
21252 if (this.constrainY) {
21253 this.setYConstraint( this.topConstraint,
21254 this.bottomConstraint,
21260 * Normally the drag element is moved pixel by pixel, but we can specify
21261 * that it move a number of pixels at a time. This method resolves the
21262 * location when we have it set up like this.
21264 * @param {int} val where we want to place the object
21265 * @param {int[]} tickArray sorted array of valid points
21266 * @return {int} the closest tick
21269 getTick: function(val, tickArray) {
21272 // If tick interval is not defined, it is effectively 1 pixel,
21273 // so we return the value passed to us.
21275 } else if (tickArray[0] >= val) {
21276 // The value is lower than the first tick, so we return the first
21278 return tickArray[0];
21280 for (var i=0, len=tickArray.length; i<len; ++i) {
21282 if (tickArray[next] && tickArray[next] >= val) {
21283 var diff1 = val - tickArray[i];
21284 var diff2 = tickArray[next] - val;
21285 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
21289 // The value is larger than the last tick, so we return the last
21291 return tickArray[tickArray.length - 1];
21298 * @return {string} string representation of the dd obj
21300 toString: function() {
21301 return ("DragDrop " + this.id);
21309 * Ext JS Library 1.1.1
21310 * Copyright(c) 2006-2007, Ext JS, LLC.
21312 * Originally Released Under LGPL - original licence link has changed is not relivant.
21315 * <script type="text/javascript">
21320 * The drag and drop utility provides a framework for building drag and drop
21321 * applications. In addition to enabling drag and drop for specific elements,
21322 * the drag and drop elements are tracked by the manager class, and the
21323 * interactions between the various elements are tracked during the drag and
21324 * the implementing code is notified about these important moments.
21327 // Only load the library once. Rewriting the manager class would orphan
21328 // existing drag and drop instances.
21329 if (!Roo.dd.DragDropMgr) {
21332 * @class Roo.dd.DragDropMgr
21333 * DragDropMgr is a singleton that tracks the element interaction for
21334 * all DragDrop items in the window. Generally, you will not call
21335 * this class directly, but it does have helper methods that could
21336 * be useful in your DragDrop implementations.
21339 Roo.dd.DragDropMgr = function() {
21341 var Event = Roo.EventManager;
21346 * Two dimensional Array of registered DragDrop objects. The first
21347 * dimension is the DragDrop item group, the second the DragDrop
21350 * @type {string: string}
21357 * Array of element ids defined as drag handles. Used to determine
21358 * if the element that generated the mousedown event is actually the
21359 * handle and not the html element itself.
21360 * @property handleIds
21361 * @type {string: string}
21368 * the DragDrop object that is currently being dragged
21369 * @property dragCurrent
21377 * the DragDrop object(s) that are being hovered over
21378 * @property dragOvers
21386 * the X distance between the cursor and the object being dragged
21395 * the Y distance between the cursor and the object being dragged
21404 * Flag to determine if we should prevent the default behavior of the
21405 * events we define. By default this is true, but this can be set to
21406 * false if you need the default behavior (not recommended)
21407 * @property preventDefault
21411 preventDefault: true,
21414 * Flag to determine if we should stop the propagation of the events
21415 * we generate. This is true by default but you may want to set it to
21416 * false if the html element contains other features that require the
21418 * @property stopPropagation
21422 stopPropagation: true,
21425 * Internal flag that is set to true when drag and drop has been
21427 * @property initialized
21434 * All drag and drop can be disabled.
21442 * Called the first time an element is registered.
21448 this.initialized = true;
21452 * In point mode, drag and drop interaction is defined by the
21453 * location of the cursor during the drag/drop
21461 * In intersect mode, drag and drop interactio nis defined by the
21462 * overlap of two or more drag and drop objects.
21463 * @property INTERSECT
21470 * The current drag and drop mode. Default: POINT
21478 * Runs method on all drag and drop objects
21479 * @method _execOnAll
21483 _execOnAll: function(sMethod, args) {
21484 for (var i in this.ids) {
21485 for (var j in this.ids[i]) {
21486 var oDD = this.ids[i][j];
21487 if (! this.isTypeOfDD(oDD)) {
21490 oDD[sMethod].apply(oDD, args);
21496 * Drag and drop initialization. Sets up the global event handlers
21501 _onLoad: function() {
21505 if (!Roo.isTouch) {
21506 Event.on(document, "mouseup", this.handleMouseUp, this, true);
21507 Event.on(document, "mousemove", this.handleMouseMove, this, true);
21509 Event.on(document, "touchend", this.handleMouseUp, this, true);
21510 Event.on(document, "touchmove", this.handleMouseMove, this, true);
21512 Event.on(window, "unload", this._onUnload, this, true);
21513 Event.on(window, "resize", this._onResize, this, true);
21514 // Event.on(window, "mouseout", this._test);
21519 * Reset constraints on all drag and drop objs
21520 * @method _onResize
21524 _onResize: function(e) {
21525 this._execOnAll("resetConstraints", []);
21529 * Lock all drag and drop functionality
21533 lock: function() { this.locked = true; },
21536 * Unlock all drag and drop functionality
21540 unlock: function() { this.locked = false; },
21543 * Is drag and drop locked?
21545 * @return {boolean} True if drag and drop is locked, false otherwise.
21548 isLocked: function() { return this.locked; },
21551 * Location cache that is set for all drag drop objects when a drag is
21552 * initiated, cleared when the drag is finished.
21553 * @property locationCache
21560 * Set useCache to false if you want to force object the lookup of each
21561 * drag and drop linked element constantly during a drag.
21562 * @property useCache
21569 * The number of pixels that the mouse needs to move after the
21570 * mousedown before the drag is initiated. Default=3;
21571 * @property clickPixelThresh
21575 clickPixelThresh: 3,
21578 * The number of milliseconds after the mousedown event to initiate the
21579 * drag if we don't get a mouseup event. Default=1000
21580 * @property clickTimeThresh
21584 clickTimeThresh: 350,
21587 * Flag that indicates that either the drag pixel threshold or the
21588 * mousdown time threshold has been met
21589 * @property dragThreshMet
21594 dragThreshMet: false,
21597 * Timeout used for the click time threshold
21598 * @property clickTimeout
21603 clickTimeout: null,
21606 * The X position of the mousedown event stored for later use when a
21607 * drag threshold is met.
21616 * The Y position of the mousedown event stored for later use when a
21617 * drag threshold is met.
21626 * Each DragDrop instance must be registered with the DragDropMgr.
21627 * This is executed in DragDrop.init()
21628 * @method regDragDrop
21629 * @param {DragDrop} oDD the DragDrop object to register
21630 * @param {String} sGroup the name of the group this element belongs to
21633 regDragDrop: function(oDD, sGroup) {
21634 if (!this.initialized) { this.init(); }
21636 if (!this.ids[sGroup]) {
21637 this.ids[sGroup] = {};
21639 this.ids[sGroup][oDD.id] = oDD;
21643 * Removes the supplied dd instance from the supplied group. Executed
21644 * by DragDrop.removeFromGroup, so don't call this function directly.
21645 * @method removeDDFromGroup
21649 removeDDFromGroup: function(oDD, sGroup) {
21650 if (!this.ids[sGroup]) {
21651 this.ids[sGroup] = {};
21654 var obj = this.ids[sGroup];
21655 if (obj && obj[oDD.id]) {
21656 delete obj[oDD.id];
21661 * Unregisters a drag and drop item. This is executed in
21662 * DragDrop.unreg, use that method instead of calling this directly.
21667 _remove: function(oDD) {
21668 for (var g in oDD.groups) {
21669 if (g && this.ids[g][oDD.id]) {
21670 delete this.ids[g][oDD.id];
21673 delete this.handleIds[oDD.id];
21677 * Each DragDrop handle element must be registered. This is done
21678 * automatically when executing DragDrop.setHandleElId()
21679 * @method regHandle
21680 * @param {String} sDDId the DragDrop id this element is a handle for
21681 * @param {String} sHandleId the id of the element that is the drag
21685 regHandle: function(sDDId, sHandleId) {
21686 if (!this.handleIds[sDDId]) {
21687 this.handleIds[sDDId] = {};
21689 this.handleIds[sDDId][sHandleId] = sHandleId;
21693 * Utility function to determine if a given element has been
21694 * registered as a drag drop item.
21695 * @method isDragDrop
21696 * @param {String} id the element id to check
21697 * @return {boolean} true if this element is a DragDrop item,
21701 isDragDrop: function(id) {
21702 return ( this.getDDById(id) ) ? true : false;
21706 * Returns the drag and drop instances that are in all groups the
21707 * passed in instance belongs to.
21708 * @method getRelated
21709 * @param {DragDrop} p_oDD the obj to get related data for
21710 * @param {boolean} bTargetsOnly if true, only return targetable objs
21711 * @return {DragDrop[]} the related instances
21714 getRelated: function(p_oDD, bTargetsOnly) {
21716 for (var i in p_oDD.groups) {
21717 for (j in this.ids[i]) {
21718 var dd = this.ids[i][j];
21719 if (! this.isTypeOfDD(dd)) {
21722 if (!bTargetsOnly || dd.isTarget) {
21723 oDDs[oDDs.length] = dd;
21732 * Returns true if the specified dd target is a legal target for
21733 * the specifice drag obj
21734 * @method isLegalTarget
21735 * @param {DragDrop} the drag obj
21736 * @param {DragDrop} the target
21737 * @return {boolean} true if the target is a legal target for the
21741 isLegalTarget: function (oDD, oTargetDD) {
21742 var targets = this.getRelated(oDD, true);
21743 for (var i=0, len=targets.length;i<len;++i) {
21744 if (targets[i].id == oTargetDD.id) {
21753 * My goal is to be able to transparently determine if an object is
21754 * typeof DragDrop, and the exact subclass of DragDrop. typeof
21755 * returns "object", oDD.constructor.toString() always returns
21756 * "DragDrop" and not the name of the subclass. So for now it just
21757 * evaluates a well-known variable in DragDrop.
21758 * @method isTypeOfDD
21759 * @param {Object} the object to evaluate
21760 * @return {boolean} true if typeof oDD = DragDrop
21763 isTypeOfDD: function (oDD) {
21764 return (oDD && oDD.__ygDragDrop);
21768 * Utility function to determine if a given element has been
21769 * registered as a drag drop handle for the given Drag Drop object.
21771 * @param {String} id the element id to check
21772 * @return {boolean} true if this element is a DragDrop handle, false
21776 isHandle: function(sDDId, sHandleId) {
21777 return ( this.handleIds[sDDId] &&
21778 this.handleIds[sDDId][sHandleId] );
21782 * Returns the DragDrop instance for a given id
21783 * @method getDDById
21784 * @param {String} id the id of the DragDrop object
21785 * @return {DragDrop} the drag drop object, null if it is not found
21788 getDDById: function(id) {
21789 for (var i in this.ids) {
21790 if (this.ids[i][id]) {
21791 return this.ids[i][id];
21798 * Fired after a registered DragDrop object gets the mousedown event.
21799 * Sets up the events required to track the object being dragged
21800 * @method handleMouseDown
21801 * @param {Event} e the event
21802 * @param oDD the DragDrop object being dragged
21806 handleMouseDown: function(e, oDD) {
21808 Roo.QuickTips.disable();
21810 this.currentTarget = e.getTarget();
21812 this.dragCurrent = oDD;
21814 var el = oDD.getEl();
21816 // track start position
21817 this.startX = e.getPageX();
21818 this.startY = e.getPageY();
21820 this.deltaX = this.startX - el.offsetLeft;
21821 this.deltaY = this.startY - el.offsetTop;
21823 this.dragThreshMet = false;
21825 this.clickTimeout = setTimeout(
21827 var DDM = Roo.dd.DDM;
21828 DDM.startDrag(DDM.startX, DDM.startY);
21830 this.clickTimeThresh );
21834 * Fired when either the drag pixel threshol or the mousedown hold
21835 * time threshold has been met.
21836 * @method startDrag
21837 * @param x {int} the X position of the original mousedown
21838 * @param y {int} the Y position of the original mousedown
21841 startDrag: function(x, y) {
21842 clearTimeout(this.clickTimeout);
21843 if (this.dragCurrent) {
21844 this.dragCurrent.b4StartDrag(x, y);
21845 this.dragCurrent.startDrag(x, y);
21847 this.dragThreshMet = true;
21851 * Internal function to handle the mouseup event. Will be invoked
21852 * from the context of the document.
21853 * @method handleMouseUp
21854 * @param {Event} e the event
21858 handleMouseUp: function(e) {
21861 Roo.QuickTips.enable();
21863 if (! this.dragCurrent) {
21867 clearTimeout(this.clickTimeout);
21869 if (this.dragThreshMet) {
21870 this.fireEvents(e, true);
21880 * Utility to stop event propagation and event default, if these
21881 * features are turned on.
21882 * @method stopEvent
21883 * @param {Event} e the event as returned by this.getEvent()
21886 stopEvent: function(e){
21887 if(this.stopPropagation) {
21888 e.stopPropagation();
21891 if (this.preventDefault) {
21892 e.preventDefault();
21897 * Internal function to clean up event handlers after the drag
21898 * operation is complete
21900 * @param {Event} e the event
21904 stopDrag: function(e) {
21905 // Fire the drag end event for the item that was dragged
21906 if (this.dragCurrent) {
21907 if (this.dragThreshMet) {
21908 this.dragCurrent.b4EndDrag(e);
21909 this.dragCurrent.endDrag(e);
21912 this.dragCurrent.onMouseUp(e);
21915 this.dragCurrent = null;
21916 this.dragOvers = {};
21920 * Internal function to handle the mousemove event. Will be invoked
21921 * from the context of the html element.
21923 * @TODO figure out what we can do about mouse events lost when the
21924 * user drags objects beyond the window boundary. Currently we can
21925 * detect this in internet explorer by verifying that the mouse is
21926 * down during the mousemove event. Firefox doesn't give us the
21927 * button state on the mousemove event.
21928 * @method handleMouseMove
21929 * @param {Event} e the event
21933 handleMouseMove: function(e) {
21934 if (! this.dragCurrent) {
21938 // var button = e.which || e.button;
21940 // check for IE mouseup outside of page boundary
21941 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
21943 return this.handleMouseUp(e);
21946 if (!this.dragThreshMet) {
21947 var diffX = Math.abs(this.startX - e.getPageX());
21948 var diffY = Math.abs(this.startY - e.getPageY());
21949 if (diffX > this.clickPixelThresh ||
21950 diffY > this.clickPixelThresh) {
21951 this.startDrag(this.startX, this.startY);
21955 if (this.dragThreshMet) {
21956 this.dragCurrent.b4Drag(e);
21957 this.dragCurrent.onDrag(e);
21958 if(!this.dragCurrent.moveOnly){
21959 this.fireEvents(e, false);
21969 * Iterates over all of the DragDrop elements to find ones we are
21970 * hovering over or dropping on
21971 * @method fireEvents
21972 * @param {Event} e the event
21973 * @param {boolean} isDrop is this a drop op or a mouseover op?
21977 fireEvents: function(e, isDrop) {
21978 var dc = this.dragCurrent;
21980 // If the user did the mouse up outside of the window, we could
21981 // get here even though we have ended the drag.
21982 if (!dc || dc.isLocked()) {
21986 var pt = e.getPoint();
21988 // cache the previous dragOver array
21994 var enterEvts = [];
21996 // Check to see if the object(s) we were hovering over is no longer
21997 // being hovered over so we can fire the onDragOut event
21998 for (var i in this.dragOvers) {
22000 var ddo = this.dragOvers[i];
22002 if (! this.isTypeOfDD(ddo)) {
22006 if (! this.isOverTarget(pt, ddo, this.mode)) {
22007 outEvts.push( ddo );
22010 oldOvers[i] = true;
22011 delete this.dragOvers[i];
22014 for (var sGroup in dc.groups) {
22016 if ("string" != typeof sGroup) {
22020 for (i in this.ids[sGroup]) {
22021 var oDD = this.ids[sGroup][i];
22022 if (! this.isTypeOfDD(oDD)) {
22026 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
22027 if (this.isOverTarget(pt, oDD, this.mode)) {
22028 // look for drop interactions
22030 dropEvts.push( oDD );
22031 // look for drag enter and drag over interactions
22034 // initial drag over: dragEnter fires
22035 if (!oldOvers[oDD.id]) {
22036 enterEvts.push( oDD );
22037 // subsequent drag overs: dragOver fires
22039 overEvts.push( oDD );
22042 this.dragOvers[oDD.id] = oDD;
22050 if (outEvts.length) {
22051 dc.b4DragOut(e, outEvts);
22052 dc.onDragOut(e, outEvts);
22055 if (enterEvts.length) {
22056 dc.onDragEnter(e, enterEvts);
22059 if (overEvts.length) {
22060 dc.b4DragOver(e, overEvts);
22061 dc.onDragOver(e, overEvts);
22064 if (dropEvts.length) {
22065 dc.b4DragDrop(e, dropEvts);
22066 dc.onDragDrop(e, dropEvts);
22070 // fire dragout events
22072 for (i=0, len=outEvts.length; i<len; ++i) {
22073 dc.b4DragOut(e, outEvts[i].id);
22074 dc.onDragOut(e, outEvts[i].id);
22077 // fire enter events
22078 for (i=0,len=enterEvts.length; i<len; ++i) {
22079 // dc.b4DragEnter(e, oDD.id);
22080 dc.onDragEnter(e, enterEvts[i].id);
22083 // fire over events
22084 for (i=0,len=overEvts.length; i<len; ++i) {
22085 dc.b4DragOver(e, overEvts[i].id);
22086 dc.onDragOver(e, overEvts[i].id);
22089 // fire drop events
22090 for (i=0, len=dropEvts.length; i<len; ++i) {
22091 dc.b4DragDrop(e, dropEvts[i].id);
22092 dc.onDragDrop(e, dropEvts[i].id);
22097 // notify about a drop that did not find a target
22098 if (isDrop && !dropEvts.length) {
22099 dc.onInvalidDrop(e);
22105 * Helper function for getting the best match from the list of drag
22106 * and drop objects returned by the drag and drop events when we are
22107 * in INTERSECT mode. It returns either the first object that the
22108 * cursor is over, or the object that has the greatest overlap with
22109 * the dragged element.
22110 * @method getBestMatch
22111 * @param {DragDrop[]} dds The array of drag and drop objects
22113 * @return {DragDrop} The best single match
22116 getBestMatch: function(dds) {
22118 // Return null if the input is not what we expect
22119 //if (!dds || !dds.length || dds.length == 0) {
22121 // If there is only one item, it wins
22122 //} else if (dds.length == 1) {
22124 var len = dds.length;
22129 // Loop through the targeted items
22130 for (var i=0; i<len; ++i) {
22132 // If the cursor is over the object, it wins. If the
22133 // cursor is over multiple matches, the first one we come
22135 if (dd.cursorIsOver) {
22138 // Otherwise the object with the most overlap wins
22141 winner.overlap.getArea() < dd.overlap.getArea()) {
22152 * Refreshes the cache of the top-left and bottom-right points of the
22153 * drag and drop objects in the specified group(s). This is in the
22154 * format that is stored in the drag and drop instance, so typical
22157 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
22161 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
22163 * @TODO this really should be an indexed array. Alternatively this
22164 * method could accept both.
22165 * @method refreshCache
22166 * @param {Object} groups an associative array of groups to refresh
22169 refreshCache: function(groups) {
22170 for (var sGroup in groups) {
22171 if ("string" != typeof sGroup) {
22174 for (var i in this.ids[sGroup]) {
22175 var oDD = this.ids[sGroup][i];
22177 if (this.isTypeOfDD(oDD)) {
22178 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
22179 var loc = this.getLocation(oDD);
22181 this.locationCache[oDD.id] = loc;
22183 delete this.locationCache[oDD.id];
22184 // this will unregister the drag and drop object if
22185 // the element is not in a usable state
22194 * This checks to make sure an element exists and is in the DOM. The
22195 * main purpose is to handle cases where innerHTML is used to remove
22196 * drag and drop objects from the DOM. IE provides an 'unspecified
22197 * error' when trying to access the offsetParent of such an element
22199 * @param {HTMLElement} el the element to check
22200 * @return {boolean} true if the element looks usable
22203 verifyEl: function(el) {
22208 parent = el.offsetParent;
22211 parent = el.offsetParent;
22222 * Returns a Region object containing the drag and drop element's position
22223 * and size, including the padding configured for it
22224 * @method getLocation
22225 * @param {DragDrop} oDD the drag and drop object to get the
22227 * @return {Roo.lib.Region} a Region object representing the total area
22228 * the element occupies, including any padding
22229 * the instance is configured for.
22232 getLocation: function(oDD) {
22233 if (! this.isTypeOfDD(oDD)) {
22237 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
22240 pos= Roo.lib.Dom.getXY(el);
22248 x2 = x1 + el.offsetWidth;
22250 y2 = y1 + el.offsetHeight;
22252 t = y1 - oDD.padding[0];
22253 r = x2 + oDD.padding[1];
22254 b = y2 + oDD.padding[2];
22255 l = x1 - oDD.padding[3];
22257 return new Roo.lib.Region( t, r, b, l );
22261 * Checks the cursor location to see if it over the target
22262 * @method isOverTarget
22263 * @param {Roo.lib.Point} pt The point to evaluate
22264 * @param {DragDrop} oTarget the DragDrop object we are inspecting
22265 * @return {boolean} true if the mouse is over the target
22269 isOverTarget: function(pt, oTarget, intersect) {
22270 // use cache if available
22271 var loc = this.locationCache[oTarget.id];
22272 if (!loc || !this.useCache) {
22273 loc = this.getLocation(oTarget);
22274 this.locationCache[oTarget.id] = loc;
22282 oTarget.cursorIsOver = loc.contains( pt );
22284 // DragDrop is using this as a sanity check for the initial mousedown
22285 // in this case we are done. In POINT mode, if the drag obj has no
22286 // contraints, we are also done. Otherwise we need to evaluate the
22287 // location of the target as related to the actual location of the
22288 // dragged element.
22289 var dc = this.dragCurrent;
22290 if (!dc || !dc.getTargetCoord ||
22291 (!intersect && !dc.constrainX && !dc.constrainY)) {
22292 return oTarget.cursorIsOver;
22295 oTarget.overlap = null;
22297 // Get the current location of the drag element, this is the
22298 // location of the mouse event less the delta that represents
22299 // where the original mousedown happened on the element. We
22300 // need to consider constraints and ticks as well.
22301 var pos = dc.getTargetCoord(pt.x, pt.y);
22303 var el = dc.getDragEl();
22304 var curRegion = new Roo.lib.Region( pos.y,
22305 pos.x + el.offsetWidth,
22306 pos.y + el.offsetHeight,
22309 var overlap = curRegion.intersect(loc);
22312 oTarget.overlap = overlap;
22313 return (intersect) ? true : oTarget.cursorIsOver;
22320 * unload event handler
22321 * @method _onUnload
22325 _onUnload: function(e, me) {
22326 Roo.dd.DragDropMgr.unregAll();
22330 * Cleans up the drag and drop events and objects.
22335 unregAll: function() {
22337 if (this.dragCurrent) {
22339 this.dragCurrent = null;
22342 this._execOnAll("unreg", []);
22344 for (i in this.elementCache) {
22345 delete this.elementCache[i];
22348 this.elementCache = {};
22353 * A cache of DOM elements
22354 * @property elementCache
22361 * Get the wrapper for the DOM element specified
22362 * @method getElWrapper
22363 * @param {String} id the id of the element to get
22364 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
22366 * @deprecated This wrapper isn't that useful
22369 getElWrapper: function(id) {
22370 var oWrapper = this.elementCache[id];
22371 if (!oWrapper || !oWrapper.el) {
22372 oWrapper = this.elementCache[id] =
22373 new this.ElementWrapper(Roo.getDom(id));
22379 * Returns the actual DOM element
22380 * @method getElement
22381 * @param {String} id the id of the elment to get
22382 * @return {Object} The element
22383 * @deprecated use Roo.getDom instead
22386 getElement: function(id) {
22387 return Roo.getDom(id);
22391 * Returns the style property for the DOM element (i.e.,
22392 * document.getElById(id).style)
22394 * @param {String} id the id of the elment to get
22395 * @return {Object} The style property of the element
22396 * @deprecated use Roo.getDom instead
22399 getCss: function(id) {
22400 var el = Roo.getDom(id);
22401 return (el) ? el.style : null;
22405 * Inner class for cached elements
22406 * @class DragDropMgr.ElementWrapper
22411 ElementWrapper: function(el) {
22416 this.el = el || null;
22421 this.id = this.el && el.id;
22423 * A reference to the style property
22426 this.css = this.el && el.style;
22430 * Returns the X position of an html element
22432 * @param el the element for which to get the position
22433 * @return {int} the X coordinate
22435 * @deprecated use Roo.lib.Dom.getX instead
22438 getPosX: function(el) {
22439 return Roo.lib.Dom.getX(el);
22443 * Returns the Y position of an html element
22445 * @param el the element for which to get the position
22446 * @return {int} the Y coordinate
22447 * @deprecated use Roo.lib.Dom.getY instead
22450 getPosY: function(el) {
22451 return Roo.lib.Dom.getY(el);
22455 * Swap two nodes. In IE, we use the native method, for others we
22456 * emulate the IE behavior
22458 * @param n1 the first node to swap
22459 * @param n2 the other node to swap
22462 swapNode: function(n1, n2) {
22466 var p = n2.parentNode;
22467 var s = n2.nextSibling;
22470 p.insertBefore(n1, n2);
22471 } else if (n2 == n1.nextSibling) {
22472 p.insertBefore(n2, n1);
22474 n1.parentNode.replaceChild(n2, n1);
22475 p.insertBefore(n1, s);
22481 * Returns the current scroll position
22482 * @method getScroll
22486 getScroll: function () {
22487 var t, l, dde=document.documentElement, db=document.body;
22488 if (dde && (dde.scrollTop || dde.scrollLeft)) {
22490 l = dde.scrollLeft;
22497 return { top: t, left: l };
22501 * Returns the specified element style property
22503 * @param {HTMLElement} el the element
22504 * @param {string} styleProp the style property
22505 * @return {string} The value of the style property
22506 * @deprecated use Roo.lib.Dom.getStyle
22509 getStyle: function(el, styleProp) {
22510 return Roo.fly(el).getStyle(styleProp);
22514 * Gets the scrollTop
22515 * @method getScrollTop
22516 * @return {int} the document's scrollTop
22519 getScrollTop: function () { return this.getScroll().top; },
22522 * Gets the scrollLeft
22523 * @method getScrollLeft
22524 * @return {int} the document's scrollTop
22527 getScrollLeft: function () { return this.getScroll().left; },
22530 * Sets the x/y position of an element to the location of the
22533 * @param {HTMLElement} moveEl The element to move
22534 * @param {HTMLElement} targetEl The position reference element
22537 moveToEl: function (moveEl, targetEl) {
22538 var aCoord = Roo.lib.Dom.getXY(targetEl);
22539 Roo.lib.Dom.setXY(moveEl, aCoord);
22543 * Numeric array sort function
22544 * @method numericSort
22547 numericSort: function(a, b) { return (a - b); },
22551 * @property _timeoutCount
22558 * Trying to make the load order less important. Without this we get
22559 * an error if this file is loaded before the Event Utility.
22560 * @method _addListeners
22564 _addListeners: function() {
22565 var DDM = Roo.dd.DDM;
22566 if ( Roo.lib.Event && document ) {
22569 if (DDM._timeoutCount > 2000) {
22571 setTimeout(DDM._addListeners, 10);
22572 if (document && document.body) {
22573 DDM._timeoutCount += 1;
22580 * Recursively searches the immediate parent and all child nodes for
22581 * the handle element in order to determine wheter or not it was
22583 * @method handleWasClicked
22584 * @param node the html element to inspect
22587 handleWasClicked: function(node, id) {
22588 if (this.isHandle(id, node.id)) {
22591 // check to see if this is a text node child of the one we want
22592 var p = node.parentNode;
22595 if (this.isHandle(id, p.id)) {
22610 // shorter alias, save a few bytes
22611 Roo.dd.DDM = Roo.dd.DragDropMgr;
22612 Roo.dd.DDM._addListeners();
22616 * Ext JS Library 1.1.1
22617 * Copyright(c) 2006-2007, Ext JS, LLC.
22619 * Originally Released Under LGPL - original licence link has changed is not relivant.
22622 * <script type="text/javascript">
22627 * A DragDrop implementation where the linked element follows the
22628 * mouse cursor during a drag.
22629 * @extends Roo.dd.DragDrop
22631 * @param {String} id the id of the linked element
22632 * @param {String} sGroup the group of related DragDrop items
22633 * @param {object} config an object containing configurable attributes
22634 * Valid properties for DD:
22637 Roo.dd.DD = function(id, sGroup, config) {
22639 this.init(id, sGroup, config);
22643 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
22646 * When set to true, the utility automatically tries to scroll the browser
22647 * window wehn a drag and drop element is dragged near the viewport boundary.
22648 * Defaults to true.
22655 * Sets the pointer offset to the distance between the linked element's top
22656 * left corner and the location the element was clicked
22657 * @method autoOffset
22658 * @param {int} iPageX the X coordinate of the click
22659 * @param {int} iPageY the Y coordinate of the click
22661 autoOffset: function(iPageX, iPageY) {
22662 var x = iPageX - this.startPageX;
22663 var y = iPageY - this.startPageY;
22664 this.setDelta(x, y);
22668 * Sets the pointer offset. You can call this directly to force the
22669 * offset to be in a particular location (e.g., pass in 0,0 to set it
22670 * to the center of the object)
22672 * @param {int} iDeltaX the distance from the left
22673 * @param {int} iDeltaY the distance from the top
22675 setDelta: function(iDeltaX, iDeltaY) {
22676 this.deltaX = iDeltaX;
22677 this.deltaY = iDeltaY;
22681 * Sets the drag element to the location of the mousedown or click event,
22682 * maintaining the cursor location relative to the location on the element
22683 * that was clicked. Override this if you want to place the element in a
22684 * location other than where the cursor is.
22685 * @method setDragElPos
22686 * @param {int} iPageX the X coordinate of the mousedown or drag event
22687 * @param {int} iPageY the Y coordinate of the mousedown or drag event
22689 setDragElPos: function(iPageX, iPageY) {
22690 // the first time we do this, we are going to check to make sure
22691 // the element has css positioning
22693 var el = this.getDragEl();
22694 this.alignElWithMouse(el, iPageX, iPageY);
22698 * Sets the element to the location of the mousedown or click event,
22699 * maintaining the cursor location relative to the location on the element
22700 * that was clicked. Override this if you want to place the element in a
22701 * location other than where the cursor is.
22702 * @method alignElWithMouse
22703 * @param {HTMLElement} el the element to move
22704 * @param {int} iPageX the X coordinate of the mousedown or drag event
22705 * @param {int} iPageY the Y coordinate of the mousedown or drag event
22707 alignElWithMouse: function(el, iPageX, iPageY) {
22708 var oCoord = this.getTargetCoord(iPageX, iPageY);
22709 var fly = el.dom ? el : Roo.fly(el);
22710 if (!this.deltaSetXY) {
22711 var aCoord = [oCoord.x, oCoord.y];
22713 var newLeft = fly.getLeft(true);
22714 var newTop = fly.getTop(true);
22715 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
22717 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
22720 this.cachePosition(oCoord.x, oCoord.y);
22721 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
22726 * Saves the most recent position so that we can reset the constraints and
22727 * tick marks on-demand. We need to know this so that we can calculate the
22728 * number of pixels the element is offset from its original position.
22729 * @method cachePosition
22730 * @param iPageX the current x position (optional, this just makes it so we
22731 * don't have to look it up again)
22732 * @param iPageY the current y position (optional, this just makes it so we
22733 * don't have to look it up again)
22735 cachePosition: function(iPageX, iPageY) {
22737 this.lastPageX = iPageX;
22738 this.lastPageY = iPageY;
22740 var aCoord = Roo.lib.Dom.getXY(this.getEl());
22741 this.lastPageX = aCoord[0];
22742 this.lastPageY = aCoord[1];
22747 * Auto-scroll the window if the dragged object has been moved beyond the
22748 * visible window boundary.
22749 * @method autoScroll
22750 * @param {int} x the drag element's x position
22751 * @param {int} y the drag element's y position
22752 * @param {int} h the height of the drag element
22753 * @param {int} w the width of the drag element
22756 autoScroll: function(x, y, h, w) {
22759 // The client height
22760 var clientH = Roo.lib.Dom.getViewWidth();
22762 // The client width
22763 var clientW = Roo.lib.Dom.getViewHeight();
22765 // The amt scrolled down
22766 var st = this.DDM.getScrollTop();
22768 // The amt scrolled right
22769 var sl = this.DDM.getScrollLeft();
22771 // Location of the bottom of the element
22774 // Location of the right of the element
22777 // The distance from the cursor to the bottom of the visible area,
22778 // adjusted so that we don't scroll if the cursor is beyond the
22779 // element drag constraints
22780 var toBot = (clientH + st - y - this.deltaY);
22782 // The distance from the cursor to the right of the visible area
22783 var toRight = (clientW + sl - x - this.deltaX);
22786 // How close to the edge the cursor must be before we scroll
22787 // var thresh = (document.all) ? 100 : 40;
22790 // How many pixels to scroll per autoscroll op. This helps to reduce
22791 // clunky scrolling. IE is more sensitive about this ... it needs this
22792 // value to be higher.
22793 var scrAmt = (document.all) ? 80 : 30;
22795 // Scroll down if we are near the bottom of the visible page and the
22796 // obj extends below the crease
22797 if ( bot > clientH && toBot < thresh ) {
22798 window.scrollTo(sl, st + scrAmt);
22801 // Scroll up if the window is scrolled down and the top of the object
22802 // goes above the top border
22803 if ( y < st && st > 0 && y - st < thresh ) {
22804 window.scrollTo(sl, st - scrAmt);
22807 // Scroll right if the obj is beyond the right border and the cursor is
22808 // near the border.
22809 if ( right > clientW && toRight < thresh ) {
22810 window.scrollTo(sl + scrAmt, st);
22813 // Scroll left if the window has been scrolled to the right and the obj
22814 // extends past the left border
22815 if ( x < sl && sl > 0 && x - sl < thresh ) {
22816 window.scrollTo(sl - scrAmt, st);
22822 * Finds the location the element should be placed if we want to move
22823 * it to where the mouse location less the click offset would place us.
22824 * @method getTargetCoord
22825 * @param {int} iPageX the X coordinate of the click
22826 * @param {int} iPageY the Y coordinate of the click
22827 * @return an object that contains the coordinates (Object.x and Object.y)
22830 getTargetCoord: function(iPageX, iPageY) {
22833 var x = iPageX - this.deltaX;
22834 var y = iPageY - this.deltaY;
22836 if (this.constrainX) {
22837 if (x < this.minX) { x = this.minX; }
22838 if (x > this.maxX) { x = this.maxX; }
22841 if (this.constrainY) {
22842 if (y < this.minY) { y = this.minY; }
22843 if (y > this.maxY) { y = this.maxY; }
22846 x = this.getTick(x, this.xTicks);
22847 y = this.getTick(y, this.yTicks);
22854 * Sets up config options specific to this class. Overrides
22855 * Roo.dd.DragDrop, but all versions of this method through the
22856 * inheritance chain are called
22858 applyConfig: function() {
22859 Roo.dd.DD.superclass.applyConfig.call(this);
22860 this.scroll = (this.config.scroll !== false);
22864 * Event that fires prior to the onMouseDown event. Overrides
22867 b4MouseDown: function(e) {
22868 // this.resetConstraints();
22869 this.autoOffset(e.getPageX(),
22874 * Event that fires prior to the onDrag event. Overrides
22877 b4Drag: function(e) {
22878 this.setDragElPos(e.getPageX(),
22882 toString: function() {
22883 return ("DD " + this.id);
22886 //////////////////////////////////////////////////////////////////////////
22887 // Debugging ygDragDrop events that can be overridden
22888 //////////////////////////////////////////////////////////////////////////
22890 startDrag: function(x, y) {
22893 onDrag: function(e) {
22896 onDragEnter: function(e, id) {
22899 onDragOver: function(e, id) {
22902 onDragOut: function(e, id) {
22905 onDragDrop: function(e, id) {
22908 endDrag: function(e) {
22915 * Ext JS Library 1.1.1
22916 * Copyright(c) 2006-2007, Ext JS, LLC.
22918 * Originally Released Under LGPL - original licence link has changed is not relivant.
22921 * <script type="text/javascript">
22925 * @class Roo.dd.DDProxy
22926 * A DragDrop implementation that inserts an empty, bordered div into
22927 * the document that follows the cursor during drag operations. At the time of
22928 * the click, the frame div is resized to the dimensions of the linked html
22929 * element, and moved to the exact location of the linked element.
22931 * References to the "frame" element refer to the single proxy element that
22932 * was created to be dragged in place of all DDProxy elements on the
22935 * @extends Roo.dd.DD
22937 * @param {String} id the id of the linked html element
22938 * @param {String} sGroup the group of related DragDrop objects
22939 * @param {object} config an object containing configurable attributes
22940 * Valid properties for DDProxy in addition to those in DragDrop:
22941 * resizeFrame, centerFrame, dragElId
22943 Roo.dd.DDProxy = function(id, sGroup, config) {
22945 this.init(id, sGroup, config);
22951 * The default drag frame div id
22952 * @property Roo.dd.DDProxy.dragElId
22956 Roo.dd.DDProxy.dragElId = "ygddfdiv";
22958 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
22961 * By default we resize the drag frame to be the same size as the element
22962 * we want to drag (this is to get the frame effect). We can turn it off
22963 * if we want a different behavior.
22964 * @property resizeFrame
22970 * By default the frame is positioned exactly where the drag element is, so
22971 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
22972 * you do not have constraints on the obj is to have the drag frame centered
22973 * around the cursor. Set centerFrame to true for this effect.
22974 * @property centerFrame
22977 centerFrame: false,
22980 * Creates the proxy element if it does not yet exist
22981 * @method createFrame
22983 createFrame: function() {
22985 var body = document.body;
22987 if (!body || !body.firstChild) {
22988 setTimeout( function() { self.createFrame(); }, 50 );
22992 var div = this.getDragEl();
22995 div = document.createElement("div");
22996 div.id = this.dragElId;
22999 s.position = "absolute";
23000 s.visibility = "hidden";
23002 s.border = "2px solid #aaa";
23005 // appendChild can blow up IE if invoked prior to the window load event
23006 // while rendering a table. It is possible there are other scenarios
23007 // that would cause this to happen as well.
23008 body.insertBefore(div, body.firstChild);
23013 * Initialization for the drag frame element. Must be called in the
23014 * constructor of all subclasses
23015 * @method initFrame
23017 initFrame: function() {
23018 this.createFrame();
23021 applyConfig: function() {
23022 Roo.dd.DDProxy.superclass.applyConfig.call(this);
23024 this.resizeFrame = (this.config.resizeFrame !== false);
23025 this.centerFrame = (this.config.centerFrame);
23026 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
23030 * Resizes the drag frame to the dimensions of the clicked object, positions
23031 * it over the object, and finally displays it
23032 * @method showFrame
23033 * @param {int} iPageX X click position
23034 * @param {int} iPageY Y click position
23037 showFrame: function(iPageX, iPageY) {
23038 var el = this.getEl();
23039 var dragEl = this.getDragEl();
23040 var s = dragEl.style;
23042 this._resizeProxy();
23044 if (this.centerFrame) {
23045 this.setDelta( Math.round(parseInt(s.width, 10)/2),
23046 Math.round(parseInt(s.height, 10)/2) );
23049 this.setDragElPos(iPageX, iPageY);
23051 Roo.fly(dragEl).show();
23055 * The proxy is automatically resized to the dimensions of the linked
23056 * element when a drag is initiated, unless resizeFrame is set to false
23057 * @method _resizeProxy
23060 _resizeProxy: function() {
23061 if (this.resizeFrame) {
23062 var el = this.getEl();
23063 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
23067 // overrides Roo.dd.DragDrop
23068 b4MouseDown: function(e) {
23069 var x = e.getPageX();
23070 var y = e.getPageY();
23071 this.autoOffset(x, y);
23072 this.setDragElPos(x, y);
23075 // overrides Roo.dd.DragDrop
23076 b4StartDrag: function(x, y) {
23077 // show the drag frame
23078 this.showFrame(x, y);
23081 // overrides Roo.dd.DragDrop
23082 b4EndDrag: function(e) {
23083 Roo.fly(this.getDragEl()).hide();
23086 // overrides Roo.dd.DragDrop
23087 // By default we try to move the element to the last location of the frame.
23088 // This is so that the default behavior mirrors that of Roo.dd.DD.
23089 endDrag: function(e) {
23091 var lel = this.getEl();
23092 var del = this.getDragEl();
23094 // Show the drag frame briefly so we can get its position
23095 del.style.visibility = "";
23098 // Hide the linked element before the move to get around a Safari
23100 lel.style.visibility = "hidden";
23101 Roo.dd.DDM.moveToEl(lel, del);
23102 del.style.visibility = "hidden";
23103 lel.style.visibility = "";
23108 beforeMove : function(){
23112 afterDrag : function(){
23116 toString: function() {
23117 return ("DDProxy " + this.id);
23123 * Ext JS Library 1.1.1
23124 * Copyright(c) 2006-2007, Ext JS, LLC.
23126 * Originally Released Under LGPL - original licence link has changed is not relivant.
23129 * <script type="text/javascript">
23133 * @class Roo.dd.DDTarget
23134 * A DragDrop implementation that does not move, but can be a drop
23135 * target. You would get the same result by simply omitting implementation
23136 * for the event callbacks, but this way we reduce the processing cost of the
23137 * event listener and the callbacks.
23138 * @extends Roo.dd.DragDrop
23140 * @param {String} id the id of the element that is a drop target
23141 * @param {String} sGroup the group of related DragDrop objects
23142 * @param {object} config an object containing configurable attributes
23143 * Valid properties for DDTarget in addition to those in
23147 Roo.dd.DDTarget = function(id, sGroup, config) {
23149 this.initTarget(id, sGroup, config);
23151 if (config && (config.listeners || config.events)) {
23152 Roo.dd.DragDrop.superclass.constructor.call(this, {
23153 listeners : config.listeners || {},
23154 events : config.events || {}
23159 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
23160 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
23161 toString: function() {
23162 return ("DDTarget " + this.id);
23167 * Ext JS Library 1.1.1
23168 * Copyright(c) 2006-2007, Ext JS, LLC.
23170 * Originally Released Under LGPL - original licence link has changed is not relivant.
23173 * <script type="text/javascript">
23178 * @class Roo.dd.ScrollManager
23179 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
23180 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
23183 Roo.dd.ScrollManager = function(){
23184 var ddm = Roo.dd.DragDropMgr;
23191 var onStop = function(e){
23196 var triggerRefresh = function(){
23197 if(ddm.dragCurrent){
23198 ddm.refreshCache(ddm.dragCurrent.groups);
23202 var doScroll = function(){
23203 if(ddm.dragCurrent){
23204 var dds = Roo.dd.ScrollManager;
23206 if(proc.el.scroll(proc.dir, dds.increment)){
23210 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
23215 var clearProc = function(){
23217 clearInterval(proc.id);
23224 var startProc = function(el, dir){
23225 Roo.log('scroll startproc');
23229 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
23232 var onFire = function(e, isDrop){
23234 if(isDrop || !ddm.dragCurrent){ return; }
23235 var dds = Roo.dd.ScrollManager;
23236 if(!dragEl || dragEl != ddm.dragCurrent){
23237 dragEl = ddm.dragCurrent;
23238 // refresh regions on drag start
23239 dds.refreshCache();
23242 var xy = Roo.lib.Event.getXY(e);
23243 var pt = new Roo.lib.Point(xy[0], xy[1]);
23244 for(var id in els){
23245 var el = els[id], r = el._region;
23246 if(r && r.contains(pt) && el.isScrollable()){
23247 if(r.bottom - pt.y <= dds.thresh){
23249 startProc(el, "down");
23252 }else if(r.right - pt.x <= dds.thresh){
23254 startProc(el, "left");
23257 }else if(pt.y - r.top <= dds.thresh){
23259 startProc(el, "up");
23262 }else if(pt.x - r.left <= dds.thresh){
23264 startProc(el, "right");
23273 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
23274 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
23278 * Registers new overflow element(s) to auto scroll
23279 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
23281 register : function(el){
23282 if(el instanceof Array){
23283 for(var i = 0, len = el.length; i < len; i++) {
23284 this.register(el[i]);
23290 Roo.dd.ScrollManager.els = els;
23294 * Unregisters overflow element(s) so they are no longer scrolled
23295 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
23297 unregister : function(el){
23298 if(el instanceof Array){
23299 for(var i = 0, len = el.length; i < len; i++) {
23300 this.unregister(el[i]);
23309 * The number of pixels from the edge of a container the pointer needs to be to
23310 * trigger scrolling (defaults to 25)
23316 * The number of pixels to scroll in each scroll increment (defaults to 50)
23322 * The frequency of scrolls in milliseconds (defaults to 500)
23328 * True to animate the scroll (defaults to true)
23334 * The animation duration in seconds -
23335 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
23341 * Manually trigger a cache refresh.
23343 refreshCache : function(){
23344 for(var id in els){
23345 if(typeof els[id] == 'object'){ // for people extending the object prototype
23346 els[id]._region = els[id].getRegion();
23353 * Ext JS Library 1.1.1
23354 * Copyright(c) 2006-2007, Ext JS, LLC.
23356 * Originally Released Under LGPL - original licence link has changed is not relivant.
23359 * <script type="text/javascript">
23364 * @class Roo.dd.Registry
23365 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
23366 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
23369 Roo.dd.Registry = function(){
23372 var autoIdSeed = 0;
23374 var getId = function(el, autogen){
23375 if(typeof el == "string"){
23379 if(!id && autogen !== false){
23380 id = "roodd-" + (++autoIdSeed);
23388 * Register a drag drop element
23389 * @param {String|HTMLElement} element The id or DOM node to register
23390 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
23391 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
23392 * knows how to interpret, plus there are some specific properties known to the Registry that should be
23393 * populated in the data object (if applicable):
23395 Value Description<br />
23396 --------- ------------------------------------------<br />
23397 handles Array of DOM nodes that trigger dragging<br />
23398 for the element being registered<br />
23399 isHandle True if the element passed in triggers<br />
23400 dragging itself, else false
23403 register : function(el, data){
23405 if(typeof el == "string"){
23406 el = document.getElementById(el);
23409 elements[getId(el)] = data;
23410 if(data.isHandle !== false){
23411 handles[data.ddel.id] = data;
23414 var hs = data.handles;
23415 for(var i = 0, len = hs.length; i < len; i++){
23416 handles[getId(hs[i])] = data;
23422 * Unregister a drag drop element
23423 * @param {String|HTMLElement} element The id or DOM node to unregister
23425 unregister : function(el){
23426 var id = getId(el, false);
23427 var data = elements[id];
23429 delete elements[id];
23431 var hs = data.handles;
23432 for(var i = 0, len = hs.length; i < len; i++){
23433 delete handles[getId(hs[i], false)];
23440 * Returns the handle registered for a DOM Node by id
23441 * @param {String|HTMLElement} id The DOM node or id to look up
23442 * @return {Object} handle The custom handle data
23444 getHandle : function(id){
23445 if(typeof id != "string"){ // must be element?
23448 return handles[id];
23452 * Returns the handle that is registered for the DOM node that is the target of the event
23453 * @param {Event} e The event
23454 * @return {Object} handle The custom handle data
23456 getHandleFromEvent : function(e){
23457 var t = Roo.lib.Event.getTarget(e);
23458 return t ? handles[t.id] : null;
23462 * Returns a custom data object that is registered for a DOM node by id
23463 * @param {String|HTMLElement} id The DOM node or id to look up
23464 * @return {Object} data The custom data
23466 getTarget : function(id){
23467 if(typeof id != "string"){ // must be element?
23470 return elements[id];
23474 * Returns a custom data object that is registered for the DOM node that is the target of the event
23475 * @param {Event} e The event
23476 * @return {Object} data The custom data
23478 getTargetFromEvent : function(e){
23479 var t = Roo.lib.Event.getTarget(e);
23480 return t ? elements[t.id] || handles[t.id] : null;
23485 * Ext JS Library 1.1.1
23486 * Copyright(c) 2006-2007, Ext JS, LLC.
23488 * Originally Released Under LGPL - original licence link has changed is not relivant.
23491 * <script type="text/javascript">
23496 * @class Roo.dd.StatusProxy
23497 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
23498 * default drag proxy used by all Roo.dd components.
23500 * @param {Object} config
23502 Roo.dd.StatusProxy = function(config){
23503 Roo.apply(this, config);
23504 this.id = this.id || Roo.id();
23505 this.el = new Roo.Layer({
23507 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
23508 {tag: "div", cls: "x-dd-drop-icon"},
23509 {tag: "div", cls: "x-dd-drag-ghost"}
23512 shadow: !config || config.shadow !== false
23514 this.ghost = Roo.get(this.el.dom.childNodes[1]);
23515 this.dropStatus = this.dropNotAllowed;
23518 Roo.dd.StatusProxy.prototype = {
23520 * @cfg {String} dropAllowed
23521 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
23523 dropAllowed : "x-dd-drop-ok",
23525 * @cfg {String} dropNotAllowed
23526 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
23528 dropNotAllowed : "x-dd-drop-nodrop",
23531 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
23532 * over the current target element.
23533 * @param {String} cssClass The css class for the new drop status indicator image
23535 setStatus : function(cssClass){
23536 cssClass = cssClass || this.dropNotAllowed;
23537 if(this.dropStatus != cssClass){
23538 this.el.replaceClass(this.dropStatus, cssClass);
23539 this.dropStatus = cssClass;
23544 * Resets the status indicator to the default dropNotAllowed value
23545 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
23547 reset : function(clearGhost){
23548 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
23549 this.dropStatus = this.dropNotAllowed;
23551 this.ghost.update("");
23556 * Updates the contents of the ghost element
23557 * @param {String} html The html that will replace the current innerHTML of the ghost element
23559 update : function(html){
23560 if(typeof html == "string"){
23561 this.ghost.update(html);
23563 this.ghost.update("");
23564 html.style.margin = "0";
23565 this.ghost.dom.appendChild(html);
23567 // ensure float = none set?? cant remember why though.
23568 var el = this.ghost.dom.firstChild;
23570 Roo.fly(el).setStyle('float', 'none');
23575 * Returns the underlying proxy {@link Roo.Layer}
23576 * @return {Roo.Layer} el
23578 getEl : function(){
23583 * Returns the ghost element
23584 * @return {Roo.Element} el
23586 getGhost : function(){
23592 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
23594 hide : function(clear){
23602 * Stops the repair animation if it's currently running
23605 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
23611 * Displays this proxy
23618 * Force the Layer to sync its shadow and shim positions to the element
23625 * Causes the proxy to return to its position of origin via an animation. Should be called after an
23626 * invalid drop operation by the item being dragged.
23627 * @param {Array} xy The XY position of the element ([x, y])
23628 * @param {Function} callback The function to call after the repair is complete
23629 * @param {Object} scope The scope in which to execute the callback
23631 repair : function(xy, callback, scope){
23632 this.callback = callback;
23633 this.scope = scope;
23634 if(xy && this.animRepair !== false){
23635 this.el.addClass("x-dd-drag-repair");
23636 this.el.hideUnders(true);
23637 this.anim = this.el.shift({
23638 duration: this.repairDuration || .5,
23642 callback: this.afterRepair,
23646 this.afterRepair();
23651 afterRepair : function(){
23653 if(typeof this.callback == "function"){
23654 this.callback.call(this.scope || this);
23656 this.callback = null;
23661 * Ext JS Library 1.1.1
23662 * Copyright(c) 2006-2007, Ext JS, LLC.
23664 * Originally Released Under LGPL - original licence link has changed is not relivant.
23667 * <script type="text/javascript">
23671 * @class Roo.dd.DragSource
23672 * @extends Roo.dd.DDProxy
23673 * A simple class that provides the basic implementation needed to make any element draggable.
23675 * @param {String/HTMLElement/Element} el The container element
23676 * @param {Object} config
23678 Roo.dd.DragSource = function(el, config){
23679 this.el = Roo.get(el);
23680 this.dragData = {};
23682 Roo.apply(this, config);
23685 this.proxy = new Roo.dd.StatusProxy();
23688 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
23689 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
23691 this.dragging = false;
23694 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
23696 * @cfg {String} dropAllowed
23697 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23699 dropAllowed : "x-dd-drop-ok",
23701 * @cfg {String} dropNotAllowed
23702 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23704 dropNotAllowed : "x-dd-drop-nodrop",
23707 * Returns the data object associated with this drag source
23708 * @return {Object} data An object containing arbitrary data
23710 getDragData : function(e){
23711 return this.dragData;
23715 onDragEnter : function(e, id){
23716 var target = Roo.dd.DragDropMgr.getDDById(id);
23717 this.cachedTarget = target;
23718 if(this.beforeDragEnter(target, e, id) !== false){
23719 if(target.isNotifyTarget){
23720 var status = target.notifyEnter(this, e, this.dragData);
23721 this.proxy.setStatus(status);
23723 this.proxy.setStatus(this.dropAllowed);
23726 if(this.afterDragEnter){
23728 * An empty function by default, but provided so that you can perform a custom action
23729 * when the dragged item enters the drop target by providing an implementation.
23730 * @param {Roo.dd.DragDrop} target The drop target
23731 * @param {Event} e The event object
23732 * @param {String} id The id of the dragged element
23733 * @method afterDragEnter
23735 this.afterDragEnter(target, e, id);
23741 * An empty function by default, but provided so that you can perform a custom action
23742 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
23743 * @param {Roo.dd.DragDrop} target The drop target
23744 * @param {Event} e The event object
23745 * @param {String} id The id of the dragged element
23746 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23748 beforeDragEnter : function(target, e, id){
23753 alignElWithMouse: function() {
23754 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
23759 onDragOver : function(e, id){
23760 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23761 if(this.beforeDragOver(target, e, id) !== false){
23762 if(target.isNotifyTarget){
23763 var status = target.notifyOver(this, e, this.dragData);
23764 this.proxy.setStatus(status);
23767 if(this.afterDragOver){
23769 * An empty function by default, but provided so that you can perform a custom action
23770 * while the dragged item is over the drop target by providing an implementation.
23771 * @param {Roo.dd.DragDrop} target The drop target
23772 * @param {Event} e The event object
23773 * @param {String} id The id of the dragged element
23774 * @method afterDragOver
23776 this.afterDragOver(target, e, id);
23782 * An empty function by default, but provided so that you can perform a custom action
23783 * while the dragged item is over the drop target and optionally cancel the onDragOver.
23784 * @param {Roo.dd.DragDrop} target The drop target
23785 * @param {Event} e The event object
23786 * @param {String} id The id of the dragged element
23787 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23789 beforeDragOver : function(target, e, id){
23794 onDragOut : function(e, id){
23795 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23796 if(this.beforeDragOut(target, e, id) !== false){
23797 if(target.isNotifyTarget){
23798 target.notifyOut(this, e, this.dragData);
23800 this.proxy.reset();
23801 if(this.afterDragOut){
23803 * An empty function by default, but provided so that you can perform a custom action
23804 * after the dragged item is dragged out of the target without dropping.
23805 * @param {Roo.dd.DragDrop} target The drop target
23806 * @param {Event} e The event object
23807 * @param {String} id The id of the dragged element
23808 * @method afterDragOut
23810 this.afterDragOut(target, e, id);
23813 this.cachedTarget = null;
23817 * An empty function by default, but provided so that you can perform a custom action before the dragged
23818 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
23819 * @param {Roo.dd.DragDrop} target The drop target
23820 * @param {Event} e The event object
23821 * @param {String} id The id of the dragged element
23822 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23824 beforeDragOut : function(target, e, id){
23829 onDragDrop : function(e, id){
23830 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23831 if(this.beforeDragDrop(target, e, id) !== false){
23832 if(target.isNotifyTarget){
23833 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
23834 this.onValidDrop(target, e, id);
23836 this.onInvalidDrop(target, e, id);
23839 this.onValidDrop(target, e, id);
23842 if(this.afterDragDrop){
23844 * An empty function by default, but provided so that you can perform a custom action
23845 * after a valid drag drop has occurred by providing an implementation.
23846 * @param {Roo.dd.DragDrop} target The drop target
23847 * @param {Event} e The event object
23848 * @param {String} id The id of the dropped element
23849 * @method afterDragDrop
23851 this.afterDragDrop(target, e, id);
23854 delete this.cachedTarget;
23858 * An empty function by default, but provided so that you can perform a custom action before the dragged
23859 * item is dropped onto the target and optionally cancel the onDragDrop.
23860 * @param {Roo.dd.DragDrop} target The drop target
23861 * @param {Event} e The event object
23862 * @param {String} id The id of the dragged element
23863 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
23865 beforeDragDrop : function(target, e, id){
23870 onValidDrop : function(target, e, id){
23872 if(this.afterValidDrop){
23874 * An empty function by default, but provided so that you can perform a custom action
23875 * after a valid drop has occurred by providing an implementation.
23876 * @param {Object} target The target DD
23877 * @param {Event} e The event object
23878 * @param {String} id The id of the dropped element
23879 * @method afterInvalidDrop
23881 this.afterValidDrop(target, e, id);
23886 getRepairXY : function(e, data){
23887 return this.el.getXY();
23891 onInvalidDrop : function(target, e, id){
23892 this.beforeInvalidDrop(target, e, id);
23893 if(this.cachedTarget){
23894 if(this.cachedTarget.isNotifyTarget){
23895 this.cachedTarget.notifyOut(this, e, this.dragData);
23897 this.cacheTarget = null;
23899 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
23901 if(this.afterInvalidDrop){
23903 * An empty function by default, but provided so that you can perform a custom action
23904 * after an invalid drop has occurred by providing an implementation.
23905 * @param {Event} e The event object
23906 * @param {String} id The id of the dropped element
23907 * @method afterInvalidDrop
23909 this.afterInvalidDrop(e, id);
23914 afterRepair : function(){
23916 this.el.highlight(this.hlColor || "c3daf9");
23918 this.dragging = false;
23922 * An empty function by default, but provided so that you can perform a custom action after an invalid
23923 * drop has occurred.
23924 * @param {Roo.dd.DragDrop} target The drop target
23925 * @param {Event} e The event object
23926 * @param {String} id The id of the dragged element
23927 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
23929 beforeInvalidDrop : function(target, e, id){
23934 handleMouseDown : function(e){
23935 if(this.dragging) {
23938 var data = this.getDragData(e);
23939 if(data && this.onBeforeDrag(data, e) !== false){
23940 this.dragData = data;
23942 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
23947 * An empty function by default, but provided so that you can perform a custom action before the initial
23948 * drag event begins and optionally cancel it.
23949 * @param {Object} data An object containing arbitrary data to be shared with drop targets
23950 * @param {Event} e The event object
23951 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23953 onBeforeDrag : function(data, e){
23958 * An empty function by default, but provided so that you can perform a custom action once the initial
23959 * drag event has begun. The drag cannot be canceled from this function.
23960 * @param {Number} x The x position of the click on the dragged object
23961 * @param {Number} y The y position of the click on the dragged object
23963 onStartDrag : Roo.emptyFn,
23965 // private - YUI override
23966 startDrag : function(x, y){
23967 this.proxy.reset();
23968 this.dragging = true;
23969 this.proxy.update("");
23970 this.onInitDrag(x, y);
23975 onInitDrag : function(x, y){
23976 var clone = this.el.dom.cloneNode(true);
23977 clone.id = Roo.id(); // prevent duplicate ids
23978 this.proxy.update(clone);
23979 this.onStartDrag(x, y);
23984 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
23985 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
23987 getProxy : function(){
23992 * Hides the drag source's {@link Roo.dd.StatusProxy}
23994 hideProxy : function(){
23996 this.proxy.reset(true);
23997 this.dragging = false;
24001 triggerCacheRefresh : function(){
24002 Roo.dd.DDM.refreshCache(this.groups);
24005 // private - override to prevent hiding
24006 b4EndDrag: function(e) {
24009 // private - override to prevent moving
24010 endDrag : function(e){
24011 this.onEndDrag(this.dragData, e);
24015 onEndDrag : function(data, e){
24018 // private - pin to cursor
24019 autoOffset : function(x, y) {
24020 this.setDelta(-12, -20);
24024 * Ext JS Library 1.1.1
24025 * Copyright(c) 2006-2007, Ext JS, LLC.
24027 * Originally Released Under LGPL - original licence link has changed is not relivant.
24030 * <script type="text/javascript">
24035 * @class Roo.dd.DropTarget
24036 * @extends Roo.dd.DDTarget
24037 * A simple class that provides the basic implementation needed to make any element a drop target that can have
24038 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
24040 * @param {String/HTMLElement/Element} el The container element
24041 * @param {Object} config
24043 Roo.dd.DropTarget = function(el, config){
24044 this.el = Roo.get(el);
24046 var listeners = false; ;
24047 if (config && config.listeners) {
24048 listeners= config.listeners;
24049 delete config.listeners;
24051 Roo.apply(this, config);
24053 if(this.containerScroll){
24054 Roo.dd.ScrollManager.register(this.el);
24058 * @scope Roo.dd.DropTarget
24063 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
24064 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
24065 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
24067 * IMPORTANT : it should set this.valid to true|false
24069 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24070 * @param {Event} e The event
24071 * @param {Object} data An object containing arbitrary data supplied by the drag source
24077 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
24078 * This method will be called on every mouse movement while the drag source is over the drop target.
24079 * This default implementation simply returns the dropAllowed config value.
24081 * IMPORTANT : it should set this.valid to true|false
24083 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24084 * @param {Event} e The event
24085 * @param {Object} data An object containing arbitrary data supplied by the drag source
24091 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
24092 * out of the target without dropping. This default implementation simply removes the CSS class specified by
24093 * overClass (if any) from the drop element.
24096 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24097 * @param {Event} e The event
24098 * @param {Object} data An object containing arbitrary data supplied by the drag source
24104 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
24105 * been dropped on it. This method has no default implementation and returns false, so you must provide an
24106 * implementation that does something to process the drop event and returns true so that the drag source's
24107 * repair action does not run.
24109 * IMPORTANT : it should set this.success
24111 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24112 * @param {Event} e The event
24113 * @param {Object} data An object containing arbitrary data supplied by the drag source
24119 Roo.dd.DropTarget.superclass.constructor.call( this,
24121 this.ddGroup || this.group,
24124 listeners : listeners || {}
24132 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
24134 * @cfg {String} overClass
24135 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
24138 * @cfg {String} ddGroup
24139 * The drag drop group to handle drop events for
24143 * @cfg {String} dropAllowed
24144 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
24146 dropAllowed : "x-dd-drop-ok",
24148 * @cfg {String} dropNotAllowed
24149 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
24151 dropNotAllowed : "x-dd-drop-nodrop",
24153 * @cfg {boolean} success
24154 * set this after drop listener..
24158 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
24159 * if the drop point is valid for over/enter..
24166 isNotifyTarget : true,
24171 notifyEnter : function(dd, e, data)
24174 this.fireEvent('enter', dd, e, data);
24175 if(this.overClass){
24176 this.el.addClass(this.overClass);
24178 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
24179 this.valid ? this.dropAllowed : this.dropNotAllowed
24186 notifyOver : function(dd, e, data)
24189 this.fireEvent('over', dd, e, data);
24190 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
24191 this.valid ? this.dropAllowed : this.dropNotAllowed
24198 notifyOut : function(dd, e, data)
24200 this.fireEvent('out', dd, e, data);
24201 if(this.overClass){
24202 this.el.removeClass(this.overClass);
24209 notifyDrop : function(dd, e, data)
24211 this.success = false;
24212 this.fireEvent('drop', dd, e, data);
24213 return this.success;
24217 * Ext JS Library 1.1.1
24218 * Copyright(c) 2006-2007, Ext JS, LLC.
24220 * Originally Released Under LGPL - original licence link has changed is not relivant.
24223 * <script type="text/javascript">
24228 * @class Roo.dd.DragZone
24229 * @extends Roo.dd.DragSource
24230 * This class provides a container DD instance that proxies for multiple child node sources.<br />
24231 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
24233 * @param {String/HTMLElement/Element} el The container element
24234 * @param {Object} config
24236 Roo.dd.DragZone = function(el, config){
24237 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
24238 if(this.containerScroll){
24239 Roo.dd.ScrollManager.register(this.el);
24243 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
24245 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
24246 * for auto scrolling during drag operations.
24249 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
24250 * method after a failed drop (defaults to "c3daf9" - light blue)
24254 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
24255 * for a valid target to drag based on the mouse down. Override this method
24256 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
24257 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
24258 * @param {EventObject} e The mouse down event
24259 * @return {Object} The dragData
24261 getDragData : function(e){
24262 return Roo.dd.Registry.getHandleFromEvent(e);
24266 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
24267 * this.dragData.ddel
24268 * @param {Number} x The x position of the click on the dragged object
24269 * @param {Number} y The y position of the click on the dragged object
24270 * @return {Boolean} true to continue the drag, false to cancel
24272 onInitDrag : function(x, y){
24273 this.proxy.update(this.dragData.ddel.cloneNode(true));
24274 this.onStartDrag(x, y);
24279 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
24281 afterRepair : function(){
24283 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
24285 this.dragging = false;
24289 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
24290 * the XY of this.dragData.ddel
24291 * @param {EventObject} e The mouse up event
24292 * @return {Array} The xy location (e.g. [100, 200])
24294 getRepairXY : function(e){
24295 return Roo.Element.fly(this.dragData.ddel).getXY();
24299 * Ext JS Library 1.1.1
24300 * Copyright(c) 2006-2007, Ext JS, LLC.
24302 * Originally Released Under LGPL - original licence link has changed is not relivant.
24305 * <script type="text/javascript">
24308 * @class Roo.dd.DropZone
24309 * @extends Roo.dd.DropTarget
24310 * This class provides a container DD instance that proxies for multiple child node targets.<br />
24311 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
24313 * @param {String/HTMLElement/Element} el The container element
24314 * @param {Object} config
24316 Roo.dd.DropZone = function(el, config){
24317 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
24320 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
24322 * Returns a custom data object associated with the DOM node that is the target of the event. By default
24323 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
24324 * provide your own custom lookup.
24325 * @param {Event} e The event
24326 * @return {Object} data The custom data
24328 getTargetFromEvent : function(e){
24329 return Roo.dd.Registry.getTargetFromEvent(e);
24333 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
24334 * that it has registered. This method has no default implementation and should be overridden to provide
24335 * node-specific processing if necessary.
24336 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24337 * {@link #getTargetFromEvent} for this node)
24338 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24339 * @param {Event} e The event
24340 * @param {Object} data An object containing arbitrary data supplied by the drag source
24342 onNodeEnter : function(n, dd, e, data){
24347 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
24348 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
24349 * overridden to provide the proper feedback.
24350 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24351 * {@link #getTargetFromEvent} for this node)
24352 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24353 * @param {Event} e The event
24354 * @param {Object} data An object containing arbitrary data supplied by the drag source
24355 * @return {String} status The CSS class that communicates the drop status back to the source so that the
24356 * underlying {@link Roo.dd.StatusProxy} can be updated
24358 onNodeOver : function(n, dd, e, data){
24359 return this.dropAllowed;
24363 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
24364 * the drop node without dropping. This method has no default implementation and should be overridden to provide
24365 * node-specific processing if necessary.
24366 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24367 * {@link #getTargetFromEvent} for this node)
24368 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24369 * @param {Event} e The event
24370 * @param {Object} data An object containing arbitrary data supplied by the drag source
24372 onNodeOut : function(n, dd, e, data){
24377 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
24378 * the drop node. The default implementation returns false, so it should be overridden to provide the
24379 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
24380 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24381 * {@link #getTargetFromEvent} for this node)
24382 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24383 * @param {Event} e The event
24384 * @param {Object} data An object containing arbitrary data supplied by the drag source
24385 * @return {Boolean} True if the drop was valid, else false
24387 onNodeDrop : function(n, dd, e, data){
24392 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
24393 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
24394 * it should be overridden to provide the proper feedback if necessary.
24395 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24396 * @param {Event} e The event
24397 * @param {Object} data An object containing arbitrary data supplied by the drag source
24398 * @return {String} status The CSS class that communicates the drop status back to the source so that the
24399 * underlying {@link Roo.dd.StatusProxy} can be updated
24401 onContainerOver : function(dd, e, data){
24402 return this.dropNotAllowed;
24406 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
24407 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
24408 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
24409 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
24410 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24411 * @param {Event} e The event
24412 * @param {Object} data An object containing arbitrary data supplied by the drag source
24413 * @return {Boolean} True if the drop was valid, else false
24415 onContainerDrop : function(dd, e, data){
24420 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
24421 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
24422 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
24423 * you should override this method and provide a custom implementation.
24424 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24425 * @param {Event} e The event
24426 * @param {Object} data An object containing arbitrary data supplied by the drag source
24427 * @return {String} status The CSS class that communicates the drop status back to the source so that the
24428 * underlying {@link Roo.dd.StatusProxy} can be updated
24430 notifyEnter : function(dd, e, data){
24431 return this.dropNotAllowed;
24435 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
24436 * This method will be called on every mouse movement while the drag source is over the drop zone.
24437 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
24438 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
24439 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
24440 * registered node, it will call {@link #onContainerOver}.
24441 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24442 * @param {Event} e The event
24443 * @param {Object} data An object containing arbitrary data supplied by the drag source
24444 * @return {String} status The CSS class that communicates the drop status back to the source so that the
24445 * underlying {@link Roo.dd.StatusProxy} can be updated
24447 notifyOver : function(dd, e, data){
24448 var n = this.getTargetFromEvent(e);
24449 if(!n){ // not over valid drop target
24450 if(this.lastOverNode){
24451 this.onNodeOut(this.lastOverNode, dd, e, data);
24452 this.lastOverNode = null;
24454 return this.onContainerOver(dd, e, data);
24456 if(this.lastOverNode != n){
24457 if(this.lastOverNode){
24458 this.onNodeOut(this.lastOverNode, dd, e, data);
24460 this.onNodeEnter(n, dd, e, data);
24461 this.lastOverNode = n;
24463 return this.onNodeOver(n, dd, e, data);
24467 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
24468 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
24469 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
24470 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24471 * @param {Event} e The event
24472 * @param {Object} data An object containing arbitrary data supplied by the drag zone
24474 notifyOut : function(dd, e, data){
24475 if(this.lastOverNode){
24476 this.onNodeOut(this.lastOverNode, dd, e, data);
24477 this.lastOverNode = null;
24482 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
24483 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
24484 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
24485 * otherwise it will call {@link #onContainerDrop}.
24486 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24487 * @param {Event} e The event
24488 * @param {Object} data An object containing arbitrary data supplied by the drag source
24489 * @return {Boolean} True if the drop was valid, else false
24491 notifyDrop : function(dd, e, data){
24492 if(this.lastOverNode){
24493 this.onNodeOut(this.lastOverNode, dd, e, data);
24494 this.lastOverNode = null;
24496 var n = this.getTargetFromEvent(e);
24498 this.onNodeDrop(n, dd, e, data) :
24499 this.onContainerDrop(dd, e, data);
24503 triggerCacheRefresh : function(){
24504 Roo.dd.DDM.refreshCache(this.groups);