4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isFirefox = ua.indexOf("firefox") > -1,
57 isIE = ua.indexOf("msie") > -1,
58 isIE7 = ua.indexOf("msie 7") > -1,
59 isIE11 = /trident.*rv\:11\./.test(ua),
60 isEdge = ua.indexOf("edge") > -1,
61 isGecko = !isSafari && ua.indexOf("gecko") > -1,
62 isBorderBox = isIE && !isStrict,
63 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
64 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
65 isLinux = (ua.indexOf("linux") != -1),
66 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
67 isIOS = /iphone|ipad/.test(ua),
68 isAndroid = /android/.test(ua),
69 isTouch = (function() {
71 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
72 window.addEventListener('touchstart', function __set_has_touch__ () {
74 window.removeEventListener('touchstart', __set_has_touch__);
76 return false; // no touch on chrome!?
78 document.createEvent("TouchEvent");
85 // remove css image flicker
88 document.execCommand("BackgroundImageCache", false, true);
94 * True if the browser is in strict mode
99 * True if the page is running over SSL
104 * True when the document is fully initialized and ready for action
109 * Turn on debugging output (currently only the factory uses this)
116 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
119 enableGarbageCollector : true,
122 * True to automatically purge event listeners after uncaching an element (defaults to false).
123 * Note: this only happens if enableGarbageCollector is true.
126 enableListenerCollection:false,
129 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
130 * the IE insecure content warning (defaults to javascript:false).
133 SSL_SECURE_URL : "javascript:false",
136 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
137 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
140 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
142 emptyFn : function(){},
145 * Copies all the properties of config to obj if they don't already exist.
146 * @param {Object} obj The receiver of the properties
147 * @param {Object} config The source of the properties
148 * @return {Object} returns obj
150 applyIf : function(o, c){
153 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
160 * Applies event listeners to elements by selectors when the document is ready.
161 * The event name is specified with an @ suffix.
164 // add a listener for click on all anchors in element with id foo
165 '#foo a@click' : function(e, t){
169 // add the same listener to multiple selectors (separated by comma BEFORE the @)
170 '#foo a, #bar span.some-class@mouseover' : function(){
175 * @param {Object} obj The list of behaviors to apply
177 addBehaviors : function(o){
179 Roo.onReady(function(){
184 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
186 var parts = b.split('@');
187 if(parts[1]){ // for Object prototype breakers
190 cache[s] = Roo.select(s);
192 cache[s].on(parts[1], o[b]);
199 * Generates unique ids. If the element already has an id, it is unchanged
200 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
201 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
202 * @return {String} The generated Id.
204 id : function(el, prefix){
205 prefix = prefix || "roo-gen";
207 var id = prefix + (++idSeed);
208 return el ? (el.id ? el.id : (el.id = id)) : id;
213 * Extends one class with another class and optionally overrides members with the passed literal. This class
214 * also adds the function "override()" to the class that can be used to override
215 * members on an instance.
216 * @param {Object} subclass The class inheriting the functionality
217 * @param {Object} superclass The class being extended
218 * @param {Object} overrides (optional) A literal with members
223 var io = function(o){
228 return function(sb, sp, overrides){
229 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
232 sb = function(){sp.apply(this, arguments);};
234 var F = function(){}, sbp, spp = sp.prototype;
236 sbp = sb.prototype = new F();
240 if(spp.constructor == Object.prototype.constructor){
245 sb.override = function(o){
249 Roo.override(sb, overrides);
255 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
257 Roo.override(MyClass, {
258 newMethod1: function(){
261 newMethod2: function(foo){
266 * @param {Object} origclass The class to override
267 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
268 * containing one or more methods.
271 override : function(origclass, overrides){
273 var p = origclass.prototype;
274 for(var method in overrides){
275 p[method] = overrides[method];
280 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
282 Roo.namespace('Company', 'Company.data');
283 Company.Widget = function() { ... }
284 Company.data.CustomStore = function(config) { ... }
286 * @param {String} namespace1
287 * @param {String} namespace2
288 * @param {String} etc
291 namespace : function(){
292 var a=arguments, o=null, i, j, d, rt;
293 for (i=0; i<a.length; ++i) {
297 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
298 for (j=1; j<d.length; ++j) {
299 o[d[j]]=o[d[j]] || {};
305 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
307 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
308 Roo.factory(conf, Roo.data);
310 * @param {String} classname
311 * @param {String} namespace (optional)
315 factory : function(c, ns)
317 // no xtype, no ns or c.xns - or forced off by c.xns
318 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
321 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
322 if (c.constructor == ns[c.xtype]) {// already created...
326 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
327 var ret = new ns[c.xtype](c);
331 c.xns = false; // prevent recursion..
335 * Logs to console if it can.
337 * @param {String|Object} string
342 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
349 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
353 urlEncode : function(o){
359 var ov = o[key], k = Roo.encodeURIComponent(key);
360 var type = typeof ov;
361 if(type == 'undefined'){
363 }else if(type != "function" && type != "object"){
364 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
365 }else if(ov instanceof Array){
367 for(var i = 0, len = ov.length; i < len; i++) {
368 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
379 * Safe version of encodeURIComponent
380 * @param {String} data
384 encodeURIComponent : function (data)
387 return encodeURIComponent(data);
388 } catch(e) {} // should be an uri encode error.
390 if (data == '' || data == null){
393 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
394 function nibble_to_hex(nibble){
395 var chars = '0123456789ABCDEF';
396 return chars.charAt(nibble);
398 data = data.toString();
400 for(var i=0; i<data.length; i++){
401 var c = data.charCodeAt(i);
402 var bs = new Array();
405 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
406 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
407 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
408 bs[3] = 0x80 | (c & 0x3F);
409 }else if (c > 0x800){
411 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
412 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
413 bs[2] = 0x80 | (c & 0x3F);
416 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
417 bs[1] = 0x80 | (c & 0x3F);
422 for(var j=0; j<bs.length; j++){
424 var hex = nibble_to_hex((b & 0xF0) >>> 4)
425 + nibble_to_hex(b &0x0F);
434 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
435 * @param {String} string
436 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
437 * @return {Object} A literal with members
439 urlDecode : function(string, overwrite){
440 if(!string || !string.length){
444 var pairs = string.split('&');
445 var pair, name, value;
446 for(var i = 0, len = pairs.length; i < len; i++){
447 pair = pairs[i].split('=');
448 name = decodeURIComponent(pair[0]);
449 value = decodeURIComponent(pair[1]);
450 if(overwrite !== true){
451 if(typeof obj[name] == "undefined"){
453 }else if(typeof obj[name] == "string"){
454 obj[name] = [obj[name]];
455 obj[name].push(value);
457 obj[name].push(value);
467 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
468 * passed array is not really an array, your function is called once with it.
469 * The supplied function is called with (Object item, Number index, Array allItems).
470 * @param {Array/NodeList/Mixed} array
471 * @param {Function} fn
472 * @param {Object} scope
474 each : function(array, fn, scope){
475 if(typeof array.length == "undefined" || typeof array == "string"){
478 for(var i = 0, len = array.length; i < len; i++){
479 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
484 combine : function(){
485 var as = arguments, l = as.length, r = [];
486 for(var i = 0; i < l; i++){
488 if(a instanceof Array){
490 }else if(a.length !== undefined && !a.substr){
491 r = r.concat(Array.prototype.slice.call(a, 0));
500 * Escapes the passed string for use in a regular expression
501 * @param {String} str
504 escapeRe : function(s) {
505 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
509 callback : function(cb, scope, args, delay){
510 if(typeof cb == "function"){
512 cb.defer(delay, scope, args || []);
514 cb.apply(scope, args || []);
520 * Return the dom node for the passed string (id), dom node, or Roo.Element
521 * @param {String/HTMLElement/Roo.Element} el
522 * @return HTMLElement
524 getDom : function(el){
528 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
532 * Shorthand for {@link Roo.ComponentMgr#get}
534 * @return Roo.Component
536 getCmp : function(id){
537 return Roo.ComponentMgr.get(id);
540 num : function(v, defaultValue){
541 if(typeof v != 'number'){
547 destroy : function(){
548 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
552 as.removeAllListeners();
556 if(typeof as.purgeListeners == 'function'){
559 if(typeof as.destroy == 'function'){
566 // inpired by a similar function in mootools library
568 * Returns the type of object that is passed in. If the object passed in is null or undefined it
569 * return false otherwise it returns one of the following values:<ul>
570 * <li><b>string</b>: If the object passed is a string</li>
571 * <li><b>number</b>: If the object passed is a number</li>
572 * <li><b>boolean</b>: If the object passed is a boolean value</li>
573 * <li><b>function</b>: If the object passed is a function reference</li>
574 * <li><b>object</b>: If the object passed is an object</li>
575 * <li><b>array</b>: If the object passed is an array</li>
576 * <li><b>regexp</b>: If the object passed is a regular expression</li>
577 * <li><b>element</b>: If the object passed is a DOM Element</li>
578 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
579 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
580 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
581 * @param {Mixed} object
585 if(o === undefined || o === null){
592 if(t == 'object' && o.nodeName) {
594 case 1: return 'element';
595 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
598 if(t == 'object' || t == 'function') {
599 switch(o.constructor) {
600 case Array: return 'array';
601 case RegExp: return 'regexp';
603 if(typeof o.length == 'number' && typeof o.item == 'function') {
611 * Returns true if the passed value is null, undefined or an empty string (optional).
612 * @param {Mixed} value The value to test
613 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
616 isEmpty : function(v, allowBlank){
617 return v === null || v === undefined || (!allowBlank ? v === '' : false);
625 isFirefox : isFirefox,
637 isBorderBox : isBorderBox,
639 isWindows : isWindows,
647 isAndroid : isAndroid,
652 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
653 * you may want to set this to true.
656 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
661 * Selects a single element as a Roo Element
662 * This is about as close as you can get to jQuery's $('do crazy stuff')
663 * @param {String} selector The selector/xpath query
664 * @param {Node} root (optional) The start of the query (defaults to document).
665 * @return {Roo.Element}
667 selectNode : function(selector, root)
669 var node = Roo.DomQuery.selectNode(selector,root);
670 return node ? Roo.get(node) : new Roo.Element(false);
673 * Find the current bootstrap width Grid size
674 * Note xs is the default for smaller.. - this is currently used by grids to render correct columns
675 * @returns {String} (xs|sm|md|lg|xl)
678 getGridSize : function()
680 var w = Roo.lib.Dom.getViewWidth();
701 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
702 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
707 * Ext JS Library 1.1.1
708 * Copyright(c) 2006-2007, Ext JS, LLC.
710 * Originally Released Under LGPL - original licence link has changed is not relivant.
713 * <script type="text/javascript">
717 // wrappedn so fnCleanup is not in global scope...
719 function fnCleanUp() {
720 var p = Function.prototype;
721 delete p.createSequence;
723 delete p.createDelegate;
724 delete p.createCallback;
725 delete p.createInterceptor;
727 window.detachEvent("onunload", fnCleanUp);
729 window.attachEvent("onunload", fnCleanUp);
736 * These functions are available on every Function object (any JavaScript function).
738 Roo.apply(Function.prototype, {
740 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
741 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
742 * Will create a function that is bound to those 2 args.
743 * @return {Function} The new function
745 createCallback : function(/*args...*/){
746 // make args available, in function below
747 var args = arguments;
750 return method.apply(window, args);
755 * Creates a delegate (callback) that sets the scope to obj.
756 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
757 * Will create a function that is automatically scoped to this.
758 * @param {Object} obj (optional) The object for which the scope is set
759 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
760 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
761 * if a number the args are inserted at the specified position
762 * @return {Function} The new function
764 createDelegate : function(obj, args, appendArgs){
767 var callArgs = args || arguments;
768 if(appendArgs === true){
769 callArgs = Array.prototype.slice.call(arguments, 0);
770 callArgs = callArgs.concat(args);
771 }else if(typeof appendArgs == "number"){
772 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
773 var applyArgs = [appendArgs, 0].concat(args); // create method call params
774 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
776 return method.apply(obj || window, callArgs);
781 * Calls this function after the number of millseconds specified.
782 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
783 * @param {Object} obj (optional) The object for which the scope is set
784 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
785 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
786 * if a number the args are inserted at the specified position
787 * @return {Number} The timeout id that can be used with clearTimeout
789 defer : function(millis, obj, args, appendArgs){
790 var fn = this.createDelegate(obj, args, appendArgs);
792 return setTimeout(fn, millis);
798 * Create a combined function call sequence of the original function + the passed function.
799 * The resulting function returns the results of the original function.
800 * The passed fcn is called with the parameters of the original function
801 * @param {Function} fcn The function to sequence
802 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
803 * @return {Function} The new function
805 createSequence : function(fcn, scope){
806 if(typeof fcn != "function"){
811 var retval = method.apply(this || window, arguments);
812 fcn.apply(scope || this || window, arguments);
818 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
819 * The resulting function returns the results of the original function.
820 * The passed fcn is called with the parameters of the original function.
822 * @param {Function} fcn The function to call before the original
823 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
824 * @return {Function} The new function
826 createInterceptor : function(fcn, scope){
827 if(typeof fcn != "function"){
834 if(fcn.apply(scope || this || window, arguments) === false){
837 return method.apply(this || window, arguments);
843 * Ext JS Library 1.1.1
844 * Copyright(c) 2006-2007, Ext JS, LLC.
846 * Originally Released Under LGPL - original licence link has changed is not relivant.
849 * <script type="text/javascript">
852 Roo.applyIf(String, {
857 * Escapes the passed string for ' and \
858 * @param {String} string The string to escape
859 * @return {String} The escaped string
862 escape : function(string) {
863 return string.replace(/('|\\)/g, "\\$1");
867 * Pads the left side of a string with a specified character. This is especially useful
868 * for normalizing number and date strings. Example usage:
870 var s = String.leftPad('123', 5, '0');
871 // s now contains the string: '00123'
873 * @param {String} string The original string
874 * @param {Number} size The total length of the output string
875 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
876 * @return {String} The padded string
879 leftPad : function (val, size, ch) {
880 var result = new String(val);
881 if(ch === null || ch === undefined || ch === '') {
884 while (result.length < size) {
885 result = ch + result;
891 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
892 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
894 var cls = 'my-class', text = 'Some text';
895 var s = String.format('<div class="{0}">{1}</div>', cls, text);
896 // s now contains the string: '<div class="my-class">Some text</div>'
898 * @param {String} string The tokenized string to be formatted
899 * @param {String} value1 The value to replace token {0}
900 * @param {String} value2 Etc...
901 * @return {String} The formatted string
904 format : function(format){
905 var args = Array.prototype.slice.call(arguments, 1);
906 return format.replace(/\{(\d+)\}/g, function(m, i){
907 return Roo.util.Format.htmlEncode(args[i]);
915 * Utility function that allows you to easily switch a string between two alternating values. The passed value
916 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
917 * they are already different, the first value passed in is returned. Note that this method returns the new value
918 * but does not change the current string.
920 // alternate sort directions
921 sort = sort.toggle('ASC', 'DESC');
923 // instead of conditional logic:
924 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
926 * @param {String} value The value to compare to the current string
927 * @param {String} other The new value to use if the string already equals the first value passed in
928 * @return {String} The new value
931 String.prototype.toggle = function(value, other){
932 return this == value ? other : value;
937 * Remove invalid unicode characters from a string
939 * @return {String} The clean string
941 String.prototype.unicodeClean = function () {
942 return this.replace(/[\s\S]/g,
943 function(character) {
944 if (character.charCodeAt()< 256) {
948 encodeURIComponent(character);
959 * Make the first letter of a string uppercase
961 * @return {String} The new string.
963 String.prototype.toUpperCaseFirst = function () {
964 return this.charAt(0).toUpperCase() + this.slice(1);
969 * Ext JS Library 1.1.1
970 * Copyright(c) 2006-2007, Ext JS, LLC.
972 * Originally Released Under LGPL - original licence link has changed is not relivant.
975 * <script type="text/javascript">
981 Roo.applyIf(Number.prototype, {
983 * Checks whether or not the current number is within a desired range. If the number is already within the
984 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
985 * exceeded. Note that this method returns the constrained value but does not change the current number.
986 * @param {Number} min The minimum number in the range
987 * @param {Number} max The maximum number in the range
988 * @return {Number} The constrained value if outside the range, otherwise the current value
990 constrain : function(min, max){
991 return Math.min(Math.max(this, min), max);
995 * Ext JS Library 1.1.1
996 * Copyright(c) 2006-2007, Ext JS, LLC.
998 * Originally Released Under LGPL - original licence link has changed is not relivant.
1001 * <script type="text/javascript">
1006 Roo.applyIf(Array.prototype, {
1009 * Checks whether or not the specified object exists in the array.
1010 * @param {Object} o The object to check for
1011 * @return {Number} The index of o in the array (or -1 if it is not found)
1013 indexOf : function(o){
1014 for (var i = 0, len = this.length; i < len; i++){
1015 if(this[i] == o) { return i; }
1021 * Removes the specified object from the array. If the object is not found nothing happens.
1022 * @param {Object} o The object to remove
1024 remove : function(o){
1025 var index = this.indexOf(o);
1027 this.splice(index, 1);
1031 * Map (JS 1.6 compatibility)
1032 * @param {Function} function to call
1034 map : function(fun )
1036 var len = this.length >>> 0;
1037 if (typeof fun != "function") {
1038 throw new TypeError();
1040 var res = new Array(len);
1041 var thisp = arguments[1];
1042 for (var i = 0; i < len; i++)
1045 res[i] = fun.call(thisp, this[i], i, this);
1053 * @param {Array} o The array to compare to
1054 * @returns {Boolean} true if the same
1056 equals : function(b)
1058 // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
1065 if (this.length !== b.length) {
1069 // sort?? a.sort().equals(b.sort());
1071 for (var i = 0; i < this.length; ++i) {
1072 if (this[i] !== b[i]) {
1084 Roo.applyIf(Array, {
1088 * @param {Array} o Or Array like object (eg. nodelist)
1095 for (var i =0; i < o.length; i++) {
1104 * Ext JS Library 1.1.1
1105 * Copyright(c) 2006-2007, Ext JS, LLC.
1107 * Originally Released Under LGPL - original licence link has changed is not relivant.
1110 * <script type="text/javascript">
1116 * The date parsing and format syntax is a subset of
1117 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1118 * supported will provide results equivalent to their PHP versions.
1120 * Following is the list of all currently supported formats:
1123 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1125 Format Output Description
1126 ------ ---------- --------------------------------------------------------------
1127 d 10 Day of the month, 2 digits with leading zeros
1128 D Wed A textual representation of a day, three letters
1129 j 10 Day of the month without leading zeros
1130 l Wednesday A full textual representation of the day of the week
1131 S th English ordinal day of month suffix, 2 chars (use with j)
1132 w 3 Numeric representation of the day of the week
1133 z 9 The julian date, or day of the year (0-365)
1134 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1135 F January A full textual representation of the month
1136 m 01 Numeric representation of a month, with leading zeros
1137 M Jan Month name abbreviation, three letters
1138 n 1 Numeric representation of a month, without leading zeros
1139 t 31 Number of days in the given month
1140 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1141 Y 2007 A full numeric representation of a year, 4 digits
1142 y 07 A two digit representation of a year
1143 a pm Lowercase Ante meridiem and Post meridiem
1144 A PM Uppercase Ante meridiem and Post meridiem
1145 g 3 12-hour format of an hour without leading zeros
1146 G 15 24-hour format of an hour without leading zeros
1147 h 03 12-hour format of an hour with leading zeros
1148 H 15 24-hour format of an hour with leading zeros
1149 i 05 Minutes with leading zeros
1150 s 01 Seconds, with leading zeros
1151 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1152 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1153 T CST Timezone setting of the machine running the code
1154 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1157 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1159 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1160 document.write(dt.format('Y-m-d')); //2007-01-10
1161 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1162 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
1165 * Here are some standard date/time patterns that you might find helpful. They
1166 * are not part of the source of Date.js, but to use them you can simply copy this
1167 * block of code into any script that is included after Date.js and they will also become
1168 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1171 ISO8601Long:"Y-m-d H:i:s",
1172 ISO8601Short:"Y-m-d",
1174 LongDate: "l, F d, Y",
1175 FullDateTime: "l, F d, Y g:i:s A",
1178 LongTime: "g:i:s A",
1179 SortableDateTime: "Y-m-d\\TH:i:s",
1180 UniversalSortableDateTime: "Y-m-d H:i:sO",
1187 var dt = new Date();
1188 document.write(dt.format(Date.patterns.ShortDate));
1193 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1194 * They generate precompiled functions from date formats instead of parsing and
1195 * processing the pattern every time you format a date. These functions are available
1196 * on every Date object (any javascript function).
1198 * The original article and download are here:
1199 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1206 Returns the number of milliseconds between this date and date
1207 @param {Date} date (optional) Defaults to now
1208 @param {String} interval (optional) Default Date.MILLI, A valid date interval enum value (eg. Date.DAY)
1209 @return {Number} The diff in milliseconds or units of interval
1210 @member Date getElapsed
1212 Date.prototype.getElapsed = function(date, interval)
1214 date = date || new Date();
1215 var ret = Math.abs(date.getTime()-this.getTime());
1219 return Math.floor(ret / (1000));
1221 return Math.floor(ret / (1000*60));
1223 return Math.floor(ret / (1000*60*60));
1225 return Math.floor(ret / (1000*60*60*24));
1226 case Date.MONTH: // this does not give exact number...??
1227 return ((date.format("Y") - this.format("Y")) * 12) + (date.format("m") - this.format("m"));
1228 case Date.YEAR: // this does not give exact number...??
1229 return (date.format("Y") - this.format("Y"));
1237 // was in date file..
1241 Date.parseFunctions = {count:0};
1243 Date.parseRegexes = [];
1245 Date.formatFunctions = {count:0};
1248 Date.prototype.dateFormat = function(format) {
1249 if (Date.formatFunctions[format] == null) {
1250 Date.createNewFormat(format);
1252 var func = Date.formatFunctions[format];
1253 return this[func]();
1258 * Formats a date given the supplied format string
1259 * @param {String} format The format string
1260 * @return {String} The formatted date
1263 Date.prototype.format = Date.prototype.dateFormat;
1266 Date.createNewFormat = function(format) {
1267 var funcName = "format" + Date.formatFunctions.count++;
1268 Date.formatFunctions[format] = funcName;
1269 var code = "Date.prototype." + funcName + " = function(){return ";
1270 var special = false;
1272 for (var i = 0; i < format.length; ++i) {
1273 ch = format.charAt(i);
1274 if (!special && ch == "\\") {
1279 code += "'" + String.escape(ch) + "' + ";
1282 code += Date.getFormatCode(ch);
1285 /** eval:var:zzzzzzzzzzzzz */
1286 eval(code.substring(0, code.length - 3) + ";}");
1290 Date.getFormatCode = function(character) {
1291 switch (character) {
1293 return "String.leftPad(this.getDate(), 2, '0') + ";
1295 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1297 return "this.getDate() + ";
1299 return "Date.dayNames[this.getDay()] + ";
1301 return "this.getSuffix() + ";
1303 return "this.getDay() + ";
1305 return "this.getDayOfYear() + ";
1307 return "this.getWeekOfYear() + ";
1309 return "Date.monthNames[this.getMonth()] + ";
1311 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1313 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1315 return "(this.getMonth() + 1) + ";
1317 return "this.getDaysInMonth() + ";
1319 return "(this.isLeapYear() ? 1 : 0) + ";
1321 return "this.getFullYear() + ";
1323 return "('' + this.getFullYear()).substring(2, 4) + ";
1325 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1327 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1329 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1331 return "this.getHours() + ";
1333 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1335 return "String.leftPad(this.getHours(), 2, '0') + ";
1337 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1339 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1341 return "this.getGMTOffset() + ";
1343 return "this.getGMTColonOffset() + ";
1345 return "this.getTimezone() + ";
1347 return "(this.getTimezoneOffset() * -60) + ";
1349 return "'" + String.escape(character) + "' + ";
1354 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1355 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1356 * the date format that is not specified will default to the current date value for that part. Time parts can also
1357 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1358 * string or the parse operation will fail.
1361 //dt = Fri May 25 2007 (current date)
1362 var dt = new Date();
1364 //dt = Thu May 25 2006 (today's month/day in 2006)
1365 dt = Date.parseDate("2006", "Y");
1367 //dt = Sun Jan 15 2006 (all date parts specified)
1368 dt = Date.parseDate("2006-1-15", "Y-m-d");
1370 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1371 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1373 * @param {String} input The unparsed date as a string
1374 * @param {String} format The format the date is in
1375 * @return {Date} The parsed date
1378 Date.parseDate = function(input, format) {
1379 if (Date.parseFunctions[format] == null) {
1380 Date.createParser(format);
1382 var func = Date.parseFunctions[format];
1383 return Date[func](input);
1389 Date.createParser = function(format) {
1390 var funcName = "parse" + Date.parseFunctions.count++;
1391 var regexNum = Date.parseRegexes.length;
1392 var currentGroup = 1;
1393 Date.parseFunctions[format] = funcName;
1395 var code = "Date." + funcName + " = function(input){\n"
1396 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1397 + "var d = new Date();\n"
1398 + "y = d.getFullYear();\n"
1399 + "m = d.getMonth();\n"
1400 + "d = d.getDate();\n"
1401 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1402 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1403 + "if (results && results.length > 0) {";
1406 var special = false;
1408 for (var i = 0; i < format.length; ++i) {
1409 ch = format.charAt(i);
1410 if (!special && ch == "\\") {
1415 regex += String.escape(ch);
1418 var obj = Date.formatCodeToRegex(ch, currentGroup);
1419 currentGroup += obj.g;
1421 if (obj.g && obj.c) {
1427 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1428 + "{v = new Date(y, m, d, h, i, s); v.setFullYear(y);}\n"
1429 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1430 + "{v = new Date(y, m, d, h, i); v.setFullYear(y);}\n"
1431 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1432 + "{v = new Date(y, m, d, h); v.setFullYear(y);}\n"
1433 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1434 + "{v = new Date(y, m, d); v.setFullYear(y);}\n"
1435 + "else if (y >= 0 && m >= 0)\n"
1436 + "{v = new Date(y, m); v.setFullYear(y);}\n"
1437 + "else if (y >= 0)\n"
1438 + "{v = new Date(y); v.setFullYear(y);}\n"
1439 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1440 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1441 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1444 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1445 /** eval:var:zzzzzzzzzzzzz */
1450 Date.formatCodeToRegex = function(character, currentGroup) {
1451 switch (character) {
1455 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1458 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1459 s:"(\\d{1,2})"}; // day of month without leading zeroes
1462 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1463 s:"(\\d{2})"}; // day of month with leading zeroes
1467 s:"(?:" + Date.dayNames.join("|") + ")"};
1471 s:"(?:st|nd|rd|th)"};
1486 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1487 s:"(" + Date.monthNames.join("|") + ")"};
1490 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1491 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1494 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1495 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1498 c:"m = Math.max(0,parseInt(results[" + currentGroup + "], 10) - 1);\n",
1499 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1510 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1514 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1515 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1519 c:"if (results[" + currentGroup + "] == 'am') {\n"
1520 + "if (h == 12) { h = 0; }\n"
1521 + "} else { if (h < 12) { h += 12; }}",
1525 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1526 + "if (h == 12) { h = 0; }\n"
1527 + "} else { if (h < 12) { h += 12; }}",
1532 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1533 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1537 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1538 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1541 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1545 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1550 "o = results[", currentGroup, "];\n",
1551 "var sn = o.substring(0,1);\n", // get + / - sign
1552 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1553 "var mn = o.substring(3,5) % 60;\n", // get minutes
1554 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1555 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1557 s:"([+\-]\\d{2,4})"};
1563 "o = results[", currentGroup, "];\n",
1564 "var sn = o.substring(0,1);\n",
1565 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1566 "var mn = o.substring(4,6) % 60;\n",
1567 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1568 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1574 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1577 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1578 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1579 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1583 s:String.escape(character)};
1588 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1589 * @return {String} The abbreviated timezone name (e.g. 'CST')
1591 Date.prototype.getTimezone = function() {
1592 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1596 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1597 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1599 Date.prototype.getGMTOffset = function() {
1600 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1601 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1602 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1606 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1607 * @return {String} 2-characters representing hours and 2-characters representing minutes
1608 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1610 Date.prototype.getGMTColonOffset = function() {
1611 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1612 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1614 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1618 * Get the numeric day number of the year, adjusted for leap year.
1619 * @return {Number} 0 through 364 (365 in leap years)
1621 Date.prototype.getDayOfYear = function() {
1623 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1624 for (var i = 0; i < this.getMonth(); ++i) {
1625 num += Date.daysInMonth[i];
1627 return num + this.getDate() - 1;
1631 * Get the string representation of the numeric week number of the year
1632 * (equivalent to the format specifier 'W').
1633 * @return {String} '00' through '52'
1635 Date.prototype.getWeekOfYear = function() {
1636 // Skip to Thursday of this week
1637 var now = this.getDayOfYear() + (4 - this.getDay());
1638 // Find the first Thursday of the year
1639 var jan1 = new Date(this.getFullYear(), 0, 1);
1640 var then = (7 - jan1.getDay() + 4);
1641 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1645 * Whether or not the current date is in a leap year.
1646 * @return {Boolean} True if the current date is in a leap year, else false
1648 Date.prototype.isLeapYear = function() {
1649 var year = this.getFullYear();
1650 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1654 * Get the first day of the current month, adjusted for leap year. The returned value
1655 * is the numeric day index within the week (0-6) which can be used in conjunction with
1656 * the {@link #monthNames} array to retrieve the textual day name.
1659 var dt = new Date('1/10/2007');
1660 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1662 * @return {Number} The day number (0-6)
1664 Date.prototype.getFirstDayOfMonth = function() {
1665 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1666 return (day < 0) ? (day + 7) : day;
1670 * Get the last day of the current month, adjusted for leap year. The returned value
1671 * is the numeric day index within the week (0-6) which can be used in conjunction with
1672 * the {@link #monthNames} array to retrieve the textual day name.
1675 var dt = new Date('1/10/2007');
1676 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1678 * @return {Number} The day number (0-6)
1680 Date.prototype.getLastDayOfMonth = function() {
1681 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1682 return (day < 0) ? (day + 7) : day;
1687 * Get the first date of this date's month
1690 Date.prototype.getFirstDateOfMonth = function() {
1691 return new Date(this.getFullYear(), this.getMonth(), 1);
1695 * Get the last date of this date's month
1698 Date.prototype.getLastDateOfMonth = function() {
1699 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1702 * Get the number of days in the current month, adjusted for leap year.
1703 * @return {Number} The number of days in the month
1705 Date.prototype.getDaysInMonth = function() {
1706 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1707 return Date.daysInMonth[this.getMonth()];
1711 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1712 * @return {String} 'st, 'nd', 'rd' or 'th'
1714 Date.prototype.getSuffix = function() {
1715 switch (this.getDate()) {
1732 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1735 * An array of textual month names.
1736 * Override these values for international dates, for example...
1737 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1756 * An array of textual day names.
1757 * Override these values for international dates, for example...
1758 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1774 Date.monthNumbers = {
1789 * Creates and returns a new Date instance with the exact same date value as the called instance.
1790 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1791 * variable will also be changed. When the intention is to create a new variable that will not
1792 * modify the original instance, you should create a clone.
1794 * Example of correctly cloning a date:
1797 var orig = new Date('10/1/2006');
1800 document.write(orig); //returns 'Thu Oct 05 2006'!
1803 var orig = new Date('10/1/2006');
1804 var copy = orig.clone();
1806 document.write(orig); //returns 'Thu Oct 01 2006'
1808 * @return {Date} The new Date instance
1810 Date.prototype.clone = function() {
1811 return new Date(this.getTime());
1815 * Clears any time information from this date
1816 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1817 @return {Date} this or the clone
1819 Date.prototype.clearTime = function(clone){
1821 return this.clone().clearTime();
1826 this.setMilliseconds(0);
1831 // safari setMonth is broken -- check that this is only donw once...
1832 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1833 Date.brokenSetMonth = Date.prototype.setMonth;
1834 Date.prototype.setMonth = function(num){
1836 var n = Math.ceil(-num);
1837 var back_year = Math.ceil(n/12);
1838 var month = (n % 12) ? 12 - n % 12 : 0 ;
1839 this.setFullYear(this.getFullYear() - back_year);
1840 return Date.brokenSetMonth.call(this, month);
1842 return Date.brokenSetMonth.apply(this, arguments);
1847 /** Date interval constant
1851 /** Date interval constant
1855 /** Date interval constant
1859 /** Date interval constant
1863 /** Date interval constant
1867 /** Date interval constant
1871 /** Date interval constant
1877 * Provides a convenient method of performing basic date arithmetic. This method
1878 * does not modify the Date instance being called - it creates and returns
1879 * a new Date instance containing the resulting date value.
1884 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1885 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1887 //Negative values will subtract correctly:
1888 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1889 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1891 //You can even chain several calls together in one line!
1892 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1893 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1896 * @param {String} interval A valid date interval enum value
1897 * @param {Number} value The amount to add to the current date
1898 * @return {Date} The new Date instance
1900 Date.prototype.add = function(interval, value){
1901 var d = this.clone();
1902 if (!interval || value === 0) { return d; }
1903 switch(interval.toLowerCase()){
1905 d.setMilliseconds(this.getMilliseconds() + value);
1908 d.setSeconds(this.getSeconds() + value);
1911 d.setMinutes(this.getMinutes() + value);
1914 d.setHours(this.getHours() + value);
1917 d.setDate(this.getDate() + value);
1920 var day = this.getDate();
1922 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1925 d.setMonth(this.getMonth() + value);
1928 d.setFullYear(this.getFullYear() + value);
1934 * @class Roo.lib.Dom
1938 * Dom utils (from YIU afaik)
1944 * Get the view width
1945 * @param {Boolean} full True will get the full document, otherwise it's the view width
1946 * @return {Number} The width
1949 getViewWidth : function(full) {
1950 return full ? this.getDocumentWidth() : this.getViewportWidth();
1953 * Get the view height
1954 * @param {Boolean} full True will get the full document, otherwise it's the view height
1955 * @return {Number} The height
1957 getViewHeight : function(full) {
1958 return full ? this.getDocumentHeight() : this.getViewportHeight();
1961 * Get the Full Document height
1962 * @return {Number} The height
1964 getDocumentHeight: function() {
1965 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1966 return Math.max(scrollHeight, this.getViewportHeight());
1969 * Get the Full Document width
1970 * @return {Number} The width
1972 getDocumentWidth: function() {
1973 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1974 return Math.max(scrollWidth, this.getViewportWidth());
1977 * Get the Window Viewport height
1978 * @return {Number} The height
1980 getViewportHeight: function() {
1981 var height = self.innerHeight;
1982 var mode = document.compatMode;
1984 if ((mode || Roo.isIE) && !Roo.isOpera) {
1985 height = (mode == "CSS1Compat") ?
1986 document.documentElement.clientHeight :
1987 document.body.clientHeight;
1993 * Get the Window Viewport width
1994 * @return {Number} The width
1996 getViewportWidth: function() {
1997 var width = self.innerWidth;
1998 var mode = document.compatMode;
2000 if (mode || Roo.isIE) {
2001 width = (mode == "CSS1Compat") ?
2002 document.documentElement.clientWidth :
2003 document.body.clientWidth;
2008 isAncestor : function(p, c) {
2015 if (p.contains && !Roo.isSafari) {
2016 return p.contains(c);
2017 } else if (p.compareDocumentPosition) {
2018 return !!(p.compareDocumentPosition(c) & 16);
2020 var parent = c.parentNode;
2025 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
2028 parent = parent.parentNode;
2034 getRegion : function(el) {
2035 return Roo.lib.Region.getRegion(el);
2038 getY : function(el) {
2039 return this.getXY(el)[1];
2042 getX : function(el) {
2043 return this.getXY(el)[0];
2046 getXY : function(el) {
2047 var p, pe, b, scroll, bd = document.body;
2048 el = Roo.getDom(el);
2049 var fly = Roo.lib.AnimBase.fly;
2050 if (el.getBoundingClientRect) {
2051 b = el.getBoundingClientRect();
2052 scroll = fly(document).getScroll();
2053 return [b.left + scroll.left, b.top + scroll.top];
2059 var hasAbsolute = fly(el).getStyle("position") == "absolute";
2066 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
2073 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
2074 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2081 if (p != el && pe.getStyle('overflow') != 'visible') {
2089 if (Roo.isSafari && hasAbsolute) {
2094 if (Roo.isGecko && !hasAbsolute) {
2096 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2097 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2101 while (p && p != bd) {
2102 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2114 setXY : function(el, xy) {
2115 el = Roo.fly(el, '_setXY');
2117 var pts = el.translatePoints(xy);
2118 if (xy[0] !== false) {
2119 el.dom.style.left = pts.left + "px";
2121 if (xy[1] !== false) {
2122 el.dom.style.top = pts.top + "px";
2126 setX : function(el, x) {
2127 this.setXY(el, [x, false]);
2130 setY : function(el, y) {
2131 this.setXY(el, [false, y]);
2135 * Portions of this file are based on pieces of Yahoo User Interface Library
2136 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2137 * YUI licensed under the BSD License:
2138 * http://developer.yahoo.net/yui/license.txt
2139 * <script type="text/javascript">
2143 Roo.lib.Event = function() {
2144 var loadComplete = false;
2146 var unloadListeners = [];
2148 var onAvailStack = [];
2150 var lastError = null;
2163 startInterval: function() {
2164 if (!this._interval) {
2166 var callback = function() {
2167 self._tryPreloadAttach();
2169 this._interval = setInterval(callback, this.POLL_INTERVAL);
2174 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2175 onAvailStack.push({ id: p_id,
2178 override: p_override,
2179 checkReady: false });
2181 retryCount = this.POLL_RETRYS;
2182 this.startInterval();
2186 addListener: function(el, eventName, fn) {
2187 el = Roo.getDom(el);
2192 if ("unload" == eventName) {
2193 unloadListeners[unloadListeners.length] =
2194 [el, eventName, fn];
2198 var wrappedFn = function(e) {
2199 return fn(Roo.lib.Event.getEvent(e));
2202 var li = [el, eventName, fn, wrappedFn];
2204 var index = listeners.length;
2205 listeners[index] = li;
2207 this.doAdd(el, eventName, wrappedFn, false);
2213 removeListener: function(el, eventName, fn) {
2216 el = Roo.getDom(el);
2219 return this.purgeElement(el, false, eventName);
2223 if ("unload" == eventName) {
2225 for (i = 0,len = unloadListeners.length; i < len; i++) {
2226 var li = unloadListeners[i];
2229 li[1] == eventName &&
2231 unloadListeners.splice(i, 1);
2239 var cacheItem = null;
2242 var index = arguments[3];
2244 if ("undefined" == typeof index) {
2245 index = this._getCacheIndex(el, eventName, fn);
2249 cacheItem = listeners[index];
2252 if (!el || !cacheItem) {
2256 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2258 delete listeners[index][this.WFN];
2259 delete listeners[index][this.FN];
2260 listeners.splice(index, 1);
2267 getTarget: function(ev, resolveTextNode) {
2268 ev = ev.browserEvent || ev;
2269 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2270 var t = ev.target || ev.srcElement;
2271 return this.resolveTextNode(t);
2275 resolveTextNode: function(node) {
2276 if (Roo.isSafari && node && 3 == node.nodeType) {
2277 return node.parentNode;
2284 getPageX: function(ev) {
2285 ev = ev.browserEvent || ev;
2286 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2288 if (!x && 0 !== x) {
2289 x = ev.clientX || 0;
2292 x += this.getScroll()[1];
2300 getPageY: function(ev) {
2301 ev = ev.browserEvent || ev;
2302 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2304 if (!y && 0 !== y) {
2305 y = ev.clientY || 0;
2308 y += this.getScroll()[0];
2317 getXY: function(ev) {
2318 ev = ev.browserEvent || ev;
2319 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2320 return [this.getPageX(ev), this.getPageY(ev)];
2324 getRelatedTarget: function(ev) {
2325 ev = ev.browserEvent || ev;
2326 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2327 var t = ev.relatedTarget;
2329 if (ev.type == "mouseout") {
2331 } else if (ev.type == "mouseover") {
2336 return this.resolveTextNode(t);
2340 getTime: function(ev) {
2341 ev = ev.browserEvent || ev;
2342 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2344 var t = new Date().getTime();
2348 this.lastError = ex;
2357 stopEvent: function(ev) {
2358 this.stopPropagation(ev);
2359 this.preventDefault(ev);
2363 stopPropagation: function(ev) {
2364 ev = ev.browserEvent || ev;
2365 if (ev.stopPropagation) {
2366 ev.stopPropagation();
2368 ev.cancelBubble = true;
2373 preventDefault: function(ev) {
2374 ev = ev.browserEvent || ev;
2375 if(ev.preventDefault) {
2376 ev.preventDefault();
2378 ev.returnValue = false;
2383 getEvent: function(e) {
2384 var ev = e || window.event;
2386 var c = this.getEvent.caller;
2388 ev = c.arguments[0];
2389 if (ev && Event == ev.constructor) {
2399 getCharCode: function(ev) {
2400 ev = ev.browserEvent || ev;
2401 return ev.charCode || ev.keyCode || 0;
2405 _getCacheIndex: function(el, eventName, fn) {
2406 for (var i = 0,len = listeners.length; i < len; ++i) {
2407 var li = listeners[i];
2409 li[this.FN] == fn &&
2410 li[this.EL] == el &&
2411 li[this.TYPE] == eventName) {
2423 getEl: function(id) {
2424 return document.getElementById(id);
2428 clearCache: function() {
2432 _load: function(e) {
2433 loadComplete = true;
2434 var EU = Roo.lib.Event;
2438 EU.doRemove(window, "load", EU._load);
2443 _tryPreloadAttach: function() {
2452 var tryAgain = !loadComplete;
2454 tryAgain = (retryCount > 0);
2459 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2460 var item = onAvailStack[i];
2462 var el = this.getEl(item.id);
2465 if (!item.checkReady ||
2468 (document && document.body)) {
2471 if (item.override) {
2472 if (item.override === true) {
2475 scope = item.override;
2478 item.fn.call(scope, item.obj);
2479 onAvailStack[i] = null;
2482 notAvail.push(item);
2487 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2491 this.startInterval();
2493 clearInterval(this._interval);
2494 this._interval = null;
2497 this.locked = false;
2504 purgeElement: function(el, recurse, eventName) {
2505 var elListeners = this.getListeners(el, eventName);
2507 for (var i = 0,len = elListeners.length; i < len; ++i) {
2508 var l = elListeners[i];
2509 this.removeListener(el, l.type, l.fn);
2513 if (recurse && el && el.childNodes) {
2514 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2515 this.purgeElement(el.childNodes[i], recurse, eventName);
2521 getListeners: function(el, eventName) {
2522 var results = [], searchLists;
2524 searchLists = [listeners, unloadListeners];
2525 } else if (eventName == "unload") {
2526 searchLists = [unloadListeners];
2528 searchLists = [listeners];
2531 for (var j = 0; j < searchLists.length; ++j) {
2532 var searchList = searchLists[j];
2533 if (searchList && searchList.length > 0) {
2534 for (var i = 0,len = searchList.length; i < len; ++i) {
2535 var l = searchList[i];
2536 if (l && l[this.EL] === el &&
2537 (!eventName || eventName === l[this.TYPE])) {
2542 adjust: l[this.ADJ_SCOPE],
2550 return (results.length) ? results : null;
2554 _unload: function(e) {
2556 var EU = Roo.lib.Event, i, j, l, len, index;
2558 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2559 l = unloadListeners[i];
2562 if (l[EU.ADJ_SCOPE]) {
2563 if (l[EU.ADJ_SCOPE] === true) {
2566 scope = l[EU.ADJ_SCOPE];
2569 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2570 unloadListeners[i] = null;
2576 unloadListeners = null;
2578 if (listeners && listeners.length > 0) {
2579 j = listeners.length;
2582 l = listeners[index];
2584 EU.removeListener(l[EU.EL], l[EU.TYPE],
2594 EU.doRemove(window, "unload", EU._unload);
2599 getScroll: function() {
2600 var dd = document.documentElement, db = document.body;
2601 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2602 return [dd.scrollTop, dd.scrollLeft];
2604 return [db.scrollTop, db.scrollLeft];
2611 doAdd: function () {
2612 if (window.addEventListener) {
2613 return function(el, eventName, fn, capture) {
2614 el.addEventListener(eventName, fn, (capture));
2616 } else if (window.attachEvent) {
2617 return function(el, eventName, fn, capture) {
2618 el.attachEvent("on" + eventName, fn);
2627 doRemove: function() {
2628 if (window.removeEventListener) {
2629 return function (el, eventName, fn, capture) {
2630 el.removeEventListener(eventName, fn, (capture));
2632 } else if (window.detachEvent) {
2633 return function (el, eventName, fn) {
2634 el.detachEvent("on" + eventName, fn);
2646 var E = Roo.lib.Event;
2647 E.on = E.addListener;
2648 E.un = E.removeListener;
2650 if (document && document.body) {
2653 E.doAdd(window, "load", E._load);
2655 E.doAdd(window, "unload", E._unload);
2656 E._tryPreloadAttach();
2663 * @class Roo.lib.Ajax
2665 * provide a simple Ajax request utility functions
2667 * Portions of this file are based on pieces of Yahoo User Interface Library
2668 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2669 * YUI licensed under the BSD License:
2670 * http://developer.yahoo.net/yui/license.txt
2671 * <script type="text/javascript">
2679 request : function(method, uri, cb, data, options) {
2681 var hs = options.headers;
2684 if(hs.hasOwnProperty(h)){
2685 this.initHeader(h, hs[h], false);
2689 if(options.xmlData){
2690 this.initHeader('Content-Type', 'text/xml', false);
2692 data = options.xmlData;
2696 return this.asyncRequest(method, uri, cb, data);
2702 * @param {DomForm} form element
2703 * @return {String} urlencode form output.
2705 serializeForm : function(form) {
2706 if(typeof form == 'string') {
2707 form = (document.getElementById(form) || document.forms[form]);
2710 var el, name, val, disabled, data = '', hasSubmit = false;
2711 for (var i = 0; i < form.elements.length; i++) {
2712 el = form.elements[i];
2713 disabled = form.elements[i].disabled;
2714 name = form.elements[i].name;
2715 val = form.elements[i].value;
2717 if (!disabled && name){
2721 case 'select-multiple':
2722 for (var j = 0; j < el.options.length; j++) {
2723 if (el.options[j].selected) {
2725 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2728 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2736 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2749 if(hasSubmit == false) {
2750 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2755 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2760 data = data.substr(0, data.length - 1);
2768 useDefaultHeader:true,
2770 defaultPostHeader:'application/x-www-form-urlencoded',
2772 useDefaultXhrHeader:true,
2774 defaultXhrHeader:'XMLHttpRequest',
2776 hasDefaultHeaders:true,
2788 setProgId:function(id)
2790 this.activeX.unshift(id);
2793 setDefaultPostHeader:function(b)
2795 this.useDefaultHeader = b;
2798 setDefaultXhrHeader:function(b)
2800 this.useDefaultXhrHeader = b;
2803 setPollingInterval:function(i)
2805 if (typeof i == 'number' && isFinite(i)) {
2806 this.pollInterval = i;
2810 createXhrObject:function(transactionId)
2816 http = new XMLHttpRequest();
2818 obj = { conn:http, tId:transactionId };
2822 for (var i = 0; i < this.activeX.length; ++i) {
2826 http = new ActiveXObject(this.activeX[i]);
2828 obj = { conn:http, tId:transactionId };
2841 getConnectionObject:function()
2844 var tId = this.transactionId;
2848 o = this.createXhrObject(tId);
2850 this.transactionId++;
2861 asyncRequest:function(method, uri, callback, postData)
2863 var o = this.getConnectionObject();
2869 o.conn.open(method, uri, true);
2871 if (this.useDefaultXhrHeader) {
2872 if (!this.defaultHeaders['X-Requested-With']) {
2873 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2877 if(postData && this.useDefaultHeader){
2878 this.initHeader('Content-Type', this.defaultPostHeader);
2881 if (this.hasDefaultHeaders || this.hasHeaders) {
2885 this.handleReadyState(o, callback);
2886 o.conn.send(postData || null);
2892 handleReadyState:function(o, callback)
2896 if (callback && callback.timeout) {
2898 this.timeout[o.tId] = window.setTimeout(function() {
2899 oConn.abort(o, callback, true);
2900 }, callback.timeout);
2903 this.poll[o.tId] = window.setInterval(
2905 if (o.conn && o.conn.readyState == 4) {
2906 window.clearInterval(oConn.poll[o.tId]);
2907 delete oConn.poll[o.tId];
2909 if(callback && callback.timeout) {
2910 window.clearTimeout(oConn.timeout[o.tId]);
2911 delete oConn.timeout[o.tId];
2914 oConn.handleTransactionResponse(o, callback);
2917 , this.pollInterval);
2920 handleTransactionResponse:function(o, callback, isAbort)
2924 this.releaseObject(o);
2928 var httpStatus, responseObject;
2932 if (o.conn.status !== undefined && o.conn.status != 0) {
2933 httpStatus = o.conn.status;
2945 if (httpStatus >= 200 && httpStatus < 300) {
2946 responseObject = this.createResponseObject(o, callback.argument);
2947 if (callback.success) {
2948 if (!callback.scope) {
2949 callback.success(responseObject);
2954 callback.success.apply(callback.scope, [responseObject]);
2959 switch (httpStatus) {
2967 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2968 if (callback.failure) {
2969 if (!callback.scope) {
2970 callback.failure(responseObject);
2973 callback.failure.apply(callback.scope, [responseObject]);
2978 responseObject = this.createResponseObject(o, callback.argument);
2979 if (callback.failure) {
2980 if (!callback.scope) {
2981 callback.failure(responseObject);
2984 callback.failure.apply(callback.scope, [responseObject]);
2990 this.releaseObject(o);
2991 responseObject = null;
2994 createResponseObject:function(o, callbackArg)
3001 var headerStr = o.conn.getAllResponseHeaders();
3002 var header = headerStr.split('\n');
3003 for (var i = 0; i < header.length; i++) {
3004 var delimitPos = header[i].indexOf(':');
3005 if (delimitPos != -1) {
3006 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
3014 obj.status = o.conn.status;
3015 obj.statusText = o.conn.statusText;
3016 obj.getResponseHeader = headerObj;
3017 obj.getAllResponseHeaders = headerStr;
3018 obj.responseText = o.conn.responseText;
3019 obj.responseXML = o.conn.responseXML;
3021 if (typeof callbackArg !== undefined) {
3022 obj.argument = callbackArg;
3028 createExceptionObject:function(tId, callbackArg, isAbort)
3031 var COMM_ERROR = 'communication failure';
3032 var ABORT_CODE = -1;
3033 var ABORT_ERROR = 'transaction aborted';
3039 obj.status = ABORT_CODE;
3040 obj.statusText = ABORT_ERROR;
3043 obj.status = COMM_CODE;
3044 obj.statusText = COMM_ERROR;
3048 obj.argument = callbackArg;
3054 initHeader:function(label, value, isDefault)
3056 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
3058 if (headerObj[label] === undefined) {
3059 headerObj[label] = value;
3064 headerObj[label] = value + "," + headerObj[label];
3068 this.hasDefaultHeaders = true;
3071 this.hasHeaders = true;
3076 setHeader:function(o)
3078 if (this.hasDefaultHeaders) {
3079 for (var prop in this.defaultHeaders) {
3080 if (this.defaultHeaders.hasOwnProperty(prop)) {
3081 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3086 if (this.hasHeaders) {
3087 for (var prop in this.headers) {
3088 if (this.headers.hasOwnProperty(prop)) {
3089 o.conn.setRequestHeader(prop, this.headers[prop]);
3093 this.hasHeaders = false;
3097 resetDefaultHeaders:function() {
3098 delete this.defaultHeaders;
3099 this.defaultHeaders = {};
3100 this.hasDefaultHeaders = false;
3103 abort:function(o, callback, isTimeout)
3105 if(this.isCallInProgress(o)) {
3107 window.clearInterval(this.poll[o.tId]);
3108 delete this.poll[o.tId];
3110 delete this.timeout[o.tId];
3113 this.handleTransactionResponse(o, callback, true);
3123 isCallInProgress:function(o)
3126 return o.conn.readyState != 4 && o.conn.readyState != 0;
3135 releaseObject:function(o)
3144 'MSXML2.XMLHTTP.3.0',
3152 * Portions of this file are based on pieces of Yahoo User Interface Library
3153 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3154 * YUI licensed under the BSD License:
3155 * http://developer.yahoo.net/yui/license.txt
3156 * <script type="text/javascript">
3160 Roo.lib.Region = function(t, r, b, l) {
3170 Roo.lib.Region.prototype = {
3171 contains : function(region) {
3172 return ( region.left >= this.left &&
3173 region.right <= this.right &&
3174 region.top >= this.top &&
3175 region.bottom <= this.bottom );
3179 getArea : function() {
3180 return ( (this.bottom - this.top) * (this.right - this.left) );
3183 intersect : function(region) {
3184 var t = Math.max(this.top, region.top);
3185 var r = Math.min(this.right, region.right);
3186 var b = Math.min(this.bottom, region.bottom);
3187 var l = Math.max(this.left, region.left);
3189 if (b >= t && r >= l) {
3190 return new Roo.lib.Region(t, r, b, l);
3195 union : function(region) {
3196 var t = Math.min(this.top, region.top);
3197 var r = Math.max(this.right, region.right);
3198 var b = Math.max(this.bottom, region.bottom);
3199 var l = Math.min(this.left, region.left);
3201 return new Roo.lib.Region(t, r, b, l);
3204 adjust : function(t, l, b, r) {
3213 Roo.lib.Region.getRegion = function(el) {
3214 var p = Roo.lib.Dom.getXY(el);
3217 var r = p[0] + el.offsetWidth;
3218 var b = p[1] + el.offsetHeight;
3221 return new Roo.lib.Region(t, r, b, l);
3224 * Portions of this file are based on pieces of Yahoo User Interface Library
3225 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3226 * YUI licensed under the BSD License:
3227 * http://developer.yahoo.net/yui/license.txt
3228 * <script type="text/javascript">
3231 //@@dep Roo.lib.Region
3234 Roo.lib.Point = function(x, y) {
3235 if (x instanceof Array) {
3239 this.x = this.right = this.left = this[0] = x;
3240 this.y = this.top = this.bottom = this[1] = y;
3243 Roo.lib.Point.prototype = new Roo.lib.Region();
3245 * Portions of this file are based on pieces of Yahoo User Interface Library
3246 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3247 * YUI licensed under the BSD License:
3248 * http://developer.yahoo.net/yui/license.txt
3249 * <script type="text/javascript">
3256 scroll : function(el, args, duration, easing, cb, scope) {
3257 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3260 motion : function(el, args, duration, easing, cb, scope) {
3261 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3264 color : function(el, args, duration, easing, cb, scope) {
3265 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3268 run : function(el, args, duration, easing, cb, scope, type) {
3269 type = type || Roo.lib.AnimBase;
3270 if (typeof easing == "string") {
3271 easing = Roo.lib.Easing[easing];
3273 var anim = new type(el, args, duration, easing);
3274 anim.animateX(function() {
3275 Roo.callback(cb, scope);
3281 * Portions of this file are based on pieces of Yahoo User Interface Library
3282 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3283 * YUI licensed under the BSD License:
3284 * http://developer.yahoo.net/yui/license.txt
3285 * <script type="text/javascript">
3293 if (!libFlyweight) {
3294 libFlyweight = new Roo.Element.Flyweight();
3296 libFlyweight.dom = el;
3297 return libFlyweight;
3300 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3304 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3306 this.init(el, attributes, duration, method);
3310 Roo.lib.AnimBase.fly = fly;
3314 Roo.lib.AnimBase.prototype = {
3316 toString: function() {
3317 var el = this.getEl();
3318 var id = el.id || el.tagName;
3319 return ("Anim " + id);
3323 noNegatives: /width|height|opacity|padding/i,
3324 offsetAttribute: /^((width|height)|(top|left))$/,
3325 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3326 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3330 doMethod: function(attr, start, end) {
3331 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3335 setAttribute: function(attr, val, unit) {
3336 if (this.patterns.noNegatives.test(attr)) {
3337 val = (val > 0) ? val : 0;
3340 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3344 getAttribute: function(attr) {
3345 var el = this.getEl();
3346 var val = fly(el).getStyle(attr);
3348 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3349 return parseFloat(val);
3352 var a = this.patterns.offsetAttribute.exec(attr) || [];
3353 var pos = !!( a[3] );
3354 var box = !!( a[2] );
3357 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3358 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3367 getDefaultUnit: function(attr) {
3368 if (this.patterns.defaultUnit.test(attr)) {
3375 animateX : function(callback, scope) {
3376 var f = function() {
3377 this.onComplete.removeListener(f);
3378 if (typeof callback == "function") {
3379 callback.call(scope || this, this);
3382 this.onComplete.addListener(f, this);
3387 setRuntimeAttribute: function(attr) {
3390 var attributes = this.attributes;
3392 this.runtimeAttributes[attr] = {};
3394 var isset = function(prop) {
3395 return (typeof prop !== 'undefined');
3398 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3402 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3405 if (isset(attributes[attr]['to'])) {
3406 end = attributes[attr]['to'];
3407 } else if (isset(attributes[attr]['by'])) {
3408 if (start.constructor == Array) {
3410 for (var i = 0, len = start.length; i < len; ++i) {
3411 end[i] = start[i] + attributes[attr]['by'][i];
3414 end = start + attributes[attr]['by'];
3418 this.runtimeAttributes[attr].start = start;
3419 this.runtimeAttributes[attr].end = end;
3422 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3426 init: function(el, attributes, duration, method) {
3428 var isAnimated = false;
3431 var startTime = null;
3434 var actualFrames = 0;
3437 el = Roo.getDom(el);
3440 this.attributes = attributes || {};
3443 this.duration = duration || 1;
3446 this.method = method || Roo.lib.Easing.easeNone;
3449 this.useSeconds = true;
3452 this.currentFrame = 0;
3455 this.totalFrames = Roo.lib.AnimMgr.fps;
3458 this.getEl = function() {
3463 this.isAnimated = function() {
3468 this.getStartTime = function() {
3472 this.runtimeAttributes = {};
3475 this.animate = function() {
3476 if (this.isAnimated()) {
3480 this.currentFrame = 0;
3482 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3484 Roo.lib.AnimMgr.registerElement(this);
3488 this.stop = function(finish) {
3490 this.currentFrame = this.totalFrames;
3491 this._onTween.fire();
3493 Roo.lib.AnimMgr.stop(this);
3496 var onStart = function() {
3497 this.onStart.fire();
3499 this.runtimeAttributes = {};
3500 for (var attr in this.attributes) {
3501 this.setRuntimeAttribute(attr);
3506 startTime = new Date();
3510 var onTween = function() {
3512 duration: new Date() - this.getStartTime(),
3513 currentFrame: this.currentFrame
3516 data.toString = function() {
3518 'duration: ' + data.duration +
3519 ', currentFrame: ' + data.currentFrame
3523 this.onTween.fire(data);
3525 var runtimeAttributes = this.runtimeAttributes;
3527 for (var attr in runtimeAttributes) {
3528 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3534 var onComplete = function() {
3535 var actual_duration = (new Date() - startTime) / 1000 ;
3538 duration: actual_duration,
3539 frames: actualFrames,
3540 fps: actualFrames / actual_duration
3543 data.toString = function() {
3545 'duration: ' + data.duration +
3546 ', frames: ' + data.frames +
3547 ', fps: ' + data.fps
3553 this.onComplete.fire(data);
3557 this._onStart = new Roo.util.Event(this);
3558 this.onStart = new Roo.util.Event(this);
3559 this.onTween = new Roo.util.Event(this);
3560 this._onTween = new Roo.util.Event(this);
3561 this.onComplete = new Roo.util.Event(this);
3562 this._onComplete = new Roo.util.Event(this);
3563 this._onStart.addListener(onStart);
3564 this._onTween.addListener(onTween);
3565 this._onComplete.addListener(onComplete);
3570 * Portions of this file are based on pieces of Yahoo User Interface Library
3571 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3572 * YUI licensed under the BSD License:
3573 * http://developer.yahoo.net/yui/license.txt
3574 * <script type="text/javascript">
3578 Roo.lib.AnimMgr = new function() {
3595 this.registerElement = function(tween) {
3596 queue[queue.length] = tween;
3598 tween._onStart.fire();
3603 this.unRegister = function(tween, index) {
3604 tween._onComplete.fire();
3605 index = index || getIndex(tween);
3607 queue.splice(index, 1);
3611 if (tweenCount <= 0) {
3617 this.start = function() {
3618 if (thread === null) {
3619 thread = setInterval(this.run, this.delay);
3624 this.stop = function(tween) {
3626 clearInterval(thread);
3628 for (var i = 0, len = queue.length; i < len; ++i) {
3629 if (queue[0].isAnimated()) {
3630 this.unRegister(queue[0], 0);
3639 this.unRegister(tween);
3644 this.run = function() {
3645 for (var i = 0, len = queue.length; i < len; ++i) {
3646 var tween = queue[i];
3647 if (!tween || !tween.isAnimated()) {
3651 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3653 tween.currentFrame += 1;
3655 if (tween.useSeconds) {
3656 correctFrame(tween);
3658 tween._onTween.fire();
3661 Roo.lib.AnimMgr.stop(tween, i);
3666 var getIndex = function(anim) {
3667 for (var i = 0, len = queue.length; i < len; ++i) {
3668 if (queue[i] == anim) {
3676 var correctFrame = function(tween) {
3677 var frames = tween.totalFrames;
3678 var frame = tween.currentFrame;
3679 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3680 var elapsed = (new Date() - tween.getStartTime());
3683 if (elapsed < tween.duration * 1000) {
3684 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3686 tweak = frames - (frame + 1);
3688 if (tweak > 0 && isFinite(tweak)) {
3689 if (tween.currentFrame + tweak >= frames) {
3690 tweak = frames - (frame + 1);
3693 tween.currentFrame += tweak;
3699 * Portions of this file are based on pieces of Yahoo User Interface Library
3700 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3701 * YUI licensed under the BSD License:
3702 * http://developer.yahoo.net/yui/license.txt
3703 * <script type="text/javascript">
3706 Roo.lib.Bezier = new function() {
3708 this.getPosition = function(points, t) {
3709 var n = points.length;
3712 for (var i = 0; i < n; ++i) {
3713 tmp[i] = [points[i][0], points[i][1]];
3716 for (var j = 1; j < n; ++j) {
3717 for (i = 0; i < n - j; ++i) {
3718 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3719 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3723 return [ tmp[0][0], tmp[0][1] ];
3729 * @class Roo.lib.Color
3731 * An abstract Color implementation. Concrete Color implementations should use
3732 * an instance of this function as their prototype, and implement the getRGB and
3733 * getHSL functions. getRGB should return an object representing the RGB
3734 * components of this Color, with the red, green, and blue components in the
3735 * range [0,255] and the alpha component in the range [0,100]. getHSL should
3736 * return an object representing the HSL components of this Color, with the hue
3737 * component in the range [0,360), the saturation and lightness components in
3738 * the range [0,100], and the alpha component in the range [0,1].
3743 * Functions for Color handling and processing.
3745 * http://www.safalra.com/web-design/javascript/Color-handling-and-processing/
3747 * The author of this program, Safalra (Stephen Morley), irrevocably releases all
3748 * rights to this program, with the intention of it becoming part of the public
3749 * domain. Because this program is released into the public domain, it comes with
3750 * no warranty either expressed or implied, to the extent permitted by law.
3752 * For more free and public domain JavaScript code by the same author, visit:
3753 * http://www.safalra.com/web-design/javascript/
3756 Roo.lib.Color = function() { }
3759 Roo.apply(Roo.lib.Color.prototype, {
3767 * @return {Object} an object representing the RGBA components of this Color. The red,
3768 * green, and blue components are converted to integers in the range [0,255].
3769 * The alpha is a value in the range [0,1].
3771 getIntegerRGB : function(){
3773 // get the RGB components of this Color
3774 var rgb = this.getRGB();
3776 // return the integer components
3778 'r' : Math.round(rgb.r),
3779 'g' : Math.round(rgb.g),
3780 'b' : Math.round(rgb.b),
3788 * @return {Object} an object representing the RGBA components of this Color. The red,
3789 * green, and blue components are converted to numbers in the range [0,100].
3790 * The alpha is a value in the range [0,1].
3792 getPercentageRGB : function(){
3794 // get the RGB components of this Color
3795 var rgb = this.getRGB();
3797 // return the percentage components
3799 'r' : 100 * rgb.r / 255,
3800 'g' : 100 * rgb.g / 255,
3801 'b' : 100 * rgb.b / 255,
3808 * getCSSHexadecimalRGB
3809 * @return {String} a string representing this Color as a CSS hexadecimal RGB Color
3810 * value - that is, a string of the form #RRGGBB where each of RR, GG, and BB
3811 * are two-digit hexadecimal numbers.
3813 getCSSHexadecimalRGB : function()
3816 // get the integer RGB components
3817 var rgb = this.getIntegerRGB();
3819 // determine the hexadecimal equivalents
3820 var r16 = rgb.r.toString(16);
3821 var g16 = rgb.g.toString(16);
3822 var b16 = rgb.b.toString(16);
3824 // return the CSS RGB Color value
3826 + (r16.length == 2 ? r16 : '0' + r16)
3827 + (g16.length == 2 ? g16 : '0' + g16)
3828 + (b16.length == 2 ? b16 : '0' + b16);
3834 * @return {String} a string representing this Color as a CSS integer RGB Color
3835 * value - that is, a string of the form rgb(r,g,b) where each of r, g, and b
3836 * are integers in the range [0,255].
3838 getCSSIntegerRGB : function(){
3840 // get the integer RGB components
3841 var rgb = this.getIntegerRGB();
3843 // return the CSS RGB Color value
3844 return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')';
3850 * @return {String} Returns a string representing this Color as a CSS integer RGBA Color
3851 * value - that is, a string of the form rgba(r,g,b,a) where each of r, g, and
3852 * b are integers in the range [0,255] and a is in the range [0,1].
3854 getCSSIntegerRGBA : function(){
3856 // get the integer RGB components
3857 var rgb = this.getIntegerRGB();
3859 // return the CSS integer RGBA Color value
3860 return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + rgb.a + ')';
3865 * getCSSPercentageRGB
3866 * @return {String} a string representing this Color as a CSS percentage RGB Color
3867 * value - that is, a string of the form rgb(r%,g%,b%) where each of r, g, and
3868 * b are in the range [0,100].
3870 getCSSPercentageRGB : function(){
3872 // get the percentage RGB components
3873 var rgb = this.getPercentageRGB();
3875 // return the CSS RGB Color value
3876 return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%)';
3881 * getCSSPercentageRGBA
3882 * @return {String} a string representing this Color as a CSS percentage RGBA Color
3883 * value - that is, a string of the form rgba(r%,g%,b%,a) where each of r, g,
3884 * and b are in the range [0,100] and a is in the range [0,1].
3886 getCSSPercentageRGBA : function(){
3888 // get the percentage RGB components
3889 var rgb = this.getPercentageRGB();
3891 // return the CSS percentage RGBA Color value
3892 return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%,' + rgb.a + ')';
3898 * @return {String} a string representing this Color as a CSS HSL Color value - that
3899 * is, a string of the form hsl(h,s%,l%) where h is in the range [0,100] and
3900 * s and l are in the range [0,100].
3902 getCSSHSL : function(){
3904 // get the HSL components
3905 var hsl = this.getHSL();
3907 // return the CSS HSL Color value
3908 return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%)';
3914 * @return {String} a string representing this Color as a CSS HSLA Color value - that
3915 * is, a string of the form hsla(h,s%,l%,a) where h is in the range [0,100],
3916 * s and l are in the range [0,100], and a is in the range [0,1].
3918 getCSSHSLA : function(){
3920 // get the HSL components
3921 var hsl = this.getHSL();
3923 // return the CSS HSL Color value
3924 return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%,' + hsl.a + ')';
3929 * Sets the Color of the specified node to this Color. This functions sets
3930 * the CSS 'color' property for the node. The parameter is:
3932 * @param {DomElement} node - the node whose Color should be set
3934 setNodeColor : function(node){
3936 // set the Color of the node
3937 node.style.color = this.getCSSHexadecimalRGB();
3942 * Sets the background Color of the specified node to this Color. This
3943 * functions sets the CSS 'background-color' property for the node. The
3946 * @param {DomElement} node - the node whose background Color should be set
3948 setNodeBackgroundColor : function(node){
3950 // set the background Color of the node
3951 node.style.backgroundColor = this.getCSSHexadecimalRGB();
3954 // convert between formats..
3957 var r = this.getIntegerRGB();
3958 return new Roo.lib.RGBColor(r.r,r.g,r.b,r.a);
3963 var hsl = this.getHSL();
3964 // return the CSS HSL Color value
3965 return new Roo.lib.HSLColor(hsl.h, hsl.s, hsl.l , hsl.a );
3971 var rgb = this.toRGB();
3972 var hsv = rgb.getHSV();
3973 // return the CSS HSL Color value
3974 return new Roo.lib.HSVColor(hsv.h, hsv.s, hsv.v , hsv.a );
3978 // modify v = 0 ... 1 (eg. 0.5)
3979 saturate : function(v)
3981 var rgb = this.toRGB();
3982 var hsv = rgb.getHSV();
3983 return new Roo.lib.HSVColor(hsv.h, hsv.s * v, hsv.v , hsv.a );
3991 * @return {Object} the RGB and alpha components of this Color as an object with r,
3992 * g, b, and a properties. r, g, and b are in the range [0,255] and a is in
3997 // return the RGB components
4009 * @return {Object} the HSV and alpha components of this Color as an object with h,
4010 * s, v, and a properties. h is in the range [0,360), s and v are in the range
4011 * [0,100], and a is in the range [0,1].
4016 // calculate the HSV components if necessary
4017 if (this.hsv == null) {
4018 this.calculateHSV();
4021 // return the HSV components
4033 * @return {Object} the HSL and alpha components of this Color as an object with h,
4034 * s, l, and a properties. h is in the range [0,360), s and l are in the range
4035 * [0,100], and a is in the range [0,1].
4037 getHSL : function(){
4040 // calculate the HSV components if necessary
4041 if (this.hsl == null) { this.calculateHSL(); }
4043 // return the HSL components
4058 * @class Roo.lib.RGBColor
4059 * @extends Roo.lib.Color
4060 * Creates a Color specified in the RGB Color space, with an optional alpha
4061 * component. The parameters are:
4065 * @param {Number} r - the red component, clipped to the range [0,255]
4066 * @param {Number} g - the green component, clipped to the range [0,255]
4067 * @param {Number} b - the blue component, clipped to the range [0,255]
4068 * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4069 * optional and defaults to 1
4071 Roo.lib.RGBColor = function (r, g, b, a){
4073 // store the alpha component after clipping it if necessary
4074 this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4076 // store the RGB components after clipping them if necessary
4079 'r' : Math.max(0, Math.min(255, r)),
4080 'g' : Math.max(0, Math.min(255, g)),
4081 'b' : Math.max(0, Math.min(255, b))
4084 // initialise the HSV and HSL components to null
4088 * //private returns the HSV or HSL hue component of this RGBColor. The hue is in the
4089 * range [0,360). The parameters are:
4091 * maximum - the maximum of the RGB component values
4092 * range - the range of the RGB component values
4097 // this does an 'exteds'
4098 Roo.extend(Roo.lib.RGBColor, Roo.lib.Color, {
4101 getHue : function(maximum, range)
4105 // check whether the range is zero
4108 // set the hue to zero (any hue is acceptable as the Color is grey)
4113 // determine which of the components has the highest value and set the hue
4116 // red has the highest value
4118 var hue = (rgb.g - rgb.b) / range * 60;
4119 if (hue < 0) { hue += 360; }
4122 // green has the highest value
4124 var hue = (rgb.b - rgb.r) / range * 60 + 120;
4127 // blue has the highest value
4129 var hue = (rgb.r - rgb.g) / range * 60 + 240;
4141 /* //private Calculates and stores the HSV components of this RGBColor so that they can
4142 * be returned be the getHSV function.
4144 calculateHSV : function(){
4146 // get the maximum and range of the RGB component values
4147 var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4148 var range = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4150 // store the HSV components
4153 'h' : this.getHue(maximum, range),
4154 's' : (maximum == 0 ? 0 : 100 * range / maximum),
4155 'v' : maximum / 2.55
4160 /* //private Calculates and stores the HSL components of this RGBColor so that they can
4161 * be returned be the getHSL function.
4163 calculateHSL : function(){
4165 // get the maximum and range of the RGB component values
4166 var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4167 var range = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4169 // determine the lightness in the range [0,1]
4170 var l = maximum / 255 - range / 510;
4172 // store the HSL components
4175 'h' : this.getHue(maximum, range),
4176 's' : (range == 0 ? 0 : range / 2.55 / (l < 0.5 ? l * 2 : 2 - l * 2)),
4185 * @class Roo.lib.HSVColor
4186 * @extends Roo.lib.Color
4187 * Creates a Color specified in the HSV Color space, with an optional alpha
4188 * component. The parameters are:
4191 * @param {Number} h - the hue component, wrapped to the range [0,360)
4192 * @param {Number} s - the saturation component, clipped to the range [0,100]
4193 * @param {Number} v - the value component, clipped to the range [0,100]
4194 * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4195 * optional and defaults to 1
4197 Roo.lib.HSVColor = function (h, s, v, a){
4199 // store the alpha component after clipping it if necessary
4200 this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4202 // store the HSV components after clipping or wrapping them if necessary
4205 'h' : (h % 360 + 360) % 360,
4206 's' : Math.max(0, Math.min(100, s)),
4207 'v' : Math.max(0, Math.min(100, v))
4210 // initialise the RGB and HSL components to null
4215 Roo.extend(Roo.lib.HSVColor, Roo.lib.Color, {
4216 /* Calculates and stores the RGB components of this HSVColor so that they can
4217 * be returned be the getRGB function.
4219 calculateRGB: function ()
4222 // check whether the saturation is zero
4225 // set the Color to the appropriate shade of grey
4232 // set some temporary values
4233 var f = hsv.h / 60 - Math.floor(hsv.h / 60);
4234 var p = hsv.v * (1 - hsv.s / 100);
4235 var q = hsv.v * (1 - hsv.s / 100 * f);
4236 var t = hsv.v * (1 - hsv.s / 100 * (1 - f));
4238 // set the RGB Color components to their temporary values
4239 switch (Math.floor(hsv.h / 60)){
4240 case 0: var r = hsv.v; var g = t; var b = p; break;
4241 case 1: var r = q; var g = hsv.v; var b = p; break;
4242 case 2: var r = p; var g = hsv.v; var b = t; break;
4243 case 3: var r = p; var g = q; var b = hsv.v; break;
4244 case 4: var r = t; var g = p; var b = hsv.v; break;
4245 case 5: var r = hsv.v; var g = p; var b = q; break;
4250 // store the RGB components
4260 /* Calculates and stores the HSL components of this HSVColor so that they can
4261 * be returned be the getHSL function.
4263 calculateHSL : function (){
4266 // determine the lightness in the range [0,100]
4267 var l = (2 - hsv.s / 100) * hsv.v / 2;
4269 // store the HSL components
4273 's' : hsv.s * hsv.v / (l < 50 ? l * 2 : 200 - l * 2),
4277 // correct a division-by-zero error
4278 if (isNaN(hsl.s)) { hsl.s = 0; }
4287 * @class Roo.lib.HSLColor
4288 * @extends Roo.lib.Color
4291 * Creates a Color specified in the HSL Color space, with an optional alpha
4292 * component. The parameters are:
4294 * @param {Number} h - the hue component, wrapped to the range [0,360)
4295 * @param {Number} s - the saturation component, clipped to the range [0,100]
4296 * @param {Number} l - the lightness component, clipped to the range [0,100]
4297 * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4298 * optional and defaults to 1
4301 Roo.lib.HSLColor = function(h, s, l, a){
4303 // store the alpha component after clipping it if necessary
4304 this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4306 // store the HSL components after clipping or wrapping them if necessary
4309 'h' : (h % 360 + 360) % 360,
4310 's' : Math.max(0, Math.min(100, s)),
4311 'l' : Math.max(0, Math.min(100, l))
4314 // initialise the RGB and HSV components to null
4317 Roo.extend(Roo.lib.HSLColor, Roo.lib.Color, {
4319 /* Calculates and stores the RGB components of this HSLColor so that they can
4320 * be returned be the getRGB function.
4322 calculateRGB: function (){
4324 // check whether the saturation is zero
4325 if (this.hsl.s == 0){
4327 // store the RGB components representing the appropriate shade of grey
4330 'r' : this.hsl.l * 2.55,
4331 'g' : this.hsl.l * 2.55,
4332 'b' : this.hsl.l * 2.55
4337 // set some temporary values
4338 var p = this.hsl.l < 50
4339 ? this.hsl.l * (1 + hsl.s / 100)
4340 : this.hsl.l + hsl.s - hsl.l * hsl.s / 100;
4341 var q = 2 * hsl.l - p;
4343 // initialise the RGB components
4346 'r' : (h + 120) / 60 % 6,
4348 'b' : (h + 240) / 60 % 6
4351 // loop over the RGB components
4352 for (var key in this.rgb){
4354 // ensure that the property is not inherited from the root object
4355 if (this.rgb.hasOwnProperty(key)){
4357 // set the component to its value in the range [0,100]
4358 if (this.rgb[key] < 1){
4359 this.rgb[key] = q + (p - q) * this.rgb[key];
4360 }else if (this.rgb[key] < 3){
4362 }else if (this.rgb[key] < 4){
4363 this.rgb[key] = q + (p - q) * (4 - this.rgb[key]);
4368 // set the component to its value in the range [0,255]
4369 this.rgb[key] *= 2.55;
4379 /* Calculates and stores the HSV components of this HSLColor so that they can
4380 * be returned be the getHSL function.
4382 calculateHSV : function(){
4384 // set a temporary value
4385 var t = this.hsl.s * (this.hsl.l < 50 ? this.hsl.l : 100 - this.hsl.l) / 100;
4387 // store the HSV components
4391 's' : 200 * t / (this.hsl.l + t),
4392 'v' : t + this.hsl.l
4395 // correct a division-by-zero error
4396 if (isNaN(this.hsv.s)) { this.hsv.s = 0; }
4403 * Portions of this file are based on pieces of Yahoo User Interface Library
4404 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4405 * YUI licensed under the BSD License:
4406 * http://developer.yahoo.net/yui/license.txt
4407 * <script type="text/javascript">
4412 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
4413 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
4416 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
4418 var fly = Roo.lib.AnimBase.fly;
4420 var superclass = Y.ColorAnim.superclass;
4421 var proto = Y.ColorAnim.prototype;
4423 proto.toString = function() {
4424 var el = this.getEl();
4425 var id = el.id || el.tagName;
4426 return ("ColorAnim " + id);
4429 proto.patterns.color = /color$/i;
4430 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
4431 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
4432 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
4433 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
4436 proto.parseColor = function(s) {
4437 if (s.length == 3) {
4441 var c = this.patterns.hex.exec(s);
4442 if (c && c.length == 4) {
4443 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
4446 c = this.patterns.rgb.exec(s);
4447 if (c && c.length == 4) {
4448 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
4451 c = this.patterns.hex3.exec(s);
4452 if (c && c.length == 4) {
4453 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
4458 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
4459 proto.getAttribute = function(attr) {
4460 var el = this.getEl();
4461 if (this.patterns.color.test(attr)) {
4462 var val = fly(el).getStyle(attr);
4464 if (this.patterns.transparent.test(val)) {
4465 var parent = el.parentNode;
4466 val = fly(parent).getStyle(attr);
4468 while (parent && this.patterns.transparent.test(val)) {
4469 parent = parent.parentNode;
4470 val = fly(parent).getStyle(attr);
4471 if (parent.tagName.toUpperCase() == 'HTML') {
4477 val = superclass.getAttribute.call(this, attr);
4482 proto.getAttribute = function(attr) {
4483 var el = this.getEl();
4484 if (this.patterns.color.test(attr)) {
4485 var val = fly(el).getStyle(attr);
4487 if (this.patterns.transparent.test(val)) {
4488 var parent = el.parentNode;
4489 val = fly(parent).getStyle(attr);
4491 while (parent && this.patterns.transparent.test(val)) {
4492 parent = parent.parentNode;
4493 val = fly(parent).getStyle(attr);
4494 if (parent.tagName.toUpperCase() == 'HTML') {
4500 val = superclass.getAttribute.call(this, attr);
4506 proto.doMethod = function(attr, start, end) {
4509 if (this.patterns.color.test(attr)) {
4511 for (var i = 0, len = start.length; i < len; ++i) {
4512 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
4515 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
4518 val = superclass.doMethod.call(this, attr, start, end);
4524 proto.setRuntimeAttribute = function(attr) {
4525 superclass.setRuntimeAttribute.call(this, attr);
4527 if (this.patterns.color.test(attr)) {
4528 var attributes = this.attributes;
4529 var start = this.parseColor(this.runtimeAttributes[attr].start);
4530 var end = this.parseColor(this.runtimeAttributes[attr].end);
4532 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
4533 end = this.parseColor(attributes[attr].by);
4535 for (var i = 0, len = start.length; i < len; ++i) {
4536 end[i] = start[i] + end[i];
4540 this.runtimeAttributes[attr].start = start;
4541 this.runtimeAttributes[attr].end = end;
4547 * Portions of this file are based on pieces of Yahoo User Interface Library
4548 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4549 * YUI licensed under the BSD License:
4550 * http://developer.yahoo.net/yui/license.txt
4551 * <script type="text/javascript">
4557 easeNone: function (t, b, c, d) {
4558 return c * t / d + b;
4562 easeIn: function (t, b, c, d) {
4563 return c * (t /= d) * t + b;
4567 easeOut: function (t, b, c, d) {
4568 return -c * (t /= d) * (t - 2) + b;
4572 easeBoth: function (t, b, c, d) {
4573 if ((t /= d / 2) < 1) {
4574 return c / 2 * t * t + b;
4577 return -c / 2 * ((--t) * (t - 2) - 1) + b;
4581 easeInStrong: function (t, b, c, d) {
4582 return c * (t /= d) * t * t * t + b;
4586 easeOutStrong: function (t, b, c, d) {
4587 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
4591 easeBothStrong: function (t, b, c, d) {
4592 if ((t /= d / 2) < 1) {
4593 return c / 2 * t * t * t * t + b;
4596 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
4601 elasticIn: function (t, b, c, d, a, p) {
4605 if ((t /= d) == 1) {
4612 if (!a || a < Math.abs(c)) {
4617 var s = p / (2 * Math.PI) * Math.asin(c / a);
4620 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4624 elasticOut: function (t, b, c, d, a, p) {
4628 if ((t /= d) == 1) {
4635 if (!a || a < Math.abs(c)) {
4640 var s = p / (2 * Math.PI) * Math.asin(c / a);
4643 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
4647 elasticBoth: function (t, b, c, d, a, p) {
4652 if ((t /= d / 2) == 2) {
4660 if (!a || a < Math.abs(c)) {
4665 var s = p / (2 * Math.PI) * Math.asin(c / a);
4669 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
4670 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4672 return a * Math.pow(2, -10 * (t -= 1)) *
4673 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
4678 backIn: function (t, b, c, d, s) {
4679 if (typeof s == 'undefined') {
4682 return c * (t /= d) * t * ((s + 1) * t - s) + b;
4686 backOut: function (t, b, c, d, s) {
4687 if (typeof s == 'undefined') {
4690 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
4694 backBoth: function (t, b, c, d, s) {
4695 if (typeof s == 'undefined') {
4699 if ((t /= d / 2 ) < 1) {
4700 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
4702 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
4706 bounceIn: function (t, b, c, d) {
4707 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
4711 bounceOut: function (t, b, c, d) {
4712 if ((t /= d) < (1 / 2.75)) {
4713 return c * (7.5625 * t * t) + b;
4714 } else if (t < (2 / 2.75)) {
4715 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
4716 } else if (t < (2.5 / 2.75)) {
4717 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
4719 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
4723 bounceBoth: function (t, b, c, d) {
4725 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
4727 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
4730 * Portions of this file are based on pieces of Yahoo User Interface Library
4731 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4732 * YUI licensed under the BSD License:
4733 * http://developer.yahoo.net/yui/license.txt
4734 * <script type="text/javascript">
4738 Roo.lib.Motion = function(el, attributes, duration, method) {
4740 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
4744 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
4748 var superclass = Y.Motion.superclass;
4749 var proto = Y.Motion.prototype;
4751 proto.toString = function() {
4752 var el = this.getEl();
4753 var id = el.id || el.tagName;
4754 return ("Motion " + id);
4757 proto.patterns.points = /^points$/i;
4759 proto.setAttribute = function(attr, val, unit) {
4760 if (this.patterns.points.test(attr)) {
4761 unit = unit || 'px';
4762 superclass.setAttribute.call(this, 'left', val[0], unit);
4763 superclass.setAttribute.call(this, 'top', val[1], unit);
4765 superclass.setAttribute.call(this, attr, val, unit);
4769 proto.getAttribute = function(attr) {
4770 if (this.patterns.points.test(attr)) {
4772 superclass.getAttribute.call(this, 'left'),
4773 superclass.getAttribute.call(this, 'top')
4776 val = superclass.getAttribute.call(this, attr);
4782 proto.doMethod = function(attr, start, end) {
4785 if (this.patterns.points.test(attr)) {
4786 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4787 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4789 val = superclass.doMethod.call(this, attr, start, end);
4794 proto.setRuntimeAttribute = function(attr) {
4795 if (this.patterns.points.test(attr)) {
4796 var el = this.getEl();
4797 var attributes = this.attributes;
4799 var control = attributes['points']['control'] || [];
4803 if (control.length > 0 && !(control[0] instanceof Array)) {
4804 control = [control];
4807 for (i = 0,len = control.length; i < len; ++i) {
4808 tmp[i] = control[i];
4813 Roo.fly(el).position();
4815 if (isset(attributes['points']['from'])) {
4816 Roo.lib.Dom.setXY(el, attributes['points']['from']);
4819 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4822 start = this.getAttribute('points');
4825 if (isset(attributes['points']['to'])) {
4826 end = translateValues.call(this, attributes['points']['to'], start);
4828 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4829 for (i = 0,len = control.length; i < len; ++i) {
4830 control[i] = translateValues.call(this, control[i], start);
4834 } else if (isset(attributes['points']['by'])) {
4835 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4837 for (i = 0,len = control.length; i < len; ++i) {
4838 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4842 this.runtimeAttributes[attr] = [start];
4844 if (control.length > 0) {
4845 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4848 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4851 superclass.setRuntimeAttribute.call(this, attr);
4855 var translateValues = function(val, start) {
4856 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4857 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4862 var isset = function(prop) {
4863 return (typeof prop !== 'undefined');
4867 * Portions of this file are based on pieces of Yahoo User Interface Library
4868 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4869 * YUI licensed under the BSD License:
4870 * http://developer.yahoo.net/yui/license.txt
4871 * <script type="text/javascript">
4875 Roo.lib.Scroll = function(el, attributes, duration, method) {
4877 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4881 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4885 var superclass = Y.Scroll.superclass;
4886 var proto = Y.Scroll.prototype;
4888 proto.toString = function() {
4889 var el = this.getEl();
4890 var id = el.id || el.tagName;
4891 return ("Scroll " + id);
4894 proto.doMethod = function(attr, start, end) {
4897 if (attr == 'scroll') {
4899 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4900 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4904 val = superclass.doMethod.call(this, attr, start, end);
4909 proto.getAttribute = function(attr) {
4911 var el = this.getEl();
4913 if (attr == 'scroll') {
4914 val = [ el.scrollLeft, el.scrollTop ];
4916 val = superclass.getAttribute.call(this, attr);
4922 proto.setAttribute = function(attr, val, unit) {
4923 var el = this.getEl();
4925 if (attr == 'scroll') {
4926 el.scrollLeft = val[0];
4927 el.scrollTop = val[1];
4929 superclass.setAttribute.call(this, attr, val, unit);
4934 * Originally based of this code... - refactored for Roo...
4935 * https://github.com/aaalsaleh/undo-manager
4938 * @author Abdulrahman Alsaleh
4939 * @copyright 2015 Abdulrahman Alsaleh
4940 * @license MIT License (c)
4942 * Hackily modifyed by alan@roojs.com
4947 * TOTALLY UNTESTED...
4949 * Documentation to be done....
4954 * @class Roo.lib.UndoManager
4955 * An undo manager implementation in JavaScript. It follows the W3C UndoManager and DOM Transaction
4956 * Draft and the undocumented and disabled Mozilla Firefox's UndoManager implementation.
4962 editor.undoManager = new Roo.lib.UndoManager(1000, editor);
4966 * For more information see this blog post with examples:
4967 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4968 - Create Elements using DOM, HTML fragments and Templates</a>.
4970 * @param {Number} limit how far back to go ... use 1000?
4971 * @param {Object} scope usually use document..
4974 Roo.lib.UndoManager = function (limit, undoScopeHost)
4978 this.scope = undoScopeHost;
4979 this.fireEvent = typeof CustomEvent != 'undefined' && undoScopeHost && undoScopeHost.dispatchEvent;
4980 if (this.fireEvent) {
4987 Roo.lib.UndoManager.prototype = {
4998 * To push and execute a transaction, the method undoManager.transact
4999 * must be called by passing a transaction object as the first argument, and a merge
5000 * flag as the second argument. A transaction object has the following properties:
5004 undoManager.transact({
5006 execute: function() { ... },
5007 undo: function() { ... },
5008 // redo same as execute
5009 redo: function() { this.execute(); }
5012 // merge transaction
5013 undoManager.transact({
5015 execute: function() { ... }, // this will be run...
5016 undo: function() { ... }, // what to do when undo is run.
5017 // redo same as execute
5018 redo: function() { this.execute(); }
5023 * @param {Object} transaction The transaction to add to the stack.
5024 * @return {String} The HTML fragment
5028 transact : function (transaction, merge)
5030 if (arguments.length < 2) {
5031 throw new TypeError('Not enough arguments to UndoManager.transact.');
5034 transaction.execute();
5036 this.stack.splice(0, this.position);
5037 if (merge && this.length) {
5038 this.stack[0].push(transaction);
5040 this.stack.unshift([transaction]);
5045 if (this.limit && this.stack.length > this.limit) {
5046 this.length = this.stack.length = this.limit;
5048 this.length = this.stack.length;
5051 if (this.fireEvent) {
5052 this.scope.dispatchEvent(
5053 new CustomEvent('DOMTransaction', {
5055 transactions: this.stack[0].slice()
5063 //Roo.log("transaction: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
5070 //Roo.log("undo: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
5072 if (this.position < this.length) {
5073 for (var i = this.stack[this.position].length - 1; i >= 0; i--) {
5074 this.stack[this.position][i].undo();
5078 if (this.fireEvent) {
5079 this.scope.dispatchEvent(
5080 new CustomEvent('undo', {
5082 transactions: this.stack[this.position - 1].slice()
5094 if (this.position > 0) {
5095 for (var i = 0, n = this.stack[this.position - 1].length; i < n; i++) {
5096 this.stack[this.position - 1][i].redo();
5100 if (this.fireEvent) {
5101 this.scope.dispatchEvent(
5102 new CustomEvent('redo', {
5104 transactions: this.stack[this.position].slice()
5114 item : function (index)
5116 if (index >= 0 && index < this.length) {
5117 return this.stack[index].slice();
5122 clearUndo : function () {
5123 this.stack.length = this.length = this.position;
5126 clearRedo : function () {
5127 this.stack.splice(0, this.position);
5129 this.length = this.stack.length;
5132 * Reset the undo - probaly done on load to clear all history.
5139 this.current_html = this.scope.innerHTML;
5140 if (this.timer !== false) {
5141 clearTimeout(this.timer);
5153 // this will handle the undo/redo on the element.?
5154 bindEvents : function()
5156 var el = this.scope;
5157 el.undoManager = this;
5160 this.scope.addEventListener('keydown', function(e) {
5161 if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
5163 el.undoManager.redo(); // Ctrl/Command + Shift + Z
5165 el.undoManager.undo(); // Ctrl/Command + Z
5172 this.scope.addEventListener('keyup', function(e) {
5173 if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
5182 el.addEventListener('input', function(e) {
5183 if(el.innerHTML == t.current_html) {
5186 // only record events every second.
5187 if (t.timer !== false) {
5188 clearTimeout(t.timer);
5191 t.timer = setTimeout(function() { t.merge = false; }, 1000);
5193 t.addEvent(t.merge);
5194 t.merge = true; // ignore changes happening every second..
5198 * Manually add an event.
5199 * Normall called without arguements - and it will just get added to the stack.
5203 addEvent : function(merge)
5205 //Roo.log("undomanager +" + (merge ? 'Y':'n'));
5206 // not sure if this should clear the timer
5207 merge = typeof(merge) == 'undefined' ? false : merge;
5209 this.scope.undoManager.transact({
5211 oldHTML: this.current_html,
5212 newHTML: this.scope.innerHTML,
5213 // nothing to execute (content already changed when input is fired)
5214 execute: function() { },
5216 this.scope.innerHTML = this.current_html = this.oldHTML;
5219 this.scope.innerHTML = this.current_html = this.newHTML;
5221 }, false); //merge);
5225 this.current_html = this.scope.innerHTML;
5235 * @class Roo.lib.Range
5237 * This is a toolkit, normally used to copy features into a Dom Range element
5238 * Roo.lib.Range.wrap(x);
5243 Roo.lib.Range = function() { };
5246 * Wrap a Dom Range object, to give it new features...
5248 * @param {Range} the range to wrap
5250 Roo.lib.Range.wrap = function(r) {
5251 return Roo.apply(r, Roo.lib.Range.prototype);
5254 * find a parent node eg. LI / OL
5255 * @param {string|Array} node name or array of nodenames
5256 * @return {DomElement|false}
5258 Roo.apply(Roo.lib.Range.prototype,
5261 closest : function(str)
5263 if (typeof(str) != 'string') {
5264 // assume it's a array.
5265 for(var i = 0;i < str.length;i++) {
5266 var r = this.closest(str[i]);
5274 str = str.toLowerCase();
5275 var n = this.commonAncestorContainer; // might not be a node
5276 while (n.nodeType != 1) {
5280 if (n.nodeName.toLowerCase() == str ) {
5283 if (n.nodeName.toLowerCase() == 'body') {
5287 return n.closest(str) || false;
5290 cloneRange : function()
5292 return Roo.lib.Range.wrap(Range.prototype.cloneRange.call(this));
5295 * @class Roo.lib.Selection
5297 * This is a toolkit, normally used to copy features into a Dom Selection element
5298 * Roo.lib.Selection.wrap(x);
5303 Roo.lib.Selection = function() { };
5306 * Wrap a Dom Range object, to give it new features...
5308 * @param {Range} the range to wrap
5310 Roo.lib.Selection.wrap = function(r, doc) {
5311 Roo.apply(r, Roo.lib.Selection.prototype);
5312 r.ownerDocument = doc; // usefull so we dont have to keep referening to it.
5316 * find a parent node eg. LI / OL
5317 * @param {string|Array} node name or array of nodenames
5318 * @return {DomElement|false}
5320 Roo.apply(Roo.lib.Selection.prototype,
5323 * the owner document
5325 ownerDocument : false,
5327 getRangeAt : function(n)
5329 return Roo.lib.Range.wrap(Selection.prototype.getRangeAt.call(this,n));
5333 * insert node at selection
5334 * @param {DomElement|string} node
5335 * @param {string} cursor (after|in|none) where to place the cursor after inserting.
5337 insertNode: function(node, cursor)
5339 if (typeof(node) == 'string') {
5340 node = this.ownerDocument.createElement(node);
5341 if (cursor == 'in') {
5342 node.innerHTML = ' ';
5346 var range = this.getRangeAt(0);
5348 if (this.type != 'Caret') {
5349 range.deleteContents();
5351 var sn = node.childNodes[0]; // select the contents.
5355 range.insertNode(node);
5356 if (cursor == 'after') {
5357 node.insertAdjacentHTML('afterend', ' ');
5358 sn = node.nextSibling;
5361 if (cursor == 'none') {
5365 this.cursorText(sn);
5368 cursorText : function(n)
5371 //var range = this.getRangeAt(0);
5372 range = Roo.lib.Range.wrap(new Range());
5373 //range.selectNode(n);
5375 var ix = Array.from(n.parentNode.childNodes).indexOf(n);
5376 range.setStart(n.parentNode,ix);
5377 range.setEnd(n.parentNode,ix+1);
5378 //range.collapse(false);
5380 this.removeAllRanges();
5381 this.addRange(range);
5383 Roo.log([n, range, this,this.baseOffset,this.extentOffset, this.type]);
5385 cursorAfter : function(n)
5387 if (!n.nextSibling || n.nextSibling.nodeValue != ' ') {
5388 n.insertAdjacentHTML('afterend', ' ');
5390 this.cursorText (n.nextSibling);
5396 * Ext JS Library 1.1.1
5397 * Copyright(c) 2006-2007, Ext JS, LLC.
5399 * Originally Released Under LGPL - original licence link has changed is not relivant.
5402 * <script type="text/javascript">
5406 // nasty IE9 hack - what a pile of crap that is..
5408 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
5409 Range.prototype.createContextualFragment = function (html) {
5410 var doc = window.document;
5411 var container = doc.createElement("div");
5412 container.innerHTML = html;
5413 var frag = doc.createDocumentFragment(), n;
5414 while ((n = container.firstChild)) {
5415 frag.appendChild(n);
5422 * @class Roo.DomHelper
5423 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
5424 * 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>.
5427 Roo.DomHelper = function(){
5428 var tempTableEl = null;
5429 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
5430 var tableRe = /^table|tbody|tr|td$/i;
5432 // build as innerHTML where available
5434 var createHtml = function(o){
5435 if(typeof o == 'string'){
5444 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
5445 if(attr == "style"){
5447 if(typeof s == "function"){
5450 if(typeof s == "string"){
5451 b += ' style="' + s + '"';
5452 }else if(typeof s == "object"){
5455 if(typeof s[key] != "function"){
5456 b += key + ":" + s[key] + ";";
5463 b += ' class="' + o["cls"] + '"';
5464 }else if(attr == "htmlFor"){
5465 b += ' for="' + o["htmlFor"] + '"';
5467 b += " " + attr + '="' + o[attr] + '"';
5471 if(emptyTags.test(o.tag)){
5475 var cn = o.children || o.cn;
5477 //http://bugs.kde.org/show_bug.cgi?id=71506
5478 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5479 for(var i = 0, len = cn.length; i < len; i++) {
5480 b += createHtml(cn[i], b);
5483 b += createHtml(cn, b);
5489 b += "</" + o.tag + ">";
5496 var createDom = function(o, parentNode){
5498 // defininition craeted..
5500 if (o.ns && o.ns != 'html') {
5502 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
5503 xmlns[o.ns] = o.xmlns;
5506 if (typeof(xmlns[o.ns]) == 'undefined') {
5507 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
5513 if (typeof(o) == 'string') {
5514 return parentNode.appendChild(document.createTextNode(o));
5516 o.tag = o.tag || 'div';
5517 if (o.ns && Roo.isIE) {
5519 o.tag = o.ns + ':' + o.tag;
5522 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
5523 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
5526 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
5527 attr == "style" || typeof o[attr] == "function") { continue; }
5529 if(attr=="cls" && Roo.isIE){
5530 el.className = o["cls"];
5532 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
5538 Roo.DomHelper.applyStyles(el, o.style);
5539 var cn = o.children || o.cn;
5541 //http://bugs.kde.org/show_bug.cgi?id=71506
5542 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5543 for(var i = 0, len = cn.length; i < len; i++) {
5544 createDom(cn[i], el);
5551 el.innerHTML = o.html;
5554 parentNode.appendChild(el);
5559 var ieTable = function(depth, s, h, e){
5560 tempTableEl.innerHTML = [s, h, e].join('');
5561 var i = -1, el = tempTableEl;
5562 while(++i < depth && el.firstChild){
5568 // kill repeat to save bytes
5572 tbe = '</tbody>'+te,
5578 * Nasty code for IE's broken table implementation
5580 var insertIntoTable = function(tag, where, el, html){
5582 tempTableEl = document.createElement('div');
5587 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
5590 if(where == 'beforebegin'){
5594 before = el.nextSibling;
5597 node = ieTable(4, trs, html, tre);
5599 else if(tag == 'tr'){
5600 if(where == 'beforebegin'){
5603 node = ieTable(3, tbs, html, tbe);
5604 } else if(where == 'afterend'){
5605 before = el.nextSibling;
5607 node = ieTable(3, tbs, html, tbe);
5608 } else{ // INTO a TR
5609 if(where == 'afterbegin'){
5610 before = el.firstChild;
5612 node = ieTable(4, trs, html, tre);
5614 } else if(tag == 'tbody'){
5615 if(where == 'beforebegin'){
5618 node = ieTable(2, ts, html, te);
5619 } else if(where == 'afterend'){
5620 before = el.nextSibling;
5622 node = ieTable(2, ts, html, te);
5624 if(where == 'afterbegin'){
5625 before = el.firstChild;
5627 node = ieTable(3, tbs, html, tbe);
5630 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
5633 if(where == 'afterbegin'){
5634 before = el.firstChild;
5636 node = ieTable(2, ts, html, te);
5638 el.insertBefore(node, before);
5642 // this is a bit like the react update code...
5645 var updateNode = function(from, to)
5647 // should we handle non-standard elements?
5648 Roo.log(["UpdateNode" , from, to]);
5649 if (from.nodeType != to.nodeType) {
5650 Roo.log(["ReplaceChild - mismatch notType" , to, from ]);
5651 from.parentNode.replaceChild(to, from);
5654 if (from.nodeType == 3) {
5655 // assume it's text?!
5656 if (from.data == to.data) {
5659 from.data = to.data;
5662 if (!from.parentNode) {
5663 // not sure why this is happening?
5666 // assume 'to' doesnt have '1/3 nodetypes!
5667 // not sure why, by from, parent node might not exist?
5668 if (from.nodeType !=1 || from.tagName != to.tagName) {
5669 Roo.log(["ReplaceChild" , from, to ]);
5671 from.parentNode.replaceChild(to, from);
5674 // compare attributes
5675 var ar = Array.from(from.attributes);
5676 for(var i = 0; i< ar.length;i++) {
5677 if (to.hasAttribute(ar[i].name)) {
5680 if (ar[i].name == 'id') { // always keep ids?
5683 //if (ar[i].name == 'style') {
5684 // throw "style removed?";
5686 Roo.log("removeAttribute" + ar[i].name);
5687 from.removeAttribute(ar[i].name);
5690 for(var i = 0; i< ar.length;i++) {
5691 if (from.getAttribute(ar[i].name) == to.getAttribute(ar[i].name)) {
5692 Roo.log("skipAttribute " + ar[i].name + '=' + to.getAttribute(ar[i].name));
5695 Roo.log("updateAttribute " + ar[i].name + '=>' + to.getAttribute(ar[i].name));
5696 from.setAttribute(ar[i].name, to.getAttribute(ar[i].name));
5699 var far = Array.from(from.childNodes);
5700 var tar = Array.from(to.childNodes);
5701 // if the lengths are different.. then it's probably a editable content change, rather than
5702 // a change of the block definition..
5704 // this did notwork , as our rebuilt nodes did not include ID's so did not match at all.
5705 /*if (from.innerHTML == to.innerHTML) {
5708 if (far.length != tar.length) {
5709 from.innerHTML = to.innerHTML;
5714 for(var i = 0; i < Math.max(tar.length, far.length); i++) {
5715 if (i >= far.length) {
5716 from.appendChild(tar[i]);
5717 Roo.log(["add", tar[i]]);
5719 } else if ( i >= tar.length) {
5720 from.removeChild(far[i]);
5721 Roo.log(["remove", far[i]]);
5724 updateNode(far[i], tar[i]);
5736 /** True to force the use of DOM instead of html fragments @type Boolean */
5740 * Returns the markup for the passed Element(s) config
5741 * @param {Object} o The Dom object spec (and children)
5744 markup : function(o){
5745 return createHtml(o);
5749 * Applies a style specification to an element
5750 * @param {String/HTMLElement} el The element to apply styles to
5751 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
5752 * a function which returns such a specification.
5754 applyStyles : function(el, styles){
5757 if(typeof styles == "string"){
5758 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
5760 while ((matches = re.exec(styles)) != null){
5761 el.setStyle(matches[1], matches[2]);
5763 }else if (typeof styles == "object"){
5764 for (var style in styles){
5765 el.setStyle(style, styles[style]);
5767 }else if (typeof styles == "function"){
5768 Roo.DomHelper.applyStyles(el, styles.call());
5774 * Inserts an HTML fragment into the Dom
5775 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
5776 * @param {HTMLElement} el The context element
5777 * @param {String} html The HTML fragmenet
5778 * @return {HTMLElement} The new node
5780 insertHtml : function(where, el, html){
5781 where = where.toLowerCase();
5782 if(el.insertAdjacentHTML){
5783 if(tableRe.test(el.tagName)){
5785 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
5791 el.insertAdjacentHTML('BeforeBegin', html);
5792 return el.previousSibling;
5794 el.insertAdjacentHTML('AfterBegin', html);
5795 return el.firstChild;
5797 el.insertAdjacentHTML('BeforeEnd', html);
5798 return el.lastChild;
5800 el.insertAdjacentHTML('AfterEnd', html);
5801 return el.nextSibling;
5803 throw 'Illegal insertion point -> "' + where + '"';
5805 var range = el.ownerDocument.createRange();
5809 range.setStartBefore(el);
5810 frag = range.createContextualFragment(html);
5811 el.parentNode.insertBefore(frag, el);
5812 return el.previousSibling;
5815 range.setStartBefore(el.firstChild);
5816 frag = range.createContextualFragment(html);
5817 el.insertBefore(frag, el.firstChild);
5818 return el.firstChild;
5820 el.innerHTML = html;
5821 return el.firstChild;
5825 range.setStartAfter(el.lastChild);
5826 frag = range.createContextualFragment(html);
5827 el.appendChild(frag);
5828 return el.lastChild;
5830 el.innerHTML = html;
5831 return el.lastChild;
5834 range.setStartAfter(el);
5835 frag = range.createContextualFragment(html);
5836 el.parentNode.insertBefore(frag, el.nextSibling);
5837 return el.nextSibling;
5839 throw 'Illegal insertion point -> "' + where + '"';
5843 * Creates new Dom element(s) and inserts them before el
5844 * @param {String/HTMLElement/Element} el The context element
5845 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5846 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5847 * @return {HTMLElement/Roo.Element} The new node
5849 insertBefore : function(el, o, returnElement){
5850 return this.doInsert(el, o, returnElement, "beforeBegin");
5854 * Creates new Dom element(s) and inserts them after el
5855 * @param {String/HTMLElement/Element} el The context element
5856 * @param {Object} o The Dom object spec (and children)
5857 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5858 * @return {HTMLElement/Roo.Element} The new node
5860 insertAfter : function(el, o, returnElement){
5861 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
5865 * Creates new Dom element(s) and inserts them as the first child of el
5866 * @param {String/HTMLElement/Element} el The context element
5867 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5868 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5869 * @return {HTMLElement/Roo.Element} The new node
5871 insertFirst : function(el, o, returnElement){
5872 return this.doInsert(el, o, returnElement, "afterBegin");
5876 doInsert : function(el, o, returnElement, pos, sibling){
5877 el = Roo.getDom(el);
5879 if(this.useDom || o.ns){
5880 newNode = createDom(o, null);
5881 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
5883 var html = createHtml(o);
5884 newNode = this.insertHtml(pos, el, html);
5886 return returnElement ? Roo.get(newNode, true) : newNode;
5890 * Creates new Dom element(s) and appends them to el
5891 * @param {String/HTMLElement/Element} el The context element
5892 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5893 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5894 * @return {HTMLElement/Roo.Element} The new node
5896 append : function(el, o, returnElement){
5897 el = Roo.getDom(el);
5899 if(this.useDom || o.ns){
5900 newNode = createDom(o, null);
5901 el.appendChild(newNode);
5903 var html = createHtml(o);
5904 newNode = this.insertHtml("beforeEnd", el, html);
5906 return returnElement ? Roo.get(newNode, true) : newNode;
5910 * Creates new Dom element(s) and overwrites the contents of el with them
5911 * @param {String/HTMLElement/Element} el The context element
5912 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5913 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5914 * @return {HTMLElement/Roo.Element} The new node
5916 overwrite : function(el, o, returnElement)
5918 el = Roo.getDom(el);
5921 while (el.childNodes.length) {
5922 el.removeChild(el.firstChild);
5926 el.innerHTML = createHtml(o);
5929 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5933 * Creates a new Roo.DomHelper.Template from the Dom object spec
5934 * @param {Object} o The Dom object spec (and children)
5935 * @return {Roo.DomHelper.Template} The new template
5937 createTemplate : function(o){
5938 var html = createHtml(o);
5939 return new Roo.Template(html);
5942 * Updates the first element with the spec from the o (replacing if necessary)
5943 * This iterates through the children, and updates attributes / children etc..
5944 * @param {String/HTMLElement/Element} el The context element
5945 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5948 update : function(el, o)
5950 updateNode(Roo.getDom(el), createDom(o));
5959 * Ext JS Library 1.1.1
5960 * Copyright(c) 2006-2007, Ext JS, LLC.
5962 * Originally Released Under LGPL - original licence link has changed is not relivant.
5965 * <script type="text/javascript">
5969 * @class Roo.Template
5970 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
5971 * For a list of available format functions, see {@link Roo.util.Format}.<br />
5974 var t = new Roo.Template({
5975 html : '<div name="{id}">' +
5976 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
5978 myformat: function (value, allValues) {
5979 return 'XX' + value;
5982 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
5984 * For more information see this blog post with examples:
5985 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
5986 - Create Elements using DOM, HTML fragments and Templates</a>.
5988 * @param {Object} cfg - Configuration object.
5990 Roo.Template = function(cfg){
5992 if(cfg instanceof Array){
5994 }else if(arguments.length > 1){
5995 cfg = Array.prototype.join.call(arguments, "");
5999 if (typeof(cfg) == 'object') {
6010 Roo.Template.prototype = {
6013 * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
6019 * @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..
6020 * it should be fixed so that template is observable...
6024 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
6032 * Returns an HTML fragment of this template with the specified values applied.
6033 * @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'})
6034 * @return {String} The HTML fragment
6039 applyTemplate : function(values){
6040 //Roo.log(["applyTemplate", values]);
6044 return this.compiled(values);
6046 var useF = this.disableFormats !== true;
6047 var fm = Roo.util.Format, tpl = this;
6048 var fn = function(m, name, format, args){
6050 if(format.substr(0, 5) == "this."){
6051 return tpl.call(format.substr(5), values[name], values);
6054 // quoted values are required for strings in compiled templates,
6055 // but for non compiled we need to strip them
6056 // quoted reversed for jsmin
6057 var re = /^\s*['"](.*)["']\s*$/;
6058 args = args.split(',');
6059 for(var i = 0, len = args.length; i < len; i++){
6060 args[i] = args[i].replace(re, "$1");
6062 args = [values[name]].concat(args);
6064 args = [values[name]];
6066 return fm[format].apply(fm, args);
6069 return values[name] !== undefined ? values[name] : "";
6072 return this.html.replace(this.re, fn);
6090 this.loading = true;
6091 this.compiled = false;
6093 var cx = new Roo.data.Connection();
6097 success : function (response) {
6101 _t.set(response.responseText,true);
6107 failure : function(response) {
6108 Roo.log("Template failed to load from " + _t.url);
6115 * Sets the HTML used as the template and optionally compiles it.
6116 * @param {String} html
6117 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
6118 * @return {Roo.Template} this
6120 set : function(html, compile){
6122 this.compiled = false;
6130 * True to disable format functions (defaults to false)
6133 disableFormats : false,
6136 * The regular expression used to match template variables
6140 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
6143 * Compiles the template into an internal function, eliminating the RegEx overhead.
6144 * @return {Roo.Template} this
6146 compile : function(){
6147 var fm = Roo.util.Format;
6148 var useF = this.disableFormats !== true;
6149 var sep = Roo.isGecko ? "+" : ",";
6150 var fn = function(m, name, format, args){
6152 args = args ? ',' + args : "";
6153 if(format.substr(0, 5) != "this."){
6154 format = "fm." + format + '(';
6156 format = 'this.call("'+ format.substr(5) + '", ';
6160 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
6162 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
6165 // branched to use + in gecko and [].join() in others
6167 body = "this.compiled = function(values){ return '" +
6168 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
6171 body = ["this.compiled = function(values){ return ['"];
6172 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
6173 body.push("'].join('');};");
6174 body = body.join('');
6184 // private function used to call members
6185 call : function(fnName, value, allValues){
6186 return this[fnName](value, allValues);
6190 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
6191 * @param {String/HTMLElement/Roo.Element} el The context element
6192 * @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'})
6193 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6194 * @return {HTMLElement/Roo.Element} The new node or Element
6196 insertFirst: function(el, values, returnElement){
6197 return this.doInsert('afterBegin', el, values, returnElement);
6201 * Applies the supplied values to the template and inserts the new node(s) before el.
6202 * @param {String/HTMLElement/Roo.Element} el The context element
6203 * @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'})
6204 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6205 * @return {HTMLElement/Roo.Element} The new node or Element
6207 insertBefore: function(el, values, returnElement){
6208 return this.doInsert('beforeBegin', el, values, returnElement);
6212 * Applies the supplied values to the template and inserts the new node(s) after el.
6213 * @param {String/HTMLElement/Roo.Element} el The context element
6214 * @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'})
6215 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6216 * @return {HTMLElement/Roo.Element} The new node or Element
6218 insertAfter : function(el, values, returnElement){
6219 return this.doInsert('afterEnd', el, values, returnElement);
6223 * Applies the supplied values to the template and appends the new node(s) to el.
6224 * @param {String/HTMLElement/Roo.Element} el The context element
6225 * @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'})
6226 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6227 * @return {HTMLElement/Roo.Element} The new node or Element
6229 append : function(el, values, returnElement){
6230 return this.doInsert('beforeEnd', el, values, returnElement);
6233 doInsert : function(where, el, values, returnEl){
6234 el = Roo.getDom(el);
6235 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
6236 return returnEl ? Roo.get(newNode, true) : newNode;
6240 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
6241 * @param {String/HTMLElement/Roo.Element} el The context element
6242 * @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'})
6243 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6244 * @return {HTMLElement/Roo.Element} The new node or Element
6246 overwrite : function(el, values, returnElement){
6247 el = Roo.getDom(el);
6248 el.innerHTML = this.applyTemplate(values);
6249 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
6253 * Alias for {@link #applyTemplate}
6256 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
6259 Roo.DomHelper.Template = Roo.Template;
6262 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
6263 * @param {String/HTMLElement} el A DOM element or its id
6264 * @returns {Roo.Template} The created template
6267 Roo.Template.from = function(el){
6268 el = Roo.getDom(el);
6269 return new Roo.Template(el.value || el.innerHTML);
6272 * Ext JS Library 1.1.1
6273 * Copyright(c) 2006-2007, Ext JS, LLC.
6275 * Originally Released Under LGPL - original licence link has changed is not relivant.
6278 * <script type="text/javascript">
6283 * This is code is also distributed under MIT license for use
6284 * with jQuery and prototype JavaScript libraries.
6287 * @class Roo.DomQuery
6288 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).
6290 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>
6293 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.
6295 <h4>Element Selectors:</h4>
6297 <li> <b>*</b> any element</li>
6298 <li> <b>E</b> an element with the tag E</li>
6299 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
6300 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
6301 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
6302 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
6304 <h4>Attribute Selectors:</h4>
6305 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
6307 <li> <b>E[foo]</b> has an attribute "foo"</li>
6308 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
6309 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
6310 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
6311 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
6312 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
6313 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
6315 <h4>Pseudo Classes:</h4>
6317 <li> <b>E:first-child</b> E is the first child of its parent</li>
6318 <li> <b>E:last-child</b> E is the last child of its parent</li>
6319 <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>
6320 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
6321 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
6322 <li> <b>E:only-child</b> E is the only child of its parent</li>
6323 <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>
6324 <li> <b>E:first</b> the first E in the resultset</li>
6325 <li> <b>E:last</b> the last E in the resultset</li>
6326 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
6327 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
6328 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
6329 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
6330 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
6331 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
6332 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
6333 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
6334 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
6336 <h4>CSS Value Selectors:</h4>
6338 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
6339 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
6340 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
6341 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
6342 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
6343 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
6347 Roo.DomQuery = function(){
6348 var cache = {}, simpleCache = {}, valueCache = {};
6349 var nonSpace = /\S/;
6350 var trimRe = /^\s+|\s+$/g;
6351 var tplRe = /\{(\d+)\}/g;
6352 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
6353 var tagTokenRe = /^(#)?([\w-\*]+)/;
6354 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
6356 function child(p, index){
6358 var n = p.firstChild;
6360 if(n.nodeType == 1){
6371 while((n = n.nextSibling) && n.nodeType != 1);
6376 while((n = n.previousSibling) && n.nodeType != 1);
6380 function children(d){
6381 var n = d.firstChild, ni = -1;
6383 var nx = n.nextSibling;
6384 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
6394 function byClassName(c, a, v){
6398 var r = [], ri = -1, cn;
6399 for(var i = 0, ci; ci = c[i]; i++){
6403 ( (ci instanceof SVGElement) ? ci.className.baseVal : ci.className)
6404 +' ').indexOf(v) != -1){
6411 function attrValue(n, attr){
6412 if(!n.tagName && typeof n.length != "undefined"){
6421 if(attr == "class" || attr == "className"){
6422 return (n instanceof SVGElement) ? n.className.baseVal : n.className;
6424 return n.getAttribute(attr) || n[attr];
6428 function getNodes(ns, mode, tagName){
6429 var result = [], ri = -1, cs;
6433 tagName = tagName || "*";
6434 if(typeof ns.getElementsByTagName != "undefined"){
6438 for(var i = 0, ni; ni = ns[i]; i++){
6439 cs = ni.getElementsByTagName(tagName);
6440 for(var j = 0, ci; ci = cs[j]; j++){
6444 }else if(mode == "/" || mode == ">"){
6445 var utag = tagName.toUpperCase();
6446 for(var i = 0, ni, cn; ni = ns[i]; i++){
6447 cn = ni.children || ni.childNodes;
6448 for(var j = 0, cj; cj = cn[j]; j++){
6449 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
6454 }else if(mode == "+"){
6455 var utag = tagName.toUpperCase();
6456 for(var i = 0, n; n = ns[i]; i++){
6457 while((n = n.nextSibling) && n.nodeType != 1);
6458 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
6462 }else if(mode == "~"){
6463 for(var i = 0, n; n = ns[i]; i++){
6464 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
6473 function concat(a, b){
6477 for(var i = 0, l = b.length; i < l; i++){
6483 function byTag(cs, tagName){
6484 if(cs.tagName || cs == document){
6490 var r = [], ri = -1;
6491 tagName = tagName.toLowerCase();
6492 for(var i = 0, ci; ci = cs[i]; i++){
6493 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
6500 function byId(cs, attr, id){
6501 if(cs.tagName || cs == document){
6507 var r = [], ri = -1;
6508 for(var i = 0,ci; ci = cs[i]; i++){
6509 if(ci && ci.id == id){
6517 function byAttribute(cs, attr, value, op, custom){
6518 var r = [], ri = -1, st = custom=="{";
6519 var f = Roo.DomQuery.operators[op];
6520 for(var i = 0, ci; ci = cs[i]; i++){
6523 a = Roo.DomQuery.getStyle(ci, attr);
6525 else if(attr == "class" || attr == "className"){
6526 a = (ci instanceof SVGElement) ? ci.className.baseVal : ci.className;
6527 }else if(attr == "for"){
6529 }else if(attr == "href"){
6530 a = ci.getAttribute("href", 2);
6532 a = ci.getAttribute(attr);
6534 if((f && f(a, value)) || (!f && a)){
6541 function byPseudo(cs, name, value){
6542 return Roo.DomQuery.pseudos[name](cs, value);
6545 // This is for IE MSXML which does not support expandos.
6546 // IE runs the same speed using setAttribute, however FF slows way down
6547 // and Safari completely fails so they need to continue to use expandos.
6548 var isIE = window.ActiveXObject ? true : false;
6550 // this eval is stop the compressor from
6551 // renaming the variable to something shorter
6553 /** eval:var:batch */
6558 function nodupIEXml(cs){
6560 cs[0].setAttribute("_nodup", d);
6562 for(var i = 1, len = cs.length; i < len; i++){
6564 if(!c.getAttribute("_nodup") != d){
6565 c.setAttribute("_nodup", d);
6569 for(var i = 0, len = cs.length; i < len; i++){
6570 cs[i].removeAttribute("_nodup");
6579 var len = cs.length, c, i, r = cs, cj, ri = -1;
6580 if(!len || typeof cs.nodeType != "undefined" || len == 1){
6583 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
6584 return nodupIEXml(cs);
6588 for(i = 1; c = cs[i]; i++){
6593 for(var j = 0; j < i; j++){
6596 for(j = i+1; cj = cs[j]; j++){
6608 function quickDiffIEXml(c1, c2){
6610 for(var i = 0, len = c1.length; i < len; i++){
6611 c1[i].setAttribute("_qdiff", d);
6614 for(var i = 0, len = c2.length; i < len; i++){
6615 if(c2[i].getAttribute("_qdiff") != d){
6616 r[r.length] = c2[i];
6619 for(var i = 0, len = c1.length; i < len; i++){
6620 c1[i].removeAttribute("_qdiff");
6625 function quickDiff(c1, c2){
6626 var len1 = c1.length;
6630 if(isIE && c1[0].selectSingleNode){
6631 return quickDiffIEXml(c1, c2);
6634 for(var i = 0; i < len1; i++){
6638 for(var i = 0, len = c2.length; i < len; i++){
6639 if(c2[i]._qdiff != d){
6640 r[r.length] = c2[i];
6646 function quickId(ns, mode, root, id){
6648 var d = root.ownerDocument || root;
6649 return d.getElementById(id);
6651 ns = getNodes(ns, mode, "*");
6652 return byId(ns, null, id);
6656 getStyle : function(el, name){
6657 return Roo.fly(el).getStyle(name);
6660 * Compiles a selector/xpath query into a reusable function. The returned function
6661 * takes one parameter "root" (optional), which is the context node from where the query should start.
6662 * @param {String} selector The selector/xpath query
6663 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
6664 * @return {Function}
6666 compile : function(path, type){
6667 type = type || "select";
6669 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
6670 var q = path, mode, lq;
6671 var tk = Roo.DomQuery.matchers;
6672 var tklen = tk.length;
6675 // accept leading mode switch
6676 var lmode = q.match(modeRe);
6677 if(lmode && lmode[1]){
6678 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
6679 q = q.replace(lmode[1], "");
6681 // strip leading slashes
6682 while(path.substr(0, 1)=="/"){
6683 path = path.substr(1);
6686 while(q && lq != q){
6688 var tm = q.match(tagTokenRe);
6689 if(type == "select"){
6692 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
6694 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
6696 q = q.replace(tm[0], "");
6697 }else if(q.substr(0, 1) != '@'){
6698 fn[fn.length] = 'n = getNodes(n, mode, "*");';
6703 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
6705 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
6707 q = q.replace(tm[0], "");
6710 while(!(mm = q.match(modeRe))){
6711 var matched = false;
6712 for(var j = 0; j < tklen; j++){
6714 var m = q.match(t.re);
6716 fn[fn.length] = t.select.replace(tplRe, function(x, i){
6719 q = q.replace(m[0], "");
6724 // prevent infinite loop on bad selector
6726 throw 'Error parsing selector, parsing failed at "' + q + '"';
6730 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
6731 q = q.replace(mm[1], "");
6734 fn[fn.length] = "return nodup(n);\n}";
6737 * list of variables that need from compression as they are used by eval.
6747 * eval:var:byClassName
6749 * eval:var:byAttribute
6750 * eval:var:attrValue
6758 * Selects a group of elements.
6759 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
6760 * @param {Node} root (optional) The start of the query (defaults to document).
6763 select : function(path, root, type){
6764 if(!root || root == document){
6767 if(typeof root == "string"){
6768 root = document.getElementById(root);
6770 var paths = path.split(",");
6772 for(var i = 0, len = paths.length; i < len; i++){
6773 var p = paths[i].replace(trimRe, "");
6775 cache[p] = Roo.DomQuery.compile(p);
6777 throw p + " is not a valid selector";
6780 var result = cache[p](root);
6781 if(result && result != document){
6782 results = results.concat(result);
6785 if(paths.length > 1){
6786 return nodup(results);
6792 * Selects a single element.
6793 * @param {String} selector The selector/xpath query
6794 * @param {Node} root (optional) The start of the query (defaults to document).
6797 selectNode : function(path, root){
6798 return Roo.DomQuery.select(path, root)[0];
6802 * Selects the value of a node, optionally replacing null with the defaultValue.
6803 * @param {String} selector The selector/xpath query
6804 * @param {Node} root (optional) The start of the query (defaults to document).
6805 * @param {String} defaultValue
6807 selectValue : function(path, root, defaultValue){
6808 path = path.replace(trimRe, "");
6809 if(!valueCache[path]){
6810 valueCache[path] = Roo.DomQuery.compile(path, "select");
6812 var n = valueCache[path](root);
6813 n = n[0] ? n[0] : n;
6814 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
6815 return ((v === null||v === undefined||v==='') ? defaultValue : v);
6819 * Selects the value of a node, parsing integers and floats.
6820 * @param {String} selector The selector/xpath query
6821 * @param {Node} root (optional) The start of the query (defaults to document).
6822 * @param {Number} defaultValue
6825 selectNumber : function(path, root, defaultValue){
6826 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
6827 return parseFloat(v);
6831 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
6832 * @param {String/HTMLElement/Array} el An element id, element or array of elements
6833 * @param {String} selector The simple selector to test
6836 is : function(el, ss){
6837 if(typeof el == "string"){
6838 el = document.getElementById(el);
6840 var isArray = (el instanceof Array);
6841 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
6842 return isArray ? (result.length == el.length) : (result.length > 0);
6846 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
6847 * @param {Array} el An array of elements to filter
6848 * @param {String} selector The simple selector to test
6849 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
6850 * the selector instead of the ones that match
6853 filter : function(els, ss, nonMatches){
6854 ss = ss.replace(trimRe, "");
6855 if(!simpleCache[ss]){
6856 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
6858 var result = simpleCache[ss](els);
6859 return nonMatches ? quickDiff(result, els) : result;
6863 * Collection of matching regular expressions and code snippets.
6867 select: 'n = byClassName(n, null, " {1} ");'
6869 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
6870 select: 'n = byPseudo(n, "{1}", "{2}");'
6872 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
6873 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
6876 select: 'n = byId(n, null, "{1}");'
6879 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
6884 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
6885 * 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, > <.
6888 "=" : function(a, v){
6891 "!=" : function(a, v){
6894 "^=" : function(a, v){
6895 return a && a.substr(0, v.length) == v;
6897 "$=" : function(a, v){
6898 return a && a.substr(a.length-v.length) == v;
6900 "*=" : function(a, v){
6901 return a && a.indexOf(v) !== -1;
6903 "%=" : function(a, v){
6904 return (a % v) == 0;
6906 "|=" : function(a, v){
6907 return a && (a == v || a.substr(0, v.length+1) == v+'-');
6909 "~=" : function(a, v){
6910 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
6915 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
6916 * and the argument (if any) supplied in the selector.
6919 "first-child" : function(c){
6920 var r = [], ri = -1, n;
6921 for(var i = 0, ci; ci = n = c[i]; i++){
6922 while((n = n.previousSibling) && n.nodeType != 1);
6930 "last-child" : function(c){
6931 var r = [], ri = -1, n;
6932 for(var i = 0, ci; ci = n = c[i]; i++){
6933 while((n = n.nextSibling) && n.nodeType != 1);
6941 "nth-child" : function(c, a) {
6942 var r = [], ri = -1;
6943 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
6944 var f = (m[1] || 1) - 0, l = m[2] - 0;
6945 for(var i = 0, n; n = c[i]; i++){
6946 var pn = n.parentNode;
6947 if (batch != pn._batch) {
6949 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
6950 if(cn.nodeType == 1){
6957 if (l == 0 || n.nodeIndex == l){
6960 } else if ((n.nodeIndex + l) % f == 0){
6968 "only-child" : function(c){
6969 var r = [], ri = -1;;
6970 for(var i = 0, ci; ci = c[i]; i++){
6971 if(!prev(ci) && !next(ci)){
6978 "empty" : function(c){
6979 var r = [], ri = -1;
6980 for(var i = 0, ci; ci = c[i]; i++){
6981 var cns = ci.childNodes, j = 0, cn, empty = true;
6984 if(cn.nodeType == 1 || cn.nodeType == 3){
6996 "contains" : function(c, v){
6997 var r = [], ri = -1;
6998 for(var i = 0, ci; ci = c[i]; i++){
6999 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
7006 "nodeValue" : function(c, v){
7007 var r = [], ri = -1;
7008 for(var i = 0, ci; ci = c[i]; i++){
7009 if(ci.firstChild && ci.firstChild.nodeValue == v){
7016 "checked" : function(c){
7017 var r = [], ri = -1;
7018 for(var i = 0, ci; ci = c[i]; i++){
7019 if(ci.checked == true){
7026 "not" : function(c, ss){
7027 return Roo.DomQuery.filter(c, ss, true);
7030 "odd" : function(c){
7031 return this["nth-child"](c, "odd");
7034 "even" : function(c){
7035 return this["nth-child"](c, "even");
7038 "nth" : function(c, a){
7039 return c[a-1] || [];
7042 "first" : function(c){
7046 "last" : function(c){
7047 return c[c.length-1] || [];
7050 "has" : function(c, ss){
7051 var s = Roo.DomQuery.select;
7052 var r = [], ri = -1;
7053 for(var i = 0, ci; ci = c[i]; i++){
7054 if(s(ss, ci).length > 0){
7061 "next" : function(c, ss){
7062 var is = Roo.DomQuery.is;
7063 var r = [], ri = -1;
7064 for(var i = 0, ci; ci = c[i]; i++){
7073 "prev" : function(c, ss){
7074 var is = Roo.DomQuery.is;
7075 var r = [], ri = -1;
7076 for(var i = 0, ci; ci = c[i]; i++){
7089 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
7090 * @param {String} path The selector/xpath query
7091 * @param {Node} root (optional) The start of the query (defaults to document).
7096 Roo.query = Roo.DomQuery.select;
7099 * Ext JS Library 1.1.1
7100 * Copyright(c) 2006-2007, Ext JS, LLC.
7102 * Originally Released Under LGPL - original licence link has changed is not relivant.
7105 * <script type="text/javascript">
7109 * @class Roo.util.Observable
7110 * Base class that provides a common interface for publishing events. Subclasses are expected to
7111 * to have a property "events" with all the events defined.<br>
7114 Employee = function(name){
7121 Roo.extend(Employee, Roo.util.Observable);
7123 * @param {Object} config properties to use (incuding events / listeners)
7126 Roo.util.Observable = function(cfg){
7129 this.addEvents(cfg.events || {});
7131 delete cfg.events; // make sure
7134 Roo.apply(this, cfg);
7137 this.on(this.listeners);
7138 delete this.listeners;
7141 Roo.util.Observable.prototype = {
7143 * @cfg {Object} listeners list of events and functions to call for this object,
7147 'click' : function(e) {
7157 * Fires the specified event with the passed parameters (minus the event name).
7158 * @param {String} eventName
7159 * @param {Object...} args Variable number of parameters are passed to handlers
7160 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
7162 fireEvent : function(){
7163 var ce = this.events[arguments[0].toLowerCase()];
7164 if(typeof ce == "object"){
7165 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
7172 filterOptRe : /^(?:scope|delay|buffer|single)$/,
7175 * Appends an event handler to this component
7176 * @param {String} eventName The type of event to listen for
7177 * @param {Function} handler The method the event invokes
7178 * @param {Object} scope (optional) The scope in which to execute the handler
7179 * function. The handler function's "this" context.
7180 * @param {Object} options (optional) An object containing handler configuration
7181 * properties. This may contain any of the following properties:<ul>
7182 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7183 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7184 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7185 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7186 * by the specified number of milliseconds. If the event fires again within that time, the original
7187 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7190 * <b>Combining Options</b><br>
7191 * Using the options argument, it is possible to combine different types of listeners:<br>
7193 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
7195 el.on('click', this.onClick, this, {
7202 * <b>Attaching multiple handlers in 1 call</b><br>
7203 * The method also allows for a single argument to be passed which is a config object containing properties
7204 * which specify multiple handlers.
7213 fn: this.onMouseOver,
7217 fn: this.onMouseOut,
7223 * Or a shorthand syntax which passes the same scope object to all handlers:
7226 'click': this.onClick,
7227 'mouseover': this.onMouseOver,
7228 'mouseout': this.onMouseOut,
7233 addListener : function(eventName, fn, scope, o){
7234 if(typeof eventName == "object"){
7237 if(this.filterOptRe.test(e)){
7240 if(typeof o[e] == "function"){
7242 this.addListener(e, o[e], o.scope, o);
7244 // individual options
7245 this.addListener(e, o[e].fn, o[e].scope, o[e]);
7250 o = (!o || typeof o == "boolean") ? {} : o;
7251 eventName = eventName.toLowerCase();
7252 var ce = this.events[eventName] || true;
7253 if(typeof ce == "boolean"){
7254 ce = new Roo.util.Event(this, eventName);
7255 this.events[eventName] = ce;
7257 ce.addListener(fn, scope, o);
7261 * Removes a listener
7262 * @param {String} eventName The type of event to listen for
7263 * @param {Function} handler The handler to remove
7264 * @param {Object} scope (optional) The scope (this object) for the handler
7266 removeListener : function(eventName, fn, scope){
7267 var ce = this.events[eventName.toLowerCase()];
7268 if(typeof ce == "object"){
7269 ce.removeListener(fn, scope);
7274 * Removes all listeners for this object
7276 purgeListeners : function(){
7277 for(var evt in this.events){
7278 if(typeof this.events[evt] == "object"){
7279 this.events[evt].clearListeners();
7284 relayEvents : function(o, events){
7285 var createHandler = function(ename){
7288 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
7291 for(var i = 0, len = events.length; i < len; i++){
7292 var ename = events[i];
7293 if(!this.events[ename]){
7294 this.events[ename] = true;
7296 o.on(ename, createHandler(ename), this);
7301 * Used to define events on this Observable
7302 * @param {Object} object The object with the events defined
7304 addEvents : function(o){
7308 Roo.applyIf(this.events, o);
7312 * Checks to see if this object has any listeners for a specified event
7313 * @param {String} eventName The name of the event to check for
7314 * @return {Boolean} True if the event is being listened for, else false
7316 hasListener : function(eventName){
7317 var e = this.events[eventName];
7318 return typeof e == "object" && e.listeners.length > 0;
7322 * Appends an event handler to this element (shorthand for addListener)
7323 * @param {String} eventName The type of event to listen for
7324 * @param {Function} handler The method the event invokes
7325 * @param {Object} scope (optional) The scope in which to execute the handler
7326 * function. The handler function's "this" context.
7327 * @param {Object} options (optional)
7330 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
7332 * Removes a listener (shorthand for removeListener)
7333 * @param {String} eventName The type of event to listen for
7334 * @param {Function} handler The handler to remove
7335 * @param {Object} scope (optional) The scope (this object) for the handler
7338 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
7341 * Starts capture on the specified Observable. All events will be passed
7342 * to the supplied function with the event name + standard signature of the event
7343 * <b>before</b> the event is fired. If the supplied function returns false,
7344 * the event will not fire.
7345 * @param {Observable} o The Observable to capture
7346 * @param {Function} fn The function to call
7347 * @param {Object} scope (optional) The scope (this object) for the fn
7350 Roo.util.Observable.capture = function(o, fn, scope){
7351 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
7355 * Removes <b>all</b> added captures from the Observable.
7356 * @param {Observable} o The Observable to release
7359 Roo.util.Observable.releaseCapture = function(o){
7360 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
7365 var createBuffered = function(h, o, scope){
7366 var task = new Roo.util.DelayedTask();
7368 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
7372 var createSingle = function(h, e, fn, scope){
7374 e.removeListener(fn, scope);
7375 return h.apply(scope, arguments);
7379 var createDelayed = function(h, o, scope){
7381 var args = Array.prototype.slice.call(arguments, 0);
7382 setTimeout(function(){
7383 h.apply(scope, args);
7388 Roo.util.Event = function(obj, name){
7391 this.listeners = [];
7394 Roo.util.Event.prototype = {
7395 addListener : function(fn, scope, options){
7396 var o = options || {};
7397 scope = scope || this.obj;
7398 if(!this.isListening(fn, scope)){
7399 var l = {fn: fn, scope: scope, options: o};
7402 h = createDelayed(h, o, scope);
7405 h = createSingle(h, this, fn, scope);
7408 h = createBuffered(h, o, scope);
7411 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
7412 this.listeners.push(l);
7414 this.listeners = this.listeners.slice(0);
7415 this.listeners.push(l);
7420 findListener : function(fn, scope){
7421 scope = scope || this.obj;
7422 var ls = this.listeners;
7423 for(var i = 0, len = ls.length; i < len; i++){
7425 if(l.fn == fn && l.scope == scope){
7432 isListening : function(fn, scope){
7433 return this.findListener(fn, scope) != -1;
7436 removeListener : function(fn, scope){
7438 if((index = this.findListener(fn, scope)) != -1){
7440 this.listeners.splice(index, 1);
7442 this.listeners = this.listeners.slice(0);
7443 this.listeners.splice(index, 1);
7450 clearListeners : function(){
7451 this.listeners = [];
7455 var ls = this.listeners, scope, len = ls.length;
7458 var args = Array.prototype.slice.call(arguments, 0);
7459 for(var i = 0; i < len; i++){
7461 if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
7462 this.firing = false;
7466 this.firing = false;
7473 * Copyright(c) 2007-2017, Roo J Solutions Ltd
7480 * @class Roo.Document
7481 * @extends Roo.util.Observable
7482 * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
7484 * @param {Object} config the methods and properties of the 'base' class for the application.
7486 * Generic Page handler - implement this to start your app..
7489 * MyProject = new Roo.Document({
7491 'load' : true // your events..
7494 'ready' : function() {
7495 // fired on Roo.onReady()
7500 Roo.Document = function(cfg) {
7505 Roo.util.Observable.call(this,cfg);
7509 Roo.onReady(function() {
7510 _this.fireEvent('ready');
7516 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
7518 * Ext JS Library 1.1.1
7519 * Copyright(c) 2006-2007, Ext JS, LLC.
7521 * Originally Released Under LGPL - original licence link has changed is not relivant.
7524 * <script type="text/javascript">
7528 * @class Roo.EventManager
7529 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
7530 * several useful events directly.
7531 * See {@link Roo.EventObject} for more details on normalized event objects.
7534 Roo.EventManager = function(){
7535 var docReadyEvent, docReadyProcId, docReadyState = false;
7536 var resizeEvent, resizeTask, textEvent, textSize;
7537 var E = Roo.lib.Event;
7538 var D = Roo.lib.Dom;
7543 var fireDocReady = function(){
7545 docReadyState = true;
7548 clearInterval(docReadyProcId);
7550 if(Roo.isGecko || Roo.isOpera) {
7551 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
7554 var defer = document.getElementById("ie-deferred-loader");
7556 defer.onreadystatechange = null;
7557 defer.parentNode.removeChild(defer);
7561 docReadyEvent.fire();
7562 docReadyEvent.clearListeners();
7567 var initDocReady = function(){
7568 docReadyEvent = new Roo.util.Event();
7569 if(Roo.isGecko || Roo.isOpera) {
7570 document.addEventListener("DOMContentLoaded", fireDocReady, false);
7572 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
7573 var defer = document.getElementById("ie-deferred-loader");
7574 defer.onreadystatechange = function(){
7575 if(this.readyState == "complete"){
7579 }else if(Roo.isSafari){
7580 docReadyProcId = setInterval(function(){
7581 var rs = document.readyState;
7582 if(rs == "complete") {
7587 // no matter what, make sure it fires on load
7588 E.on(window, "load", fireDocReady);
7591 var createBuffered = function(h, o){
7592 var task = new Roo.util.DelayedTask(h);
7594 // create new event object impl so new events don't wipe out properties
7595 e = new Roo.EventObjectImpl(e);
7596 task.delay(o.buffer, h, null, [e]);
7600 var createSingle = function(h, el, ename, fn){
7602 Roo.EventManager.removeListener(el, ename, fn);
7607 var createDelayed = function(h, o){
7609 // create new event object impl so new events don't wipe out properties
7610 e = new Roo.EventObjectImpl(e);
7611 setTimeout(function(){
7616 var transitionEndVal = false;
7618 var transitionEnd = function()
7620 if (transitionEndVal) {
7621 return transitionEndVal;
7623 var el = document.createElement('div');
7625 var transEndEventNames = {
7626 WebkitTransition : 'webkitTransitionEnd',
7627 MozTransition : 'transitionend',
7628 OTransition : 'oTransitionEnd otransitionend',
7629 transition : 'transitionend'
7632 for (var name in transEndEventNames) {
7633 if (el.style[name] !== undefined) {
7634 transitionEndVal = transEndEventNames[name];
7635 return transitionEndVal ;
7642 var listen = function(element, ename, opt, fn, scope)
7644 var o = (!opt || typeof opt == "boolean") ? {} : opt;
7645 fn = fn || o.fn; scope = scope || o.scope;
7646 var el = Roo.getDom(element);
7650 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
7653 if (ename == 'transitionend') {
7654 ename = transitionEnd();
7656 var h = function(e){
7657 e = Roo.EventObject.setEvent(e);
7660 t = e.getTarget(o.delegate, el);
7667 if(o.stopEvent === true){
7670 if(o.preventDefault === true){
7673 if(o.stopPropagation === true){
7674 e.stopPropagation();
7677 if(o.normalized === false){
7681 fn.call(scope || el, e, t, o);
7684 h = createDelayed(h, o);
7687 h = createSingle(h, el, ename, fn);
7690 h = createBuffered(h, o);
7693 fn._handlers = fn._handlers || [];
7696 fn._handlers.push([Roo.id(el), ename, h]);
7700 E.on(el, ename, h); // this adds the actuall listener to the object..
7703 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
7704 el.addEventListener("DOMMouseScroll", h, false);
7705 E.on(window, 'unload', function(){
7706 el.removeEventListener("DOMMouseScroll", h, false);
7709 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7710 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
7715 var stopListening = function(el, ename, fn){
7716 var id = Roo.id(el), hds = fn._handlers, hd = fn;
7718 for(var i = 0, len = hds.length; i < len; i++){
7720 if(h[0] == id && h[1] == ename){
7727 E.un(el, ename, hd);
7728 el = Roo.getDom(el);
7729 if(ename == "mousewheel" && el.addEventListener){
7730 el.removeEventListener("DOMMouseScroll", hd, false);
7732 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7733 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
7737 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
7744 * @scope Roo.EventManager
7749 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
7750 * object with a Roo.EventObject
7751 * @param {Function} fn The method the event invokes
7752 * @param {Object} scope An object that becomes the scope of the handler
7753 * @param {boolean} override If true, the obj passed in becomes
7754 * the execution scope of the listener
7755 * @return {Function} The wrapped function
7758 wrap : function(fn, scope, override){
7760 Roo.EventObject.setEvent(e);
7761 fn.call(override ? scope || window : window, Roo.EventObject, scope);
7766 * Appends an event handler to an element (shorthand for addListener)
7767 * @param {String/HTMLElement} element The html element or id to assign the
7768 * @param {String} eventName The type of event to listen for
7769 * @param {Function} handler The method the event invokes
7770 * @param {Object} scope (optional) The scope in which to execute the handler
7771 * function. The handler function's "this" context.
7772 * @param {Object} options (optional) An object containing handler configuration
7773 * properties. This may contain any of the following properties:<ul>
7774 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7775 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7776 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7777 * <li>preventDefault {Boolean} True to prevent the default action</li>
7778 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7779 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7780 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7781 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7782 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7783 * by the specified number of milliseconds. If the event fires again within that time, the original
7784 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7787 * <b>Combining Options</b><br>
7788 * Using the options argument, it is possible to combine different types of listeners:<br>
7790 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7792 el.on('click', this.onClick, this, {
7799 * <b>Attaching multiple handlers in 1 call</b><br>
7800 * The method also allows for a single argument to be passed which is a config object containing properties
7801 * which specify multiple handlers.
7811 fn: this.onMouseOver
7820 * Or a shorthand syntax:<br>
7823 'click' : this.onClick,
7824 'mouseover' : this.onMouseOver,
7825 'mouseout' : this.onMouseOut
7829 addListener : function(element, eventName, fn, scope, options){
7830 if(typeof eventName == "object"){
7836 if(typeof o[e] == "function"){
7838 listen(element, e, o, o[e], o.scope);
7840 // individual options
7841 listen(element, e, o[e]);
7846 return listen(element, eventName, options, fn, scope);
7850 * Removes an event handler
7852 * @param {String/HTMLElement} element The id or html element to remove the
7854 * @param {String} eventName The type of event
7855 * @param {Function} fn
7856 * @return {Boolean} True if a listener was actually removed
7858 removeListener : function(element, eventName, fn){
7859 return stopListening(element, eventName, fn);
7863 * Fires when the document is ready (before onload and before images are loaded). Can be
7864 * accessed shorthanded Roo.onReady().
7865 * @param {Function} fn The method the event invokes
7866 * @param {Object} scope An object that becomes the scope of the handler
7867 * @param {boolean} options
7869 onDocumentReady : function(fn, scope, options){
7870 if(docReadyState){ // if it already fired
7871 docReadyEvent.addListener(fn, scope, options);
7872 docReadyEvent.fire();
7873 docReadyEvent.clearListeners();
7879 docReadyEvent.addListener(fn, scope, options);
7883 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
7884 * @param {Function} fn The method the event invokes
7885 * @param {Object} scope An object that becomes the scope of the handler
7886 * @param {boolean} options
7888 onWindowResize : function(fn, scope, options)
7891 resizeEvent = new Roo.util.Event();
7892 resizeTask = new Roo.util.DelayedTask(function(){
7893 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7895 E.on(window, "resize", function()
7898 resizeTask.delay(50);
7900 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7904 resizeEvent.addListener(fn, scope, options);
7908 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
7909 * @param {Function} fn The method the event invokes
7910 * @param {Object} scope An object that becomes the scope of the handler
7911 * @param {boolean} options
7913 onTextResize : function(fn, scope, options){
7915 textEvent = new Roo.util.Event();
7916 var textEl = new Roo.Element(document.createElement('div'));
7917 textEl.dom.className = 'x-text-resize';
7918 textEl.dom.innerHTML = 'X';
7919 textEl.appendTo(document.body);
7920 textSize = textEl.dom.offsetHeight;
7921 setInterval(function(){
7922 if(textEl.dom.offsetHeight != textSize){
7923 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
7925 }, this.textResizeInterval);
7927 textEvent.addListener(fn, scope, options);
7931 * Removes the passed window resize listener.
7932 * @param {Function} fn The method the event invokes
7933 * @param {Object} scope The scope of handler
7935 removeResizeListener : function(fn, scope){
7937 resizeEvent.removeListener(fn, scope);
7942 fireResize : function(){
7944 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7948 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
7952 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
7954 textResizeInterval : 50
7959 * @scopeAlias pub=Roo.EventManager
7963 * Appends an event handler to an element (shorthand for addListener)
7964 * @param {String/HTMLElement} element The html element or id to assign the
7965 * @param {String} eventName The type of event to listen for
7966 * @param {Function} handler The method the event invokes
7967 * @param {Object} scope (optional) The scope in which to execute the handler
7968 * function. The handler function's "this" context.
7969 * @param {Object} options (optional) An object containing handler configuration
7970 * properties. This may contain any of the following properties:<ul>
7971 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7972 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7973 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7974 * <li>preventDefault {Boolean} True to prevent the default action</li>
7975 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7976 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7977 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7978 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7979 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7980 * by the specified number of milliseconds. If the event fires again within that time, the original
7981 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7984 * <b>Combining Options</b><br>
7985 * Using the options argument, it is possible to combine different types of listeners:<br>
7987 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7989 el.on('click', this.onClick, this, {
7996 * <b>Attaching multiple handlers in 1 call</b><br>
7997 * The method also allows for a single argument to be passed which is a config object containing properties
7998 * which specify multiple handlers.
8008 fn: this.onMouseOver
8017 * Or a shorthand syntax:<br>
8020 'click' : this.onClick,
8021 'mouseover' : this.onMouseOver,
8022 'mouseout' : this.onMouseOut
8026 pub.on = pub.addListener;
8027 pub.un = pub.removeListener;
8029 pub.stoppedMouseDownEvent = new Roo.util.Event();
8033 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
8034 * @param {Function} fn The method the event invokes
8035 * @param {Object} scope An object that becomes the scope of the handler
8036 * @param {boolean} override If true, the obj passed in becomes
8037 * the execution scope of the listener
8041 Roo.onReady = Roo.EventManager.onDocumentReady;
8043 Roo.onReady(function(){
8044 var bd = Roo.get(document.body);
8049 : Roo.isIE11 ? "roo-ie11"
8050 : Roo.isEdge ? "roo-edge"
8051 : Roo.isGecko ? "roo-gecko"
8052 : Roo.isOpera ? "roo-opera"
8053 : Roo.isSafari ? "roo-safari" : ""];
8056 cls.push("roo-mac");
8059 cls.push("roo-linux");
8062 cls.push("roo-ios");
8065 cls.push("roo-touch");
8067 if(Roo.isBorderBox){
8068 cls.push('roo-border-box');
8070 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
8071 var p = bd.dom.parentNode;
8073 p.className += ' roo-strict';
8076 bd.addClass(cls.join(' '));
8080 * @class Roo.EventObject
8081 * EventObject exposes the Yahoo! UI Event functionality directly on the object
8082 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
8085 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
8087 var target = e.getTarget();
8090 var myDiv = Roo.get("myDiv");
8091 myDiv.on("click", handleClick);
8093 Roo.EventManager.on("myDiv", 'click', handleClick);
8094 Roo.EventManager.addListener("myDiv", 'click', handleClick);
8098 Roo.EventObject = function(){
8100 var E = Roo.lib.Event;
8102 // safari keypress events for special keys return bad keycodes
8105 63235 : 39, // right
8108 63276 : 33, // page up
8109 63277 : 34, // page down
8110 63272 : 46, // delete
8115 // normalize button clicks
8116 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
8117 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
8119 Roo.EventObjectImpl = function(e){
8121 this.setEvent(e.browserEvent || e);
8124 Roo.EventObjectImpl.prototype = {
8126 * Used to fix doc tools.
8127 * @scope Roo.EventObject.prototype
8133 /** The normal browser event */
8134 browserEvent : null,
8135 /** The button pressed in a mouse event */
8137 /** True if the shift key was down during the event */
8139 /** True if the control key was down during the event */
8141 /** True if the alt key was down during the event */
8200 setEvent : function(e){
8201 if(e == this || (e && e.browserEvent)){ // already wrapped
8204 this.browserEvent = e;
8206 // normalize buttons
8207 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
8208 if(e.type == 'click' && this.button == -1){
8212 this.shiftKey = e.shiftKey;
8213 // mac metaKey behaves like ctrlKey
8214 this.ctrlKey = e.ctrlKey || e.metaKey;
8215 this.altKey = e.altKey;
8216 // in getKey these will be normalized for the mac
8217 this.keyCode = e.keyCode;
8218 // keyup warnings on firefox.
8219 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
8220 // cache the target for the delayed and or buffered events
8221 this.target = E.getTarget(e);
8223 this.xy = E.getXY(e);
8226 this.shiftKey = false;
8227 this.ctrlKey = false;
8228 this.altKey = false;
8238 * Stop the event (preventDefault and stopPropagation)
8240 stopEvent : function(){
8241 if(this.browserEvent){
8242 if(this.browserEvent.type == 'mousedown'){
8243 Roo.EventManager.stoppedMouseDownEvent.fire(this);
8245 E.stopEvent(this.browserEvent);
8250 * Prevents the browsers default handling of the event.
8252 preventDefault : function(){
8253 if(this.browserEvent){
8254 E.preventDefault(this.browserEvent);
8259 isNavKeyPress : function(){
8260 var k = this.keyCode;
8261 k = Roo.isSafari ? (safariKeys[k] || k) : k;
8262 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
8265 isSpecialKey : function(){
8266 var k = this.keyCode;
8267 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
8268 (k == 16) || (k == 17) ||
8269 (k >= 18 && k <= 20) ||
8270 (k >= 33 && k <= 35) ||
8271 (k >= 36 && k <= 39) ||
8272 (k >= 44 && k <= 45);
8275 * Cancels bubbling of the event.
8277 stopPropagation : function(){
8278 if(this.browserEvent){
8279 if(this.type == 'mousedown'){
8280 Roo.EventManager.stoppedMouseDownEvent.fire(this);
8282 E.stopPropagation(this.browserEvent);
8287 * Gets the key code for the event.
8290 getCharCode : function(){
8291 return this.charCode || this.keyCode;
8295 * Returns a normalized keyCode for the event.
8296 * @return {Number} The key code
8298 getKey : function(){
8299 var k = this.keyCode || this.charCode;
8300 return Roo.isSafari ? (safariKeys[k] || k) : k;
8304 * Gets the x coordinate of the event.
8307 getPageX : function(){
8312 * Gets the y coordinate of the event.
8315 getPageY : function(){
8320 * Gets the time of the event.
8323 getTime : function(){
8324 if(this.browserEvent){
8325 return E.getTime(this.browserEvent);
8331 * Gets the page coordinates of the event.
8332 * @return {Array} The xy values like [x, y]
8339 * Gets the target for the event.
8340 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
8341 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8342 search as a number or element (defaults to 10 || document.body)
8343 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8344 * @return {HTMLelement}
8346 getTarget : function(selector, maxDepth, returnEl){
8347 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
8350 * Gets the related target.
8351 * @return {HTMLElement}
8353 getRelatedTarget : function(){
8354 if(this.browserEvent){
8355 return E.getRelatedTarget(this.browserEvent);
8361 * Normalizes mouse wheel delta across browsers
8362 * @return {Number} The delta
8364 getWheelDelta : function(){
8365 var e = this.browserEvent;
8367 if(e.wheelDelta){ /* IE/Opera. */
8368 delta = e.wheelDelta/120;
8369 }else if(e.detail){ /* Mozilla case. */
8370 delta = -e.detail/3;
8376 * Returns true if the control, meta, shift or alt key was pressed during this event.
8379 hasModifier : function(){
8380 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
8384 * Returns true if the target of this event equals el or is a child of el
8385 * @param {String/HTMLElement/Element} el
8386 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
8389 within : function(el, related){
8390 var t = this[related ? "getRelatedTarget" : "getTarget"]();
8391 return t && Roo.fly(el).contains(t);
8394 getPoint : function(){
8395 return new Roo.lib.Point(this.xy[0], this.xy[1]);
8399 return new Roo.EventObjectImpl();
8404 * Ext JS Library 1.1.1
8405 * Copyright(c) 2006-2007, Ext JS, LLC.
8407 * Originally Released Under LGPL - original licence link has changed is not relivant.
8410 * <script type="text/javascript">
8414 // was in Composite Element!??!?!
8417 var D = Roo.lib.Dom;
8418 var E = Roo.lib.Event;
8419 var A = Roo.lib.Anim;
8421 // local style camelizing for speed
8423 var camelRe = /(-[a-z])/gi;
8424 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
8425 var view = document.defaultView;
8428 * @class Roo.Element
8429 * Represents an Element in the DOM.<br><br>
8432 var el = Roo.get("my-div");
8435 var el = getEl("my-div");
8437 // or with a DOM element
8438 var el = Roo.get(myDivElement);
8440 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
8441 * each call instead of constructing a new one.<br><br>
8442 * <b>Animations</b><br />
8443 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
8444 * should either be a boolean (true) or an object literal with animation options. The animation options are:
8446 Option Default Description
8447 --------- -------- ---------------------------------------------
8448 duration .35 The duration of the animation in seconds
8449 easing easeOut The YUI easing method
8450 callback none A function to execute when the anim completes
8451 scope this The scope (this) of the callback function
8453 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
8454 * manipulate the animation. Here's an example:
8456 var el = Roo.get("my-div");
8461 // default animation
8462 el.setWidth(100, true);
8464 // animation with some options set
8471 // using the "anim" property to get the Anim object
8477 el.setWidth(100, opt);
8479 if(opt.anim.isAnimated()){
8483 * <b> Composite (Collections of) Elements</b><br />
8484 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
8485 * @constructor Create a new Element directly.
8486 * @param {String/HTMLElement} element
8487 * @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).
8489 Roo.Element = function(element, forceNew)
8491 var dom = typeof element == "string" ?
8492 document.getElementById(element) : element;
8494 this.listeners = {};
8496 if(!dom){ // invalid id/element
8500 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
8501 return Roo.Element.cache[id];
8511 * The DOM element ID
8514 this.id = id || Roo.id(dom);
8516 return this; // assumed for cctor?
8519 var El = Roo.Element;
8523 * The element's default display mode (defaults to "")
8526 originalDisplay : "",
8529 // note this is overridden in BS version..
8532 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
8538 * Sets the element's visibility mode. When setVisible() is called it
8539 * will use this to determine whether to set the visibility or the display property.
8540 * @param visMode Element.VISIBILITY or Element.DISPLAY
8541 * @return {Roo.Element} this
8543 setVisibilityMode : function(visMode){
8544 this.visibilityMode = visMode;
8548 * Convenience method for setVisibilityMode(Element.DISPLAY)
8549 * @param {String} display (optional) What to set display to when visible
8550 * @return {Roo.Element} this
8552 enableDisplayMode : function(display){
8553 this.setVisibilityMode(El.DISPLAY);
8554 if(typeof display != "undefined") { this.originalDisplay = display; }
8559 * 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)
8560 * @param {String} selector The simple selector to test
8561 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8562 search as a number or element (defaults to 10 || document.body)
8563 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8564 * @return {HTMLElement} The matching DOM node (or null if no match was found)
8566 findParent : function(simpleSelector, maxDepth, returnEl){
8567 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
8568 maxDepth = maxDepth || 50;
8569 if(typeof maxDepth != "number"){
8570 stopEl = Roo.getDom(maxDepth);
8573 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
8574 if(dq.is(p, simpleSelector)){
8575 return returnEl ? Roo.get(p) : p;
8585 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
8586 * @param {String} selector The simple selector to test
8587 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8588 search as a number or element (defaults to 10 || document.body)
8589 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8590 * @return {HTMLElement} The matching DOM node (or null if no match was found)
8592 findParentNode : function(simpleSelector, maxDepth, returnEl){
8593 var p = Roo.fly(this.dom.parentNode, '_internal');
8594 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
8598 * Looks at the scrollable parent element
8600 findScrollableParent : function()
8602 var overflowRegex = /(auto|scroll)/;
8604 if(this.getStyle('position') === 'fixed'){
8605 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8608 var excludeStaticParent = this.getStyle('position') === "absolute";
8610 for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
8612 if (excludeStaticParent && parent.getStyle('position') === "static") {
8616 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
8620 if(parent.dom.nodeName.toLowerCase() == 'body'){
8621 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8625 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8629 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
8630 * This is a shortcut for findParentNode() that always returns an Roo.Element.
8631 * @param {String} selector The simple selector to test
8632 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8633 search as a number or element (defaults to 10 || document.body)
8634 * @return {Roo.Element} The matching DOM node (or null if no match was found)
8636 up : function(simpleSelector, maxDepth){
8637 return this.findParentNode(simpleSelector, maxDepth, true);
8643 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
8644 * @param {String} selector The simple selector to test
8645 * @return {Boolean} True if this element matches the selector, else false
8647 is : function(simpleSelector){
8648 return Roo.DomQuery.is(this.dom, simpleSelector);
8652 * Perform animation on this element.
8653 * @param {Object} args The YUI animation control args
8654 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
8655 * @param {Function} onComplete (optional) Function to call when animation completes
8656 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
8657 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
8658 * @return {Roo.Element} this
8660 animate : function(args, duration, onComplete, easing, animType){
8661 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
8666 * @private Internal animation call
8668 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
8669 animType = animType || 'run';
8671 var anim = Roo.lib.Anim[animType](
8673 (opt.duration || defaultDur) || .35,
8674 (opt.easing || defaultEase) || 'easeOut',
8676 Roo.callback(cb, this);
8677 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
8685 // private legacy anim prep
8686 preanim : function(a, i){
8687 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
8691 * Removes worthless text nodes
8692 * @param {Boolean} forceReclean (optional) By default the element
8693 * keeps track if it has been cleaned already so
8694 * you can call this over and over. However, if you update the element and
8695 * need to force a reclean, you can pass true.
8697 clean : function(forceReclean){
8698 if(this.isCleaned && forceReclean !== true){
8702 var d = this.dom, n = d.firstChild, ni = -1;
8704 var nx = n.nextSibling;
8705 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
8712 this.isCleaned = true;
8717 calcOffsetsTo : function(el){
8720 var restorePos = false;
8721 if(el.getStyle('position') == 'static'){
8722 el.position('relative');
8727 while(op && op != d && op.tagName != 'HTML'){
8730 op = op.offsetParent;
8733 el.position('static');
8739 * Scrolls this element into view within the passed container.
8740 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
8741 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
8742 * @return {Roo.Element} this
8744 scrollIntoView : function(container, hscroll){
8745 var c = Roo.getDom(container) || document.body;
8748 var o = this.calcOffsetsTo(c),
8751 b = t+el.offsetHeight,
8752 r = l+el.offsetWidth;
8754 var ch = c.clientHeight;
8755 var ct = parseInt(c.scrollTop, 10);
8756 var cl = parseInt(c.scrollLeft, 10);
8758 var cr = cl + c.clientWidth;
8766 if(hscroll !== false){
8770 c.scrollLeft = r-c.clientWidth;
8777 scrollChildIntoView : function(child, hscroll){
8778 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
8782 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
8783 * the new height may not be available immediately.
8784 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
8785 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
8786 * @param {Function} onComplete (optional) Function to call when animation completes
8787 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
8788 * @return {Roo.Element} this
8790 autoHeight : function(animate, duration, onComplete, easing){
8791 var oldHeight = this.getHeight();
8793 this.setHeight(1); // force clipping
8794 setTimeout(function(){
8795 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
8797 this.setHeight(height);
8799 if(typeof onComplete == "function"){
8803 this.setHeight(oldHeight); // restore original height
8804 this.setHeight(height, animate, duration, function(){
8806 if(typeof onComplete == "function") { onComplete(); }
8807 }.createDelegate(this), easing);
8809 }.createDelegate(this), 0);
8814 * Returns true if this element is an ancestor of the passed element
8815 * @param {HTMLElement/String} el The element to check
8816 * @return {Boolean} True if this element is an ancestor of el, else false
8818 contains : function(el){
8819 if(!el){return false;}
8820 return D.isAncestor(this.dom, el.dom ? el.dom : el);
8824 * Checks whether the element is currently visible using both visibility and display properties.
8825 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
8826 * @return {Boolean} True if the element is currently visible, else false
8828 isVisible : function(deep) {
8829 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
8830 if(deep !== true || !vis){
8833 var p = this.dom.parentNode;
8834 while(p && p.tagName.toLowerCase() != "body"){
8835 if(!Roo.fly(p, '_isVisible').isVisible()){
8844 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
8845 * @param {String} selector The CSS selector
8846 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
8847 * @return {CompositeElement/CompositeElementLite} The composite element
8849 select : function(selector, unique){
8850 return El.select(selector, unique, this.dom);
8854 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
8855 * @param {String} selector The CSS selector
8856 * @return {Array} An array of the matched nodes
8858 query : function(selector, unique){
8859 return Roo.DomQuery.select(selector, this.dom);
8863 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
8864 * @param {String} selector The CSS selector
8865 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8866 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8868 child : function(selector, returnDom){
8869 var n = Roo.DomQuery.selectNode(selector, this.dom);
8870 return returnDom ? n : Roo.get(n);
8874 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
8875 * @param {String} selector The CSS selector
8876 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8877 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8879 down : function(selector, returnDom){
8880 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
8881 return returnDom ? n : Roo.get(n);
8885 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
8886 * @param {String} group The group the DD object is member of
8887 * @param {Object} config The DD config object
8888 * @param {Object} overrides An object containing methods to override/implement on the DD object
8889 * @return {Roo.dd.DD} The DD object
8891 initDD : function(group, config, overrides){
8892 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
8893 return Roo.apply(dd, overrides);
8897 * Initializes a {@link Roo.dd.DDProxy} object for this element.
8898 * @param {String} group The group the DDProxy object is member of
8899 * @param {Object} config The DDProxy config object
8900 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
8901 * @return {Roo.dd.DDProxy} The DDProxy object
8903 initDDProxy : function(group, config, overrides){
8904 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
8905 return Roo.apply(dd, overrides);
8909 * Initializes a {@link Roo.dd.DDTarget} object for this element.
8910 * @param {String} group The group the DDTarget object is member of
8911 * @param {Object} config The DDTarget config object
8912 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
8913 * @return {Roo.dd.DDTarget} The DDTarget object
8915 initDDTarget : function(group, config, overrides){
8916 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
8917 return Roo.apply(dd, overrides);
8921 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
8922 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
8923 * @param {Boolean} visible Whether the element is visible
8924 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8925 * @return {Roo.Element} this
8927 setVisible : function(visible, animate){
8929 if(this.visibilityMode == El.DISPLAY){
8930 this.setDisplayed(visible);
8933 this.dom.style.visibility = visible ? "visible" : "hidden";
8936 // closure for composites
8938 var visMode = this.visibilityMode;
8940 this.setOpacity(.01);
8941 this.setVisible(true);
8943 this.anim({opacity: { to: (visible?1:0) }},
8944 this.preanim(arguments, 1),
8945 null, .35, 'easeIn', function(){
8947 if(visMode == El.DISPLAY){
8948 dom.style.display = "none";
8950 dom.style.visibility = "hidden";
8952 Roo.get(dom).setOpacity(1);
8960 * Returns true if display is not "none"
8963 isDisplayed : function() {
8964 return this.getStyle("display") != "none";
8968 * Toggles the element's visibility or display, depending on visibility mode.
8969 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8970 * @return {Roo.Element} this
8972 toggle : function(animate){
8973 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
8978 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
8979 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
8980 * @return {Roo.Element} this
8982 setDisplayed : function(value) {
8983 if(typeof value == "boolean"){
8984 value = value ? this.originalDisplay : "none";
8986 this.setStyle("display", value);
8991 * Tries to focus the element. Any exceptions are caught and ignored.
8992 * @return {Roo.Element} this
8994 focus : function() {
9002 * Tries to blur the element. Any exceptions are caught and ignored.
9003 * @return {Roo.Element} this
9013 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
9014 * @param {String/Array} className The CSS class to add, or an array of classes
9015 * @return {Roo.Element} this
9017 addClass : function(className){
9018 if(className instanceof Array){
9019 for(var i = 0, len = className.length; i < len; i++) {
9020 this.addClass(className[i]);
9023 if(className && !this.hasClass(className)){
9024 if (this.dom instanceof SVGElement) {
9025 this.dom.className.baseVal =this.dom.className.baseVal + " " + className;
9027 this.dom.className = this.dom.className + " " + className;
9035 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
9036 * @param {String/Array} className The CSS class to add, or an array of classes
9037 * @return {Roo.Element} this
9039 radioClass : function(className){
9040 var siblings = this.dom.parentNode.childNodes;
9041 for(var i = 0; i < siblings.length; i++) {
9042 var s = siblings[i];
9043 if(s.nodeType == 1){
9044 Roo.get(s).removeClass(className);
9047 this.addClass(className);
9052 * Removes one or more CSS classes from the element.
9053 * @param {String/Array} className The CSS class to remove, or an array of classes
9054 * @return {Roo.Element} this
9056 removeClass : function(className){
9058 var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
9059 if(!className || !cn){
9062 if(className instanceof Array){
9063 for(var i = 0, len = className.length; i < len; i++) {
9064 this.removeClass(className[i]);
9067 if(this.hasClass(className)){
9068 var re = this.classReCache[className];
9070 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
9071 this.classReCache[className] = re;
9073 if (this.dom instanceof SVGElement) {
9074 this.dom.className.baseVal = cn.replace(re, " ");
9076 this.dom.className = cn.replace(re, " ");
9087 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
9088 * @param {String} className The CSS class to toggle
9089 * @return {Roo.Element} this
9091 toggleClass : function(className){
9092 if(this.hasClass(className)){
9093 this.removeClass(className);
9095 this.addClass(className);
9101 * Checks if the specified CSS class exists on this element's DOM node.
9102 * @param {String} className The CSS class to check for
9103 * @return {Boolean} True if the class exists, else false
9105 hasClass : function(className){
9106 if (this.dom instanceof SVGElement) {
9107 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1;
9109 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
9113 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
9114 * @param {String} oldClassName The CSS class to replace
9115 * @param {String} newClassName The replacement CSS class
9116 * @return {Roo.Element} this
9118 replaceClass : function(oldClassName, newClassName){
9119 this.removeClass(oldClassName);
9120 this.addClass(newClassName);
9125 * Returns an object with properties matching the styles requested.
9126 * For example, el.getStyles('color', 'font-size', 'width') might return
9127 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
9128 * @param {String} style1 A style name
9129 * @param {String} style2 A style name
9130 * @param {String} etc.
9131 * @return {Object} The style object
9133 getStyles : function(){
9134 var a = arguments, len = a.length, r = {};
9135 for(var i = 0; i < len; i++){
9136 r[a[i]] = this.getStyle(a[i]);
9142 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
9143 * @param {String} property The style property whose value is returned.
9144 * @return {String} The current value of the style property for this element.
9146 getStyle : function(){
9147 return view && view.getComputedStyle ?
9149 var el = this.dom, v, cs, camel;
9150 if(prop == 'float'){
9153 if(el.style && (v = el.style[prop])){
9156 if(cs = view.getComputedStyle(el, "")){
9157 if(!(camel = propCache[prop])){
9158 camel = propCache[prop] = prop.replace(camelRe, camelFn);
9165 var el = this.dom, v, cs, camel;
9166 if(prop == 'opacity'){
9167 if(typeof el.style.filter == 'string'){
9168 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
9170 var fv = parseFloat(m[1]);
9172 return fv ? fv / 100 : 0;
9177 }else if(prop == 'float'){
9178 prop = "styleFloat";
9180 if(!(camel = propCache[prop])){
9181 camel = propCache[prop] = prop.replace(camelRe, camelFn);
9183 if(v = el.style[camel]){
9186 if(cs = el.currentStyle){
9194 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
9195 * @param {String/Object} property The style property to be set, or an object of multiple styles.
9196 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
9197 * @return {Roo.Element} this
9199 setStyle : function(prop, value){
9200 if(typeof prop == "string"){
9202 if (prop == 'float') {
9203 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
9208 if(!(camel = propCache[prop])){
9209 camel = propCache[prop] = prop.replace(camelRe, camelFn);
9212 if(camel == 'opacity') {
9213 this.setOpacity(value);
9215 this.dom.style[camel] = value;
9218 for(var style in prop){
9219 if(typeof prop[style] != "function"){
9220 this.setStyle(style, prop[style]);
9228 * More flexible version of {@link #setStyle} for setting style properties.
9229 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
9230 * a function which returns such a specification.
9231 * @return {Roo.Element} this
9233 applyStyles : function(style){
9234 Roo.DomHelper.applyStyles(this.dom, style);
9239 * 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).
9240 * @return {Number} The X position of the element
9243 return D.getX(this.dom);
9247 * 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).
9248 * @return {Number} The Y position of the element
9251 return D.getY(this.dom);
9255 * 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).
9256 * @return {Array} The XY position of the element
9259 return D.getXY(this.dom);
9263 * 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).
9264 * @param {Number} The X position of the element
9265 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9266 * @return {Roo.Element} this
9268 setX : function(x, animate){
9270 D.setX(this.dom, x);
9272 this.setXY([x, this.getY()], this.preanim(arguments, 1));
9278 * 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).
9279 * @param {Number} The Y position of the element
9280 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9281 * @return {Roo.Element} this
9283 setY : function(y, animate){
9285 D.setY(this.dom, y);
9287 this.setXY([this.getX(), y], this.preanim(arguments, 1));
9293 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
9294 * @param {String} left The left CSS property value
9295 * @return {Roo.Element} this
9297 setLeft : function(left){
9298 this.setStyle("left", this.addUnits(left));
9303 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
9304 * @param {String} top The top CSS property value
9305 * @return {Roo.Element} this
9307 setTop : function(top){
9308 this.setStyle("top", this.addUnits(top));
9313 * Sets the element's CSS right style.
9314 * @param {String} right The right CSS property value
9315 * @return {Roo.Element} this
9317 setRight : function(right){
9318 this.setStyle("right", this.addUnits(right));
9323 * Sets the element's CSS bottom style.
9324 * @param {String} bottom The bottom CSS property value
9325 * @return {Roo.Element} this
9327 setBottom : function(bottom){
9328 this.setStyle("bottom", this.addUnits(bottom));
9333 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9334 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9335 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
9336 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9337 * @return {Roo.Element} this
9339 setXY : function(pos, animate){
9341 D.setXY(this.dom, pos);
9343 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
9349 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9350 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9351 * @param {Number} x X value for new position (coordinates are page-based)
9352 * @param {Number} y Y value for new position (coordinates are page-based)
9353 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9354 * @return {Roo.Element} this
9356 setLocation : function(x, y, animate){
9357 this.setXY([x, y], this.preanim(arguments, 2));
9362 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9363 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9364 * @param {Number} x X value for new position (coordinates are page-based)
9365 * @param {Number} y Y value for new position (coordinates are page-based)
9366 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9367 * @return {Roo.Element} this
9369 moveTo : function(x, y, animate){
9370 this.setXY([x, y], this.preanim(arguments, 2));
9375 * Returns the region of the given element.
9376 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
9377 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
9379 getRegion : function(){
9380 return D.getRegion(this.dom);
9384 * Returns the offset height of the element
9385 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
9386 * @return {Number} The element's height
9388 getHeight : function(contentHeight){
9389 var h = this.dom.offsetHeight || 0;
9390 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
9394 * Returns the offset width of the element
9395 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
9396 * @return {Number} The element's width
9398 getWidth : function(contentWidth){
9399 var w = this.dom.offsetWidth || 0;
9400 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
9404 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
9405 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
9406 * if a height has not been set using CSS.
9409 getComputedHeight : function(){
9410 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
9412 h = parseInt(this.getStyle('height'), 10) || 0;
9413 if(!this.isBorderBox()){
9414 h += this.getFrameWidth('tb');
9421 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
9422 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
9423 * if a width has not been set using CSS.
9426 getComputedWidth : function(){
9427 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
9429 w = parseInt(this.getStyle('width'), 10) || 0;
9430 if(!this.isBorderBox()){
9431 w += this.getFrameWidth('lr');
9438 * Returns the size of the element.
9439 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
9440 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
9442 getSize : function(contentSize){
9443 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
9447 * Returns the width and height of the viewport.
9448 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
9450 getViewSize : function(){
9451 var d = this.dom, doc = document, aw = 0, ah = 0;
9452 if(d == doc || d == doc.body){
9453 return {width : D.getViewWidth(), height: D.getViewHeight()};
9456 width : d.clientWidth,
9457 height: d.clientHeight
9463 * Returns the value of the "value" attribute
9464 * @param {Boolean} asNumber true to parse the value as a number
9465 * @return {String/Number}
9467 getValue : function(asNumber){
9468 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
9472 adjustWidth : function(width){
9473 if(typeof width == "number"){
9474 if(this.autoBoxAdjust && !this.isBorderBox()){
9475 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9485 adjustHeight : function(height){
9486 if(typeof height == "number"){
9487 if(this.autoBoxAdjust && !this.isBorderBox()){
9488 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9498 * Set the width of the element
9499 * @param {Number} width The new width
9500 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9501 * @return {Roo.Element} this
9503 setWidth : function(width, animate){
9504 width = this.adjustWidth(width);
9506 this.dom.style.width = this.addUnits(width);
9508 this.anim({width: {to: width}}, this.preanim(arguments, 1));
9514 * Set the height of the element
9515 * @param {Number} height The new height
9516 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9517 * @return {Roo.Element} this
9519 setHeight : function(height, animate){
9520 height = this.adjustHeight(height);
9522 this.dom.style.height = this.addUnits(height);
9524 this.anim({height: {to: height}}, this.preanim(arguments, 1));
9530 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
9531 * @param {Number} width The new width
9532 * @param {Number} height The new height
9533 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9534 * @return {Roo.Element} this
9536 setSize : function(width, height, animate){
9537 if(typeof width == "object"){ // in case of object from getSize()
9538 height = width.height; width = width.width;
9540 width = this.adjustWidth(width); height = this.adjustHeight(height);
9542 this.dom.style.width = this.addUnits(width);
9543 this.dom.style.height = this.addUnits(height);
9545 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
9551 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
9552 * @param {Number} x X value for new position (coordinates are page-based)
9553 * @param {Number} y Y value for new position (coordinates are page-based)
9554 * @param {Number} width The new width
9555 * @param {Number} height The new height
9556 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9557 * @return {Roo.Element} this
9559 setBounds : function(x, y, width, height, animate){
9561 this.setSize(width, height);
9562 this.setLocation(x, y);
9564 width = this.adjustWidth(width); height = this.adjustHeight(height);
9565 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
9566 this.preanim(arguments, 4), 'motion');
9572 * 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.
9573 * @param {Roo.lib.Region} region The region to fill
9574 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9575 * @return {Roo.Element} this
9577 setRegion : function(region, animate){
9578 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
9583 * Appends an event handler
9585 * @param {String} eventName The type of event to append
9586 * @param {Function} fn The method the event invokes
9587 * @param {Object} scope (optional) The scope (this object) of the fn
9588 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9590 addListener : function(eventName, fn, scope, options)
9592 if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
9593 this.addListener('touchstart', this.onTapHandler, this);
9596 // we need to handle a special case where dom element is a svg element.
9597 // in this case we do not actua
9602 if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
9603 if (typeof(this.listeners[eventName]) == 'undefined') {
9604 this.listeners[eventName] = new Roo.util.Event(this, eventName);
9606 this.listeners[eventName].addListener(fn, scope, options);
9611 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
9616 onTapHandler : function(event)
9618 if(!this.tapedTwice) {
9619 this.tapedTwice = true;
9621 setTimeout( function() {
9622 s.tapedTwice = false;
9626 event.preventDefault();
9627 var revent = new MouseEvent('dblclick', {
9633 this.dom.dispatchEvent(revent);
9634 //action on double tap goes below
9639 * Removes an event handler from this element
9640 * @param {String} eventName the type of event to remove
9641 * @param {Function} fn the method the event invokes
9642 * @param {Function} scope (needed for svg fake listeners)
9643 * @return {Roo.Element} this
9645 removeListener : function(eventName, fn, scope){
9646 Roo.EventManager.removeListener(this.dom, eventName, fn);
9647 if (typeof(this.listeners) == 'undefined' || typeof(this.listeners[eventName]) == 'undefined') {
9650 this.listeners[eventName].removeListener(fn, scope);
9655 * Removes all previous added listeners from this element
9656 * @return {Roo.Element} this
9658 removeAllListeners : function(){
9659 E.purgeElement(this.dom);
9660 this.listeners = {};
9664 relayEvent : function(eventName, observable){
9665 this.on(eventName, function(e){
9666 observable.fireEvent(eventName, e);
9672 * Set the opacity of the element
9673 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
9674 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9675 * @return {Roo.Element} this
9677 setOpacity : function(opacity, animate){
9679 var s = this.dom.style;
9682 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
9683 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
9685 s.opacity = opacity;
9688 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
9694 * Gets the left X coordinate
9695 * @param {Boolean} local True to get the local css position instead of page coordinate
9698 getLeft : function(local){
9702 return parseInt(this.getStyle("left"), 10) || 0;
9707 * Gets the right X coordinate of the element (element X position + element width)
9708 * @param {Boolean} local True to get the local css position instead of page coordinate
9711 getRight : function(local){
9713 return this.getX() + this.getWidth();
9715 return (this.getLeft(true) + this.getWidth()) || 0;
9720 * Gets the top Y coordinate
9721 * @param {Boolean} local True to get the local css position instead of page coordinate
9724 getTop : function(local) {
9728 return parseInt(this.getStyle("top"), 10) || 0;
9733 * Gets the bottom Y coordinate of the element (element Y position + element height)
9734 * @param {Boolean} local True to get the local css position instead of page coordinate
9737 getBottom : function(local){
9739 return this.getY() + this.getHeight();
9741 return (this.getTop(true) + this.getHeight()) || 0;
9746 * Initializes positioning on this element. If a desired position is not passed, it will make the
9747 * the element positioned relative IF it is not already positioned.
9748 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
9749 * @param {Number} zIndex (optional) The zIndex to apply
9750 * @param {Number} x (optional) Set the page X position
9751 * @param {Number} y (optional) Set the page Y position
9753 position : function(pos, zIndex, x, y){
9755 if(this.getStyle('position') == 'static'){
9756 this.setStyle('position', 'relative');
9759 this.setStyle("position", pos);
9762 this.setStyle("z-index", zIndex);
9764 if(x !== undefined && y !== undefined){
9766 }else if(x !== undefined){
9768 }else if(y !== undefined){
9774 * Clear positioning back to the default when the document was loaded
9775 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
9776 * @return {Roo.Element} this
9778 clearPositioning : function(value){
9786 "position" : "static"
9792 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
9793 * snapshot before performing an update and then restoring the element.
9796 getPositioning : function(){
9797 var l = this.getStyle("left");
9798 var t = this.getStyle("top");
9800 "position" : this.getStyle("position"),
9802 "right" : l ? "" : this.getStyle("right"),
9804 "bottom" : t ? "" : this.getStyle("bottom"),
9805 "z-index" : this.getStyle("z-index")
9810 * Gets the width of the border(s) for the specified side(s)
9811 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9812 * passing lr would get the border (l)eft width + the border (r)ight width.
9813 * @return {Number} The width of the sides passed added together
9815 getBorderWidth : function(side){
9816 return this.addStyles(side, El.borders);
9820 * Gets the width of the padding(s) for the specified side(s)
9821 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9822 * passing lr would get the padding (l)eft + the padding (r)ight.
9823 * @return {Number} The padding of the sides passed added together
9825 getPadding : function(side){
9826 return this.addStyles(side, El.paddings);
9830 * Set positioning with an object returned by getPositioning().
9831 * @param {Object} posCfg
9832 * @return {Roo.Element} this
9834 setPositioning : function(pc){
9835 this.applyStyles(pc);
9836 if(pc.right == "auto"){
9837 this.dom.style.right = "";
9839 if(pc.bottom == "auto"){
9840 this.dom.style.bottom = "";
9846 fixDisplay : function(){
9847 if(this.getStyle("display") == "none"){
9848 this.setStyle("visibility", "hidden");
9849 this.setStyle("display", this.originalDisplay); // first try reverting to default
9850 if(this.getStyle("display") == "none"){ // if that fails, default to block
9851 this.setStyle("display", "block");
9857 * Quick set left and top adding default units
9858 * @param {String} left The left CSS property value
9859 * @param {String} top The top CSS property value
9860 * @return {Roo.Element} this
9862 setLeftTop : function(left, top){
9863 this.dom.style.left = this.addUnits(left);
9864 this.dom.style.top = this.addUnits(top);
9869 * Move this element relative to its current position.
9870 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9871 * @param {Number} distance How far to move the element in pixels
9872 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9873 * @return {Roo.Element} this
9875 move : function(direction, distance, animate){
9876 var xy = this.getXY();
9877 direction = direction.toLowerCase();
9881 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
9885 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
9890 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
9895 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
9902 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
9903 * @return {Roo.Element} this
9906 if(!this.isClipped){
9907 this.isClipped = true;
9908 this.originalClip = {
9909 "o": this.getStyle("overflow"),
9910 "x": this.getStyle("overflow-x"),
9911 "y": this.getStyle("overflow-y")
9913 this.setStyle("overflow", "hidden");
9914 this.setStyle("overflow-x", "hidden");
9915 this.setStyle("overflow-y", "hidden");
9921 * Return clipping (overflow) to original clipping before clip() was called
9922 * @return {Roo.Element} this
9924 unclip : function(){
9926 this.isClipped = false;
9927 var o = this.originalClip;
9928 if(o.o){this.setStyle("overflow", o.o);}
9929 if(o.x){this.setStyle("overflow-x", o.x);}
9930 if(o.y){this.setStyle("overflow-y", o.y);}
9937 * Gets the x,y coordinates specified by the anchor position on the element.
9938 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
9939 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
9940 * {width: (target width), height: (target height)} (defaults to the element's current size)
9941 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
9942 * @return {Array} [x, y] An array containing the element's x and y coordinates
9944 getAnchorXY : function(anchor, local, s){
9945 //Passing a different size is useful for pre-calculating anchors,
9946 //especially for anchored animations that change the el size.
9948 var w, h, vp = false;
9951 if(d == document.body || d == document){
9953 w = D.getViewWidth(); h = D.getViewHeight();
9955 w = this.getWidth(); h = this.getHeight();
9958 w = s.width; h = s.height;
9960 var x = 0, y = 0, r = Math.round;
9961 switch((anchor || "tl").toLowerCase()){
10003 var sc = this.getScroll();
10004 return [x + sc.left, y + sc.top];
10006 //Add the element's offset xy
10007 var o = this.getXY();
10008 return [x+o[0], y+o[1]];
10012 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
10013 * supported position values.
10014 * @param {String/HTMLElement/Roo.Element} element The element to align to.
10015 * @param {String} position The position to align to.
10016 * @param {Array} offsets (optional) Offset the positioning by [x, y]
10017 * @return {Array} [x, y]
10019 getAlignToXY : function(el, p, o)
10024 throw "Element.alignTo with an element that doesn't exist";
10026 var c = false; //constrain to viewport
10027 var p1 = "", p2 = "";
10032 }else if(p == "?"){
10034 }else if(p.indexOf("-") == -1){
10037 p = p.toLowerCase();
10038 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
10040 throw "Element.alignTo with an invalid alignment " + p;
10042 p1 = m[1]; p2 = m[2]; c = !!m[3];
10044 //Subtract the aligned el's internal xy from the target's offset xy
10045 //plus custom offset to get the aligned el's new offset xy
10046 var a1 = this.getAnchorXY(p1, true);
10047 var a2 = el.getAnchorXY(p2, false);
10048 var x = a2[0] - a1[0] + o[0];
10049 var y = a2[1] - a1[1] + o[1];
10051 //constrain the aligned el to viewport if necessary
10052 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
10053 // 5px of margin for ie
10054 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
10056 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
10057 //perpendicular to the vp border, allow the aligned el to slide on that border,
10058 //otherwise swap the aligned el to the opposite border of the target.
10059 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
10060 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
10061 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t") );
10062 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
10064 var doc = document;
10065 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
10066 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
10068 if((x+w) > dw + scrollX){
10069 x = swapX ? r.left-w : dw+scrollX-w;
10072 x = swapX ? r.right : scrollX;
10074 if((y+h) > dh + scrollY){
10075 y = swapY ? r.top-h : dh+scrollY-h;
10078 y = swapY ? r.bottom : scrollY;
10085 getConstrainToXY : function(){
10086 var os = {top:0, left:0, bottom:0, right: 0};
10088 return function(el, local, offsets, proposedXY){
10090 offsets = offsets ? Roo.applyIf(offsets, os) : os;
10092 var vw, vh, vx = 0, vy = 0;
10093 if(el.dom == document.body || el.dom == document){
10094 vw = Roo.lib.Dom.getViewWidth();
10095 vh = Roo.lib.Dom.getViewHeight();
10097 vw = el.dom.clientWidth;
10098 vh = el.dom.clientHeight;
10100 var vxy = el.getXY();
10106 var s = el.getScroll();
10108 vx += offsets.left + s.left;
10109 vy += offsets.top + s.top;
10111 vw -= offsets.right;
10112 vh -= offsets.bottom;
10117 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
10118 var x = xy[0], y = xy[1];
10119 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
10121 // only move it if it needs it
10124 // first validate right/bottom
10133 // then make sure top/left isn't negative
10142 return moved ? [x, y] : false;
10147 adjustForConstraints : function(xy, parent, offsets){
10148 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
10152 * Aligns this element with another element relative to the specified anchor points. If the other element is the
10153 * document it aligns it to the viewport.
10154 * The position parameter is optional, and can be specified in any one of the following formats:
10156 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
10157 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
10158 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
10159 * deprecated in favor of the newer two anchor syntax below</i>.</li>
10160 * <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
10161 * element's anchor point, and the second value is used as the target's anchor point.</li>
10163 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
10164 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
10165 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
10166 * that specified in order to enforce the viewport constraints.
10167 * Following are all of the supported anchor positions:
10170 ----- -----------------------------
10171 tl The top left corner (default)
10172 t The center of the top edge
10173 tr The top right corner
10174 l The center of the left edge
10175 c In the center of the element
10176 r The center of the right edge
10177 bl The bottom left corner
10178 b The center of the bottom edge
10179 br The bottom right corner
10183 // align el to other-el using the default positioning ("tl-bl", non-constrained)
10184 el.alignTo("other-el");
10186 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
10187 el.alignTo("other-el", "tr?");
10189 // align the bottom right corner of el with the center left edge of other-el
10190 el.alignTo("other-el", "br-l?");
10192 // align the center of el with the bottom left corner of other-el and
10193 // adjust the x position by -6 pixels (and the y position by 0)
10194 el.alignTo("other-el", "c-bl", [-6, 0]);
10196 * @param {String/HTMLElement/Roo.Element} element The element to align to.
10197 * @param {String} position The position to align to.
10198 * @param {Array} offsets (optional) Offset the positioning by [x, y]
10199 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10200 * @return {Roo.Element} this
10202 alignTo : function(element, position, offsets, animate){
10203 var xy = this.getAlignToXY(element, position, offsets);
10204 this.setXY(xy, this.preanim(arguments, 3));
10209 * Anchors an element to another element and realigns it when the window is resized.
10210 * @param {String/HTMLElement/Roo.Element} element The element to align to.
10211 * @param {String} position The position to align to.
10212 * @param {Array} offsets (optional) Offset the positioning by [x, y]
10213 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
10214 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
10215 * is a number, it is used as the buffer delay (defaults to 50ms).
10216 * @param {Function} callback The function to call after the animation finishes
10217 * @return {Roo.Element} this
10219 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
10220 var action = function(){
10221 this.alignTo(el, alignment, offsets, animate);
10222 Roo.callback(callback, this);
10224 Roo.EventManager.onWindowResize(action, this);
10225 var tm = typeof monitorScroll;
10226 if(tm != 'undefined'){
10227 Roo.EventManager.on(window, 'scroll', action, this,
10228 {buffer: tm == 'number' ? monitorScroll : 50});
10230 action.call(this); // align immediately
10234 * Clears any opacity settings from this element. Required in some cases for IE.
10235 * @return {Roo.Element} this
10237 clearOpacity : function(){
10238 if (window.ActiveXObject) {
10239 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
10240 this.dom.style.filter = "";
10243 this.dom.style.opacity = "";
10244 this.dom.style["-moz-opacity"] = "";
10245 this.dom.style["-khtml-opacity"] = "";
10251 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
10252 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10253 * @return {Roo.Element} this
10255 hide : function(animate){
10256 this.setVisible(false, this.preanim(arguments, 0));
10261 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
10262 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10263 * @return {Roo.Element} this
10265 show : function(animate){
10266 this.setVisible(true, this.preanim(arguments, 0));
10271 * @private Test if size has a unit, otherwise appends the default
10273 addUnits : function(size){
10274 return Roo.Element.addUnits(size, this.defaultUnit);
10278 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
10279 * @return {Roo.Element} this
10281 beginMeasure : function(){
10283 if(el.offsetWidth || el.offsetHeight){
10284 return this; // offsets work already
10287 var p = this.dom, b = document.body; // start with this element
10288 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
10289 var pe = Roo.get(p);
10290 if(pe.getStyle('display') == 'none'){
10291 changed.push({el: p, visibility: pe.getStyle("visibility")});
10292 p.style.visibility = "hidden";
10293 p.style.display = "block";
10297 this._measureChanged = changed;
10303 * Restores displays to before beginMeasure was called
10304 * @return {Roo.Element} this
10306 endMeasure : function(){
10307 var changed = this._measureChanged;
10309 for(var i = 0, len = changed.length; i < len; i++) {
10310 var r = changed[i];
10311 r.el.style.visibility = r.visibility;
10312 r.el.style.display = "none";
10314 this._measureChanged = null;
10320 * Update the innerHTML of this element, optionally searching for and processing scripts
10321 * @param {String} html The new HTML
10322 * @param {Boolean} loadScripts (optional) true to look for and process scripts
10323 * @param {Function} callback For async script loading you can be noticed when the update completes
10324 * @return {Roo.Element} this
10326 update : function(html, loadScripts, callback){
10327 if(typeof html == "undefined"){
10330 if(loadScripts !== true){
10331 this.dom.innerHTML = html;
10332 if(typeof callback == "function"){
10338 var dom = this.dom;
10340 html += '<span id="' + id + '"></span>';
10342 E.onAvailable(id, function(){
10343 var hd = document.getElementsByTagName("head")[0];
10344 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
10345 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
10346 var typeRe = /\stype=([\'\"])(.*?)\1/i;
10349 while(match = re.exec(html)){
10350 var attrs = match[1];
10351 var srcMatch = attrs ? attrs.match(srcRe) : false;
10352 if(srcMatch && srcMatch[2]){
10353 var s = document.createElement("script");
10354 s.src = srcMatch[2];
10355 var typeMatch = attrs.match(typeRe);
10356 if(typeMatch && typeMatch[2]){
10357 s.type = typeMatch[2];
10360 }else if(match[2] && match[2].length > 0){
10361 if(window.execScript) {
10362 window.execScript(match[2]);
10370 window.eval(match[2]);
10374 var el = document.getElementById(id);
10375 if(el){el.parentNode.removeChild(el);}
10376 if(typeof callback == "function"){
10380 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
10385 * Direct access to the UpdateManager update() method (takes the same parameters).
10386 * @param {String/Function} url The url for this request or a function to call to get the url
10387 * @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}
10388 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
10389 * @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.
10390 * @return {Roo.Element} this
10393 var um = this.getUpdateManager();
10394 um.update.apply(um, arguments);
10399 * Gets this element's UpdateManager
10400 * @return {Roo.UpdateManager} The UpdateManager
10402 getUpdateManager : function(){
10403 if(!this.updateManager){
10404 this.updateManager = new Roo.UpdateManager(this);
10406 return this.updateManager;
10410 * Disables text selection for this element (normalized across browsers)
10411 * @return {Roo.Element} this
10413 unselectable : function(){
10414 this.dom.unselectable = "on";
10415 this.swallowEvent("selectstart", true);
10416 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
10417 this.addClass("x-unselectable");
10422 * Calculates the x, y to center this element on the screen
10423 * @return {Array} The x, y values [x, y]
10425 getCenterXY : function(){
10426 return this.getAlignToXY(document, 'c-c');
10430 * Centers the Element in either the viewport, or another Element.
10431 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
10433 center : function(centerIn){
10434 this.alignTo(centerIn || document, 'c-c');
10439 * Tests various css rules/browsers to determine if this element uses a border box
10440 * @return {Boolean}
10442 isBorderBox : function(){
10443 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
10447 * Return a box {x, y, width, height} that can be used to set another elements
10448 * size/location to match this element.
10449 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
10450 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
10451 * @return {Object} box An object in the format {x, y, width, height}
10453 getBox : function(contentBox, local){
10458 var left = parseInt(this.getStyle("left"), 10) || 0;
10459 var top = parseInt(this.getStyle("top"), 10) || 0;
10462 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
10464 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
10466 var l = this.getBorderWidth("l")+this.getPadding("l");
10467 var r = this.getBorderWidth("r")+this.getPadding("r");
10468 var t = this.getBorderWidth("t")+this.getPadding("t");
10469 var b = this.getBorderWidth("b")+this.getPadding("b");
10470 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)};
10472 bx.right = bx.x + bx.width;
10473 bx.bottom = bx.y + bx.height;
10478 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
10479 for more information about the sides.
10480 * @param {String} sides
10483 getFrameWidth : function(sides, onlyContentBox){
10484 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
10488 * 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.
10489 * @param {Object} box The box to fill {x, y, width, height}
10490 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
10491 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10492 * @return {Roo.Element} this
10494 setBox : function(box, adjust, animate){
10495 var w = box.width, h = box.height;
10496 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
10497 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
10498 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
10500 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
10505 * Forces the browser to repaint this element
10506 * @return {Roo.Element} this
10508 repaint : function(){
10509 var dom = this.dom;
10510 this.addClass("x-repaint");
10511 setTimeout(function(){
10512 Roo.get(dom).removeClass("x-repaint");
10518 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
10519 * then it returns the calculated width of the sides (see getPadding)
10520 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
10521 * @return {Object/Number}
10523 getMargins : function(side){
10526 top: parseInt(this.getStyle("margin-top"), 10) || 0,
10527 left: parseInt(this.getStyle("margin-left"), 10) || 0,
10528 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
10529 right: parseInt(this.getStyle("margin-right"), 10) || 0
10532 return this.addStyles(side, El.margins);
10537 addStyles : function(sides, styles){
10539 for(var i = 0, len = sides.length; i < len; i++){
10540 v = this.getStyle(styles[sides.charAt(i)]);
10542 w = parseInt(v, 10);
10550 * Creates a proxy element of this element
10551 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
10552 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
10553 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
10554 * @return {Roo.Element} The new proxy element
10556 createProxy : function(config, renderTo, matchBox){
10558 renderTo = Roo.getDom(renderTo);
10560 renderTo = document.body;
10562 config = typeof config == "object" ?
10563 config : {tag : "div", cls: config};
10564 var proxy = Roo.DomHelper.append(renderTo, config, true);
10566 proxy.setBox(this.getBox());
10572 * Puts a mask over this element to disable user interaction. Requires core.css.
10573 * This method can only be applied to elements which accept child nodes.
10574 * @param {String} msg (optional) A message to display in the mask
10575 * @param {String} msgCls (optional) A css class to apply to the msg element - use no-spinner to hide the spinner on bootstrap
10576 * @return {Element} The mask element
10578 mask : function(msg, msgCls)
10580 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
10581 this.setStyle("position", "relative");
10584 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
10587 this.addClass("x-masked");
10588 this._mask.setDisplayed(true);
10592 var dom = this.dom;
10593 while (dom && dom.style) {
10594 if (!isNaN(parseInt(dom.style.zIndex))) {
10595 z = Math.max(z, parseInt(dom.style.zIndex));
10597 dom = dom.parentNode;
10599 // if we are masking the body - then it hides everything..
10600 if (this.dom == document.body) {
10602 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
10603 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
10606 if(typeof msg == 'string'){
10607 if(!this._maskMsg){
10608 this._maskMsg = Roo.DomHelper.append(this.dom, {
10609 cls: "roo-el-mask-msg",
10613 cls: 'fa fa-spinner fa-spin'
10621 var mm = this._maskMsg;
10622 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
10623 if (mm.dom.lastChild) { // weird IE issue?
10624 mm.dom.lastChild.innerHTML = msg;
10626 mm.setDisplayed(true);
10628 mm.setStyle('z-index', z + 102);
10630 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
10631 this._mask.setHeight(this.getHeight());
10633 this._mask.setStyle('z-index', z + 100);
10639 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
10640 * it is cached for reuse.
10642 unmask : function(removeEl){
10644 if(removeEl === true){
10645 this._mask.remove();
10648 this._maskMsg.remove();
10649 delete this._maskMsg;
10652 this._mask.setDisplayed(false);
10654 this._maskMsg.setDisplayed(false);
10658 this.removeClass("x-masked");
10662 * Returns true if this element is masked
10663 * @return {Boolean}
10665 isMasked : function(){
10666 return this._mask && this._mask.isVisible();
10670 * Creates an iframe shim for this element to keep selects and other windowed objects from
10672 * @return {Roo.Element} The new shim element
10674 createShim : function(){
10675 var el = document.createElement('iframe');
10676 el.frameBorder = 'no';
10677 el.className = 'roo-shim';
10678 if(Roo.isIE && Roo.isSecure){
10679 el.src = Roo.SSL_SECURE_URL;
10681 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
10682 shim.autoBoxAdjust = false;
10687 * Removes this element from the DOM and deletes it from the cache
10689 remove : function(){
10690 if(this.dom.parentNode){
10691 this.dom.parentNode.removeChild(this.dom);
10693 delete El.cache[this.dom.id];
10697 * Sets up event handlers to add and remove a css class when the mouse is over this element
10698 * @param {String} className
10699 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
10700 * mouseout events for children elements
10701 * @return {Roo.Element} this
10703 addClassOnOver : function(className, preventFlicker){
10704 this.on("mouseover", function(){
10705 Roo.fly(this, '_internal').addClass(className);
10707 var removeFn = function(e){
10708 if(preventFlicker !== true || !e.within(this, true)){
10709 Roo.fly(this, '_internal').removeClass(className);
10712 this.on("mouseout", removeFn, this.dom);
10717 * Sets up event handlers to add and remove a css class when this element has the focus
10718 * @param {String} className
10719 * @return {Roo.Element} this
10721 addClassOnFocus : function(className){
10722 this.on("focus", function(){
10723 Roo.fly(this, '_internal').addClass(className);
10725 this.on("blur", function(){
10726 Roo.fly(this, '_internal').removeClass(className);
10731 * 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)
10732 * @param {String} className
10733 * @return {Roo.Element} this
10735 addClassOnClick : function(className){
10736 var dom = this.dom;
10737 this.on("mousedown", function(){
10738 Roo.fly(dom, '_internal').addClass(className);
10739 var d = Roo.get(document);
10740 var fn = function(){
10741 Roo.fly(dom, '_internal').removeClass(className);
10742 d.removeListener("mouseup", fn);
10744 d.on("mouseup", fn);
10750 * Stops the specified event from bubbling and optionally prevents the default action
10751 * @param {String} eventName
10752 * @param {Boolean} preventDefault (optional) true to prevent the default action too
10753 * @return {Roo.Element} this
10755 swallowEvent : function(eventName, preventDefault){
10756 var fn = function(e){
10757 e.stopPropagation();
10758 if(preventDefault){
10759 e.preventDefault();
10762 if(eventName instanceof Array){
10763 for(var i = 0, len = eventName.length; i < len; i++){
10764 this.on(eventName[i], fn);
10768 this.on(eventName, fn);
10775 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
10778 * Sizes this element to its parent element's dimensions performing
10779 * neccessary box adjustments.
10780 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
10781 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
10782 * @return {Roo.Element} this
10784 fitToParent : function(monitorResize, targetParent) {
10785 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
10786 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
10787 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
10790 var p = Roo.get(targetParent || this.dom.parentNode);
10791 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
10792 if (monitorResize === true) {
10793 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
10794 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
10800 * Gets the next sibling, skipping text nodes
10801 * @return {HTMLElement} The next sibling or null
10803 getNextSibling : function(){
10804 var n = this.dom.nextSibling;
10805 while(n && n.nodeType != 1){
10812 * Gets the previous sibling, skipping text nodes
10813 * @return {HTMLElement} The previous sibling or null
10815 getPrevSibling : function(){
10816 var n = this.dom.previousSibling;
10817 while(n && n.nodeType != 1){
10818 n = n.previousSibling;
10825 * Appends the passed element(s) to this element
10826 * @param {String/HTMLElement/Array/Element/CompositeElement} el
10827 * @return {Roo.Element} this
10829 appendChild: function(el){
10836 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
10837 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
10838 * automatically generated with the specified attributes.
10839 * @param {HTMLElement} insertBefore (optional) a child element of this element
10840 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
10841 * @return {Roo.Element} The new child element
10843 createChild: function(config, insertBefore, returnDom){
10844 config = config || {tag:'div'};
10846 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
10848 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
10852 * Appends this element to the passed element
10853 * @param {String/HTMLElement/Element} el The new parent element
10854 * @return {Roo.Element} this
10856 appendTo: function(el){
10857 el = Roo.getDom(el);
10858 el.appendChild(this.dom);
10863 * Inserts this element before the passed element in the DOM
10864 * @param {String/HTMLElement/Element} el The element to insert before
10865 * @return {Roo.Element} this
10867 insertBefore: function(el){
10868 el = Roo.getDom(el);
10869 el.parentNode.insertBefore(this.dom, el);
10874 * Inserts this element after the passed element in the DOM
10875 * @param {String/HTMLElement/Element} el The element to insert after
10876 * @return {Roo.Element} this
10878 insertAfter: function(el){
10879 el = Roo.getDom(el);
10880 el.parentNode.insertBefore(this.dom, el.nextSibling);
10885 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
10886 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10887 * @return {Roo.Element} The new child
10889 insertFirst: function(el, returnDom){
10891 if(typeof el == 'object' && !el.nodeType){ // dh config
10892 return this.createChild(el, this.dom.firstChild, returnDom);
10894 el = Roo.getDom(el);
10895 this.dom.insertBefore(el, this.dom.firstChild);
10896 return !returnDom ? Roo.get(el) : el;
10901 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
10902 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10903 * @param {String} where (optional) 'before' or 'after' defaults to before
10904 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10905 * @return {Roo.Element} the inserted Element
10907 insertSibling: function(el, where, returnDom){
10908 where = where ? where.toLowerCase() : 'before';
10910 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
10912 if(typeof el == 'object' && !el.nodeType){ // dh config
10913 if(where == 'after' && !this.dom.nextSibling){
10914 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
10916 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
10920 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
10921 where == 'before' ? this.dom : this.dom.nextSibling);
10930 * Creates and wraps this element with another element
10931 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
10932 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10933 * @return {HTMLElement/Element} The newly created wrapper element
10935 wrap: function(config, returnDom){
10937 config = {tag: "div"};
10939 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
10940 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
10945 * Replaces the passed element with this element
10946 * @param {String/HTMLElement/Element} el The element to replace
10947 * @return {Roo.Element} this
10949 replace: function(el){
10951 this.insertBefore(el);
10957 * Inserts an html fragment into this element
10958 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
10959 * @param {String} html The HTML fragment
10960 * @param {Boolean} returnEl True to return an Roo.Element
10961 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
10963 insertHtml : function(where, html, returnEl){
10964 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
10965 return returnEl ? Roo.get(el) : el;
10969 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
10970 * @param {Object} o The object with the attributes
10971 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
10972 * @return {Roo.Element} this
10974 set : function(o, useSet){
10976 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
10977 for(var attr in o){
10978 if(attr == "style" || typeof o[attr] == "function") { continue; }
10980 el.className = o["cls"];
10983 el.setAttribute(attr, o[attr]);
10985 el[attr] = o[attr];
10990 Roo.DomHelper.applyStyles(el, o.style);
10996 * Convenience method for constructing a KeyMap
10997 * @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:
10998 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
10999 * @param {Function} fn The function to call
11000 * @param {Object} scope (optional) The scope of the function
11001 * @return {Roo.KeyMap} The KeyMap created
11003 addKeyListener : function(key, fn, scope){
11005 if(typeof key != "object" || key instanceof Array){
11021 return new Roo.KeyMap(this, config);
11025 * Creates a KeyMap for this element
11026 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
11027 * @return {Roo.KeyMap} The KeyMap created
11029 addKeyMap : function(config){
11030 return new Roo.KeyMap(this, config);
11034 * Returns true if this element is scrollable.
11035 * @return {Boolean}
11037 isScrollable : function(){
11038 var dom = this.dom;
11039 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
11043 * 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().
11044 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
11045 * @param {Number} value The new scroll value
11046 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
11047 * @return {Element} this
11050 scrollTo : function(side, value, animate){
11051 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
11052 if(!animate || !A){
11053 this.dom[prop] = value;
11055 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
11056 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
11062 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
11063 * within this element's scrollable range.
11064 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
11065 * @param {Number} distance How far to scroll the element in pixels
11066 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
11067 * @return {Boolean} Returns true if a scroll was triggered or false if the element
11068 * was scrolled as far as it could go.
11070 scroll : function(direction, distance, animate){
11071 if(!this.isScrollable()){
11075 var l = el.scrollLeft, t = el.scrollTop;
11076 var w = el.scrollWidth, h = el.scrollHeight;
11077 var cw = el.clientWidth, ch = el.clientHeight;
11078 direction = direction.toLowerCase();
11079 var scrolled = false;
11080 var a = this.preanim(arguments, 2);
11085 var v = Math.min(l + distance, w-cw);
11086 this.scrollTo("left", v, a);
11093 var v = Math.max(l - distance, 0);
11094 this.scrollTo("left", v, a);
11102 var v = Math.max(t - distance, 0);
11103 this.scrollTo("top", v, a);
11111 var v = Math.min(t + distance, h-ch);
11112 this.scrollTo("top", v, a);
11121 * Translates the passed page coordinates into left/top css values for this element
11122 * @param {Number/Array} x The page x or an array containing [x, y]
11123 * @param {Number} y The page y
11124 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
11126 translatePoints : function(x, y){
11127 if(typeof x == 'object' || x instanceof Array){
11128 y = x[1]; x = x[0];
11130 var p = this.getStyle('position');
11131 var o = this.getXY();
11133 var l = parseInt(this.getStyle('left'), 10);
11134 var t = parseInt(this.getStyle('top'), 10);
11137 l = (p == "relative") ? 0 : this.dom.offsetLeft;
11140 t = (p == "relative") ? 0 : this.dom.offsetTop;
11143 return {left: (x - o[0] + l), top: (y - o[1] + t)};
11147 * Returns the current scroll position of the element.
11148 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
11150 getScroll : function(){
11151 var d = this.dom, doc = document;
11152 if(d == doc || d == doc.body){
11153 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
11154 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
11155 return {left: l, top: t};
11157 return {left: d.scrollLeft, top: d.scrollTop};
11162 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
11163 * are convert to standard 6 digit hex color.
11164 * @param {String} attr The css attribute
11165 * @param {String} defaultValue The default value to use when a valid color isn't found
11166 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
11169 getColor : function(attr, defaultValue, prefix){
11170 var v = this.getStyle(attr);
11171 if(!v || v == "transparent" || v == "inherit") {
11172 return defaultValue;
11174 var color = typeof prefix == "undefined" ? "#" : prefix;
11175 if(v.substr(0, 4) == "rgb("){
11176 var rvs = v.slice(4, v.length -1).split(",");
11177 for(var i = 0; i < 3; i++){
11178 var h = parseInt(rvs[i]).toString(16);
11185 if(v.substr(0, 1) == "#"){
11186 if(v.length == 4) {
11187 for(var i = 1; i < 4; i++){
11188 var c = v.charAt(i);
11191 }else if(v.length == 7){
11192 color += v.substr(1);
11196 return(color.length > 5 ? color.toLowerCase() : defaultValue);
11200 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
11201 * gradient background, rounded corners and a 4-way shadow.
11202 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
11203 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
11204 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
11205 * @return {Roo.Element} this
11207 boxWrap : function(cls){
11208 cls = cls || 'x-box';
11209 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
11210 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
11215 * Returns the value of a namespaced attribute from the element's underlying DOM node.
11216 * @param {String} namespace The namespace in which to look for the attribute
11217 * @param {String} name The attribute name
11218 * @return {String} The attribute value
11220 getAttributeNS : Roo.isIE ? function(ns, name){
11222 var type = typeof d[ns+":"+name];
11223 if(type != 'undefined' && type != 'unknown'){
11224 return d[ns+":"+name];
11227 } : function(ns, name){
11229 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
11234 * Sets or Returns the value the dom attribute value
11235 * @param {String|Object} name The attribute name (or object to set multiple attributes)
11236 * @param {String} value (optional) The value to set the attribute to
11237 * @return {String} The attribute value
11239 attr : function(name){
11240 if (arguments.length > 1) {
11241 this.dom.setAttribute(name, arguments[1]);
11242 return arguments[1];
11244 if (typeof(name) == 'object') {
11245 for(var i in name) {
11246 this.attr(i, name[i]);
11252 if (!this.dom.hasAttribute(name)) {
11255 return this.dom.getAttribute(name);
11262 var ep = El.prototype;
11265 * Appends an event handler (Shorthand for addListener)
11266 * @param {String} eventName The type of event to append
11267 * @param {Function} fn The method the event invokes
11268 * @param {Object} scope (optional) The scope (this object) of the fn
11269 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
11272 ep.on = ep.addListener;
11273 // backwards compat
11274 ep.mon = ep.addListener;
11277 * Removes an event handler from this element (shorthand for removeListener)
11278 * @param {String} eventName the type of event to remove
11279 * @param {Function} fn the method the event invokes
11280 * @return {Roo.Element} this
11283 ep.un = ep.removeListener;
11286 * true to automatically adjust width and height settings for box-model issues (default to true)
11288 ep.autoBoxAdjust = true;
11291 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
11294 El.addUnits = function(v, defaultUnit){
11295 if(v === "" || v == "auto"){
11298 if(v === undefined){
11301 if(typeof v == "number" || !El.unitPattern.test(v)){
11302 return v + (defaultUnit || 'px');
11307 // special markup used throughout Roo when box wrapping elements
11308 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>';
11310 * Visibility mode constant - Use visibility to hide element
11316 * Visibility mode constant - Use display to hide element
11322 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
11323 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
11324 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
11336 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
11337 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
11338 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
11339 * @return {Element} The Element object
11342 El.get = function(el){
11344 if(!el){ return null; }
11345 if(typeof el == "string"){ // element id
11346 if(!(elm = document.getElementById(el))){
11349 if(ex = El.cache[el]){
11352 ex = El.cache[el] = new El(elm);
11355 }else if(el.tagName){ // dom element
11359 if(ex = El.cache[id]){
11362 ex = El.cache[id] = new El(el);
11365 }else if(el instanceof El){
11367 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
11368 // catch case where it hasn't been appended
11369 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
11372 }else if(el.isComposite){
11374 }else if(el instanceof Array){
11375 return El.select(el);
11376 }else if(el == document){
11377 // create a bogus element object representing the document object
11379 var f = function(){};
11380 f.prototype = El.prototype;
11382 docEl.dom = document;
11390 El.uncache = function(el){
11391 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
11393 delete El.cache[a[i].id || a[i]];
11399 // Garbage collection - uncache elements/purge listeners on orphaned elements
11400 // so we don't hold a reference and cause the browser to retain them
11401 El.garbageCollect = function(){
11402 if(!Roo.enableGarbageCollector){
11403 clearInterval(El.collectorThread);
11406 for(var eid in El.cache){
11407 var el = El.cache[eid], d = el.dom;
11408 // -------------------------------------------------------
11409 // Determining what is garbage:
11410 // -------------------------------------------------------
11412 // dom node is null, definitely garbage
11413 // -------------------------------------------------------
11415 // no parentNode == direct orphan, definitely garbage
11416 // -------------------------------------------------------
11417 // !d.offsetParent && !document.getElementById(eid)
11418 // display none elements have no offsetParent so we will
11419 // also try to look it up by it's id. However, check
11420 // offsetParent first so we don't do unneeded lookups.
11421 // This enables collection of elements that are not orphans
11422 // directly, but somewhere up the line they have an orphan
11424 // -------------------------------------------------------
11425 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
11426 delete El.cache[eid];
11427 if(d && Roo.enableListenerCollection){
11433 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
11437 El.Flyweight = function(dom){
11440 El.Flyweight.prototype = El.prototype;
11442 El._flyweights = {};
11444 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
11445 * the dom node can be overwritten by other code.
11446 * @param {String/HTMLElement} el The dom node or id
11447 * @param {String} named (optional) Allows for creation of named reusable flyweights to
11448 * prevent conflicts (e.g. internally Roo uses "_internal")
11450 * @return {Element} The shared Element object
11452 El.fly = function(el, named){
11453 named = named || '_global';
11454 el = Roo.getDom(el);
11458 if(!El._flyweights[named]){
11459 El._flyweights[named] = new El.Flyweight();
11461 El._flyweights[named].dom = el;
11462 return El._flyweights[named];
11466 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
11467 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
11468 * Shorthand of {@link Roo.Element#get}
11469 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
11470 * @return {Element} The Element object
11476 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
11477 * the dom node can be overwritten by other code.
11478 * Shorthand of {@link Roo.Element#fly}
11479 * @param {String/HTMLElement} el The dom node or id
11480 * @param {String} named (optional) Allows for creation of named reusable flyweights to
11481 * prevent conflicts (e.g. internally Roo uses "_internal")
11483 * @return {Element} The shared Element object
11489 // speedy lookup for elements never to box adjust
11490 var noBoxAdjust = Roo.isStrict ? {
11493 input:1, select:1, textarea:1
11495 if(Roo.isIE || Roo.isGecko){
11496 noBoxAdjust['button'] = 1;
11500 Roo.EventManager.on(window, 'unload', function(){
11502 delete El._flyweights;
11510 Roo.Element.selectorFunction = Roo.DomQuery.select;
11513 Roo.Element.select = function(selector, unique, root){
11515 if(typeof selector == "string"){
11516 els = Roo.Element.selectorFunction(selector, root);
11517 }else if(selector.length !== undefined){
11520 throw "Invalid selector";
11522 if(unique === true){
11523 return new Roo.CompositeElement(els);
11525 return new Roo.CompositeElementLite(els);
11529 * Selects elements based on the passed CSS selector to enable working on them as 1.
11530 * @param {String/Array} selector The CSS selector or an array of elements
11531 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
11532 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
11533 * @return {CompositeElementLite/CompositeElement}
11537 Roo.select = Roo.Element.select;
11554 * Ext JS Library 1.1.1
11555 * Copyright(c) 2006-2007, Ext JS, LLC.
11557 * Originally Released Under LGPL - original licence link has changed is not relivant.
11560 * <script type="text/javascript">
11565 //Notifies Element that fx methods are available
11566 Roo.enableFx = true;
11570 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
11571 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
11572 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
11573 * Element effects to work.</p><br/>
11575 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
11576 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
11577 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
11578 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
11579 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
11580 * expected results and should be done with care.</p><br/>
11582 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
11583 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
11586 ----- -----------------------------
11587 tl The top left corner
11588 t The center of the top edge
11589 tr The top right corner
11590 l The center of the left edge
11591 r The center of the right edge
11592 bl The bottom left corner
11593 b The center of the bottom edge
11594 br The bottom right corner
11596 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
11597 * below are common options that can be passed to any Fx method.</b>
11598 * @cfg {Function} callback A function called when the effect is finished
11599 * @cfg {Object} scope The scope of the effect function
11600 * @cfg {String} easing A valid Easing value for the effect
11601 * @cfg {String} afterCls A css class to apply after the effect
11602 * @cfg {Number} duration The length of time (in seconds) that the effect should last
11603 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
11604 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
11605 * effects that end with the element being visually hidden, ignored otherwise)
11606 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
11607 * a function which returns such a specification that will be applied to the Element after the effect finishes
11608 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
11609 * @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
11610 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
11614 * Slides the element into view. An anchor point can be optionally passed to set the point of
11615 * origin for the slide effect. This function automatically handles wrapping the element with
11616 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
11619 // default: slide the element in from the top
11622 // custom: slide the element in from the right with a 2-second duration
11623 el.slideIn('r', { duration: 2 });
11625 // common config options shown with default values
11631 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11632 * @param {Object} options (optional) Object literal with any of the Fx config options
11633 * @return {Roo.Element} The Element
11635 slideIn : function(anchor, o){
11636 var el = this.getFxEl();
11639 el.queueFx(o, function(){
11641 anchor = anchor || "t";
11643 // fix display to visibility
11646 // restore values after effect
11647 var r = this.getFxRestore();
11648 var b = this.getBox();
11649 // fixed size for slide
11653 var wrap = this.fxWrap(r.pos, o, "hidden");
11655 var st = this.dom.style;
11656 st.visibility = "visible";
11657 st.position = "absolute";
11659 // clear out temp styles after slide and unwrap
11660 var after = function(){
11661 el.fxUnwrap(wrap, r.pos, o);
11662 st.width = r.width;
11663 st.height = r.height;
11666 // time to calc the positions
11667 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
11669 switch(anchor.toLowerCase()){
11671 wrap.setSize(b.width, 0);
11672 st.left = st.bottom = "0";
11676 wrap.setSize(0, b.height);
11677 st.right = st.top = "0";
11681 wrap.setSize(0, b.height);
11682 wrap.setX(b.right);
11683 st.left = st.top = "0";
11684 a = {width: bw, points: pt};
11687 wrap.setSize(b.width, 0);
11688 wrap.setY(b.bottom);
11689 st.left = st.top = "0";
11690 a = {height: bh, points: pt};
11693 wrap.setSize(0, 0);
11694 st.right = st.bottom = "0";
11695 a = {width: bw, height: bh};
11698 wrap.setSize(0, 0);
11699 wrap.setY(b.y+b.height);
11700 st.right = st.top = "0";
11701 a = {width: bw, height: bh, points: pt};
11704 wrap.setSize(0, 0);
11705 wrap.setXY([b.right, b.bottom]);
11706 st.left = st.top = "0";
11707 a = {width: bw, height: bh, points: pt};
11710 wrap.setSize(0, 0);
11711 wrap.setX(b.x+b.width);
11712 st.left = st.bottom = "0";
11713 a = {width: bw, height: bh, points: pt};
11716 this.dom.style.visibility = "visible";
11719 arguments.callee.anim = wrap.fxanim(a,
11729 * Slides the element out of view. An anchor point can be optionally passed to set the end point
11730 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
11731 * 'hidden') but block elements will still take up space in the document. The element must be removed
11732 * from the DOM using the 'remove' config option if desired. This function automatically handles
11733 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
11736 // default: slide the element out to the top
11739 // custom: slide the element out to the right with a 2-second duration
11740 el.slideOut('r', { duration: 2 });
11742 // common config options shown with default values
11750 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11751 * @param {Object} options (optional) Object literal with any of the Fx config options
11752 * @return {Roo.Element} The Element
11754 slideOut : function(anchor, o){
11755 var el = this.getFxEl();
11758 el.queueFx(o, function(){
11760 anchor = anchor || "t";
11762 // restore values after effect
11763 var r = this.getFxRestore();
11765 var b = this.getBox();
11766 // fixed size for slide
11770 var wrap = this.fxWrap(r.pos, o, "visible");
11772 var st = this.dom.style;
11773 st.visibility = "visible";
11774 st.position = "absolute";
11778 var after = function(){
11780 el.setDisplayed(false);
11785 el.fxUnwrap(wrap, r.pos, o);
11787 st.width = r.width;
11788 st.height = r.height;
11793 var a, zero = {to: 0};
11794 switch(anchor.toLowerCase()){
11796 st.left = st.bottom = "0";
11797 a = {height: zero};
11800 st.right = st.top = "0";
11804 st.left = st.top = "0";
11805 a = {width: zero, points: {to:[b.right, b.y]}};
11808 st.left = st.top = "0";
11809 a = {height: zero, points: {to:[b.x, b.bottom]}};
11812 st.right = st.bottom = "0";
11813 a = {width: zero, height: zero};
11816 st.right = st.top = "0";
11817 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
11820 st.left = st.top = "0";
11821 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
11824 st.left = st.bottom = "0";
11825 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
11829 arguments.callee.anim = wrap.fxanim(a,
11839 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
11840 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
11841 * The element must be removed from the DOM using the 'remove' config option if desired.
11847 // common config options shown with default values
11855 * @param {Object} options (optional) Object literal with any of the Fx config options
11856 * @return {Roo.Element} The Element
11858 puff : function(o){
11859 var el = this.getFxEl();
11862 el.queueFx(o, function(){
11863 this.clearOpacity();
11866 // restore values after effect
11867 var r = this.getFxRestore();
11868 var st = this.dom.style;
11870 var after = function(){
11872 el.setDisplayed(false);
11879 el.setPositioning(r.pos);
11880 st.width = r.width;
11881 st.height = r.height;
11886 var width = this.getWidth();
11887 var height = this.getHeight();
11889 arguments.callee.anim = this.fxanim({
11890 width : {to: this.adjustWidth(width * 2)},
11891 height : {to: this.adjustHeight(height * 2)},
11892 points : {by: [-(width * .5), -(height * .5)]},
11894 fontSize: {to:200, unit: "%"}
11905 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
11906 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
11907 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
11913 // all config options shown with default values
11921 * @param {Object} options (optional) Object literal with any of the Fx config options
11922 * @return {Roo.Element} The Element
11924 switchOff : function(o){
11925 var el = this.getFxEl();
11928 el.queueFx(o, function(){
11929 this.clearOpacity();
11932 // restore values after effect
11933 var r = this.getFxRestore();
11934 var st = this.dom.style;
11936 var after = function(){
11938 el.setDisplayed(false);
11944 el.setPositioning(r.pos);
11945 st.width = r.width;
11946 st.height = r.height;
11951 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
11952 this.clearOpacity();
11956 points:{by:[0, this.getHeight() * .5]}
11957 }, o, 'motion', 0.3, 'easeIn', after);
11958 }).defer(100, this);
11965 * Highlights the Element by setting a color (applies to the background-color by default, but can be
11966 * changed using the "attr" config option) and then fading back to the original color. If no original
11967 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
11970 // default: highlight background to yellow
11973 // custom: highlight foreground text to blue for 2 seconds
11974 el.highlight("0000ff", { attr: 'color', duration: 2 });
11976 // common config options shown with default values
11977 el.highlight("ffff9c", {
11978 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
11979 endColor: (current color) or "ffffff",
11984 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
11985 * @param {Object} options (optional) Object literal with any of the Fx config options
11986 * @return {Roo.Element} The Element
11988 highlight : function(color, o){
11989 var el = this.getFxEl();
11992 el.queueFx(o, function(){
11993 color = color || "ffff9c";
11994 attr = o.attr || "backgroundColor";
11996 this.clearOpacity();
11999 var origColor = this.getColor(attr);
12000 var restoreColor = this.dom.style[attr];
12001 endColor = (o.endColor || origColor) || "ffffff";
12003 var after = function(){
12004 el.dom.style[attr] = restoreColor;
12009 a[attr] = {from: color, to: endColor};
12010 arguments.callee.anim = this.fxanim(a,
12020 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
12023 // default: a single light blue ripple
12026 // custom: 3 red ripples lasting 3 seconds total
12027 el.frame("ff0000", 3, { duration: 3 });
12029 // common config options shown with default values
12030 el.frame("C3DAF9", 1, {
12031 duration: 1 //duration of entire animation (not each individual ripple)
12032 // Note: Easing is not configurable and will be ignored if included
12035 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
12036 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
12037 * @param {Object} options (optional) Object literal with any of the Fx config options
12038 * @return {Roo.Element} The Element
12040 frame : function(color, count, o){
12041 var el = this.getFxEl();
12044 el.queueFx(o, function(){
12045 color = color || "#C3DAF9";
12046 if(color.length == 6){
12047 color = "#" + color;
12049 count = count || 1;
12050 duration = o.duration || 1;
12053 var b = this.getBox();
12054 var animFn = function(){
12055 var proxy = this.createProxy({
12058 visbility:"hidden",
12059 position:"absolute",
12060 "z-index":"35000", // yee haw
12061 border:"0px solid " + color
12064 var scale = Roo.isBorderBox ? 2 : 1;
12066 top:{from:b.y, to:b.y - 20},
12067 left:{from:b.x, to:b.x - 20},
12068 borderWidth:{from:0, to:10},
12069 opacity:{from:1, to:0},
12070 height:{from:b.height, to:(b.height + (20*scale))},
12071 width:{from:b.width, to:(b.width + (20*scale))}
12072 }, duration, function(){
12076 animFn.defer((duration/2)*1000, this);
12087 * Creates a pause before any subsequent queued effects begin. If there are
12088 * no effects queued after the pause it will have no effect.
12093 * @param {Number} seconds The length of time to pause (in seconds)
12094 * @return {Roo.Element} The Element
12096 pause : function(seconds){
12097 var el = this.getFxEl();
12100 el.queueFx(o, function(){
12101 setTimeout(function(){
12103 }, seconds * 1000);
12109 * Fade an element in (from transparent to opaque). The ending opacity can be specified
12110 * using the "endOpacity" config option.
12113 // default: fade in from opacity 0 to 100%
12116 // custom: fade in from opacity 0 to 75% over 2 seconds
12117 el.fadeIn({ endOpacity: .75, duration: 2});
12119 // common config options shown with default values
12121 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
12126 * @param {Object} options (optional) Object literal with any of the Fx config options
12127 * @return {Roo.Element} The Element
12129 fadeIn : function(o){
12130 var el = this.getFxEl();
12132 el.queueFx(o, function(){
12133 this.setOpacity(0);
12135 this.dom.style.visibility = 'visible';
12136 var to = o.endOpacity || 1;
12137 arguments.callee.anim = this.fxanim({opacity:{to:to}},
12138 o, null, .5, "easeOut", function(){
12140 this.clearOpacity();
12149 * Fade an element out (from opaque to transparent). The ending opacity can be specified
12150 * using the "endOpacity" config option.
12153 // default: fade out from the element's current opacity to 0
12156 // custom: fade out from the element's current opacity to 25% over 2 seconds
12157 el.fadeOut({ endOpacity: .25, duration: 2});
12159 // common config options shown with default values
12161 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
12168 * @param {Object} options (optional) Object literal with any of the Fx config options
12169 * @return {Roo.Element} The Element
12171 fadeOut : function(o){
12172 var el = this.getFxEl();
12174 el.queueFx(o, function(){
12175 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
12176 o, null, .5, "easeOut", function(){
12177 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
12178 this.dom.style.display = "none";
12180 this.dom.style.visibility = "hidden";
12182 this.clearOpacity();
12190 * Animates the transition of an element's dimensions from a starting height/width
12191 * to an ending height/width.
12194 // change height and width to 100x100 pixels
12195 el.scale(100, 100);
12197 // common config options shown with default values. The height and width will default to
12198 // the element's existing values if passed as null.
12201 [element's height], {
12206 * @param {Number} width The new width (pass undefined to keep the original width)
12207 * @param {Number} height The new height (pass undefined to keep the original height)
12208 * @param {Object} options (optional) Object literal with any of the Fx config options
12209 * @return {Roo.Element} The Element
12211 scale : function(w, h, o){
12212 this.shift(Roo.apply({}, o, {
12220 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
12221 * Any of these properties not specified in the config object will not be changed. This effect
12222 * requires that at least one new dimension, position or opacity setting must be passed in on
12223 * the config object in order for the function to have any effect.
12226 // slide the element horizontally to x position 200 while changing the height and opacity
12227 el.shift({ x: 200, height: 50, opacity: .8 });
12229 // common config options shown with default values.
12231 width: [element's width],
12232 height: [element's height],
12233 x: [element's x position],
12234 y: [element's y position],
12235 opacity: [element's opacity],
12240 * @param {Object} options Object literal with any of the Fx config options
12241 * @return {Roo.Element} The Element
12243 shift : function(o){
12244 var el = this.getFxEl();
12246 el.queueFx(o, function(){
12247 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
12248 if(w !== undefined){
12249 a.width = {to: this.adjustWidth(w)};
12251 if(h !== undefined){
12252 a.height = {to: this.adjustHeight(h)};
12254 if(x !== undefined || y !== undefined){
12256 x !== undefined ? x : this.getX(),
12257 y !== undefined ? y : this.getY()
12260 if(op !== undefined){
12261 a.opacity = {to: op};
12263 if(o.xy !== undefined){
12264 a.points = {to: o.xy};
12266 arguments.callee.anim = this.fxanim(a,
12267 o, 'motion', .35, "easeOut", function(){
12275 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
12276 * ending point of the effect.
12279 // default: slide the element downward while fading out
12282 // custom: slide the element out to the right with a 2-second duration
12283 el.ghost('r', { duration: 2 });
12285 // common config options shown with default values
12293 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
12294 * @param {Object} options (optional) Object literal with any of the Fx config options
12295 * @return {Roo.Element} The Element
12297 ghost : function(anchor, o){
12298 var el = this.getFxEl();
12301 el.queueFx(o, function(){
12302 anchor = anchor || "b";
12304 // restore values after effect
12305 var r = this.getFxRestore();
12306 var w = this.getWidth(),
12307 h = this.getHeight();
12309 var st = this.dom.style;
12311 var after = function(){
12313 el.setDisplayed(false);
12319 el.setPositioning(r.pos);
12320 st.width = r.width;
12321 st.height = r.height;
12326 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
12327 switch(anchor.toLowerCase()){
12354 arguments.callee.anim = this.fxanim(a,
12364 * Ensures that all effects queued after syncFx is called on the element are
12365 * run concurrently. This is the opposite of {@link #sequenceFx}.
12366 * @return {Roo.Element} The Element
12368 syncFx : function(){
12369 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
12378 * Ensures that all effects queued after sequenceFx is called on the element are
12379 * run in sequence. This is the opposite of {@link #syncFx}.
12380 * @return {Roo.Element} The Element
12382 sequenceFx : function(){
12383 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
12385 concurrent : false,
12392 nextFx : function(){
12393 var ef = this.fxQueue[0];
12400 * Returns true if the element has any effects actively running or queued, else returns false.
12401 * @return {Boolean} True if element has active effects, else false
12403 hasActiveFx : function(){
12404 return this.fxQueue && this.fxQueue[0];
12408 * Stops any running effects and clears the element's internal effects queue if it contains
12409 * any additional effects that haven't started yet.
12410 * @return {Roo.Element} The Element
12412 stopFx : function(){
12413 if(this.hasActiveFx()){
12414 var cur = this.fxQueue[0];
12415 if(cur && cur.anim && cur.anim.isAnimated()){
12416 this.fxQueue = [cur]; // clear out others
12417 cur.anim.stop(true);
12424 beforeFx : function(o){
12425 if(this.hasActiveFx() && !o.concurrent){
12436 * Returns true if the element is currently blocking so that no other effect can be queued
12437 * until this effect is finished, else returns false if blocking is not set. This is commonly
12438 * used to ensure that an effect initiated by a user action runs to completion prior to the
12439 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
12440 * @return {Boolean} True if blocking, else false
12442 hasFxBlock : function(){
12443 var q = this.fxQueue;
12444 return q && q[0] && q[0].block;
12448 queueFx : function(o, fn){
12452 if(!this.hasFxBlock()){
12453 Roo.applyIf(o, this.fxDefaults);
12455 var run = this.beforeFx(o);
12456 fn.block = o.block;
12457 this.fxQueue.push(fn);
12469 fxWrap : function(pos, o, vis){
12471 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
12474 wrapXY = this.getXY();
12476 var div = document.createElement("div");
12477 div.style.visibility = vis;
12478 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
12479 wrap.setPositioning(pos);
12480 if(wrap.getStyle("position") == "static"){
12481 wrap.position("relative");
12483 this.clearPositioning('auto');
12485 wrap.dom.appendChild(this.dom);
12487 wrap.setXY(wrapXY);
12494 fxUnwrap : function(wrap, pos, o){
12495 this.clearPositioning();
12496 this.setPositioning(pos);
12498 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
12504 getFxRestore : function(){
12505 var st = this.dom.style;
12506 return {pos: this.getPositioning(), width: st.width, height : st.height};
12510 afterFx : function(o){
12512 this.applyStyles(o.afterStyle);
12515 this.addClass(o.afterCls);
12517 if(o.remove === true){
12520 Roo.callback(o.callback, o.scope, [this]);
12522 this.fxQueue.shift();
12528 getFxEl : function(){ // support for composite element fx
12529 return Roo.get(this.dom);
12533 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
12534 animType = animType || 'run';
12536 var anim = Roo.lib.Anim[animType](
12538 (opt.duration || defaultDur) || .35,
12539 (opt.easing || defaultEase) || 'easeOut',
12541 Roo.callback(cb, this);
12550 // backwords compat
12551 Roo.Fx.resize = Roo.Fx.scale;
12553 //When included, Roo.Fx is automatically applied to Element so that all basic
12554 //effects are available directly via the Element API
12555 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
12557 * Ext JS Library 1.1.1
12558 * Copyright(c) 2006-2007, Ext JS, LLC.
12560 * Originally Released Under LGPL - original licence link has changed is not relivant.
12563 * <script type="text/javascript">
12568 * @class Roo.CompositeElement
12569 * Standard composite class. Creates a Roo.Element for every element in the collection.
12571 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12572 * actions will be performed on all the elements in this collection.</b>
12574 * All methods return <i>this</i> and can be chained.
12576 var els = Roo.select("#some-el div.some-class", true);
12577 // or select directly from an existing element
12578 var el = Roo.get('some-el');
12579 el.select('div.some-class', true);
12581 els.setWidth(100); // all elements become 100 width
12582 els.hide(true); // all elements fade out and hide
12584 els.setWidth(100).hide(true);
12587 Roo.CompositeElement = function(els){
12588 this.elements = [];
12589 this.addElements(els);
12591 Roo.CompositeElement.prototype = {
12593 addElements : function(els){
12597 if(typeof els == "string"){
12598 els = Roo.Element.selectorFunction(els);
12600 var yels = this.elements;
12601 var index = yels.length-1;
12602 for(var i = 0, len = els.length; i < len; i++) {
12603 yels[++index] = Roo.get(els[i]);
12609 * Clears this composite and adds the elements returned by the passed selector.
12610 * @param {String/Array} els A string CSS selector, an array of elements or an element
12611 * @return {CompositeElement} this
12613 fill : function(els){
12614 this.elements = [];
12620 * Filters this composite to only elements that match the passed selector.
12621 * @param {String} selector A string CSS selector
12622 * @param {Boolean} inverse return inverse filter (not matches)
12623 * @return {CompositeElement} this
12625 filter : function(selector, inverse){
12627 inverse = inverse || false;
12628 this.each(function(el){
12629 var match = inverse ? !el.is(selector) : el.is(selector);
12631 els[els.length] = el.dom;
12638 invoke : function(fn, args){
12639 var els = this.elements;
12640 for(var i = 0, len = els.length; i < len; i++) {
12641 Roo.Element.prototype[fn].apply(els[i], args);
12646 * Adds elements to this composite.
12647 * @param {String/Array} els A string CSS selector, an array of elements or an element
12648 * @return {CompositeElement} this
12650 add : function(els){
12651 if(typeof els == "string"){
12652 this.addElements(Roo.Element.selectorFunction(els));
12653 }else if(els.length !== undefined){
12654 this.addElements(els);
12656 this.addElements([els]);
12661 * Calls the passed function passing (el, this, index) for each element in this composite.
12662 * @param {Function} fn The function to call
12663 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12664 * @return {CompositeElement} this
12666 each : function(fn, scope){
12667 var els = this.elements;
12668 for(var i = 0, len = els.length; i < len; i++){
12669 if(fn.call(scope || els[i], els[i], this, i) === false) {
12677 * Returns the Element object at the specified index
12678 * @param {Number} index
12679 * @return {Roo.Element}
12681 item : function(index){
12682 return this.elements[index] || null;
12686 * Returns the first Element
12687 * @return {Roo.Element}
12689 first : function(){
12690 return this.item(0);
12694 * Returns the last Element
12695 * @return {Roo.Element}
12698 return this.item(this.elements.length-1);
12702 * Returns the number of elements in this composite
12705 getCount : function(){
12706 return this.elements.length;
12710 * Returns true if this composite contains the passed element
12713 contains : function(el){
12714 return this.indexOf(el) !== -1;
12718 * Returns true if this composite contains the passed element
12721 indexOf : function(el){
12722 return this.elements.indexOf(Roo.get(el));
12727 * Removes the specified element(s).
12728 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
12729 * or an array of any of those.
12730 * @param {Boolean} removeDom (optional) True to also remove the element from the document
12731 * @return {CompositeElement} this
12733 removeElement : function(el, removeDom){
12734 if(el instanceof Array){
12735 for(var i = 0, len = el.length; i < len; i++){
12736 this.removeElement(el[i]);
12740 var index = typeof el == 'number' ? el : this.indexOf(el);
12743 var d = this.elements[index];
12747 d.parentNode.removeChild(d);
12750 this.elements.splice(index, 1);
12756 * Replaces the specified element with the passed element.
12757 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
12759 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
12760 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
12761 * @return {CompositeElement} this
12763 replaceElement : function(el, replacement, domReplace){
12764 var index = typeof el == 'number' ? el : this.indexOf(el);
12767 this.elements[index].replaceWith(replacement);
12769 this.elements.splice(index, 1, Roo.get(replacement))
12776 * Removes all elements.
12778 clear : function(){
12779 this.elements = [];
12783 Roo.CompositeElement.createCall = function(proto, fnName){
12784 if(!proto[fnName]){
12785 proto[fnName] = function(){
12786 return this.invoke(fnName, arguments);
12790 for(var fnName in Roo.Element.prototype){
12791 if(typeof Roo.Element.prototype[fnName] == "function"){
12792 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
12798 * Ext JS Library 1.1.1
12799 * Copyright(c) 2006-2007, Ext JS, LLC.
12801 * Originally Released Under LGPL - original licence link has changed is not relivant.
12804 * <script type="text/javascript">
12808 * @class Roo.CompositeElementLite
12809 * @extends Roo.CompositeElement
12810 * Flyweight composite class. Reuses the same Roo.Element for element operations.
12812 var els = Roo.select("#some-el div.some-class");
12813 // or select directly from an existing element
12814 var el = Roo.get('some-el');
12815 el.select('div.some-class');
12817 els.setWidth(100); // all elements become 100 width
12818 els.hide(true); // all elements fade out and hide
12820 els.setWidth(100).hide(true);
12821 </code></pre><br><br>
12822 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12823 * actions will be performed on all the elements in this collection.</b>
12825 Roo.CompositeElementLite = function(els){
12826 Roo.CompositeElementLite.superclass.constructor.call(this, els);
12827 this.el = new Roo.Element.Flyweight();
12829 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
12830 addElements : function(els){
12832 if(els instanceof Array){
12833 this.elements = this.elements.concat(els);
12835 var yels = this.elements;
12836 var index = yels.length-1;
12837 for(var i = 0, len = els.length; i < len; i++) {
12838 yels[++index] = els[i];
12844 invoke : function(fn, args){
12845 var els = this.elements;
12847 for(var i = 0, len = els.length; i < len; i++) {
12849 Roo.Element.prototype[fn].apply(el, args);
12854 * Returns a flyweight Element of the dom element object at the specified index
12855 * @param {Number} index
12856 * @return {Roo.Element}
12858 item : function(index){
12859 if(!this.elements[index]){
12862 this.el.dom = this.elements[index];
12866 // fixes scope with flyweight
12867 addListener : function(eventName, handler, scope, opt){
12868 var els = this.elements;
12869 for(var i = 0, len = els.length; i < len; i++) {
12870 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
12876 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
12877 * passed is the flyweight (shared) Roo.Element instance, so if you require a
12878 * a reference to the dom node, use el.dom.</b>
12879 * @param {Function} fn The function to call
12880 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12881 * @return {CompositeElement} this
12883 each : function(fn, scope){
12884 var els = this.elements;
12886 for(var i = 0, len = els.length; i < len; i++){
12888 if(fn.call(scope || el, el, this, i) === false){
12895 indexOf : function(el){
12896 return this.elements.indexOf(Roo.getDom(el));
12899 replaceElement : function(el, replacement, domReplace){
12900 var index = typeof el == 'number' ? el : this.indexOf(el);
12902 replacement = Roo.getDom(replacement);
12904 var d = this.elements[index];
12905 d.parentNode.insertBefore(replacement, d);
12906 d.parentNode.removeChild(d);
12908 this.elements.splice(index, 1, replacement);
12913 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
12917 * Ext JS Library 1.1.1
12918 * Copyright(c) 2006-2007, Ext JS, LLC.
12920 * Originally Released Under LGPL - original licence link has changed is not relivant.
12923 * <script type="text/javascript">
12929 * @class Roo.data.Connection
12930 * @extends Roo.util.Observable
12931 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
12932 * either to a configured URL, or to a URL specified at request time.
12934 * Requests made by this class are asynchronous, and will return immediately. No data from
12935 * the server will be available to the statement immediately following the {@link #request} call.
12936 * To process returned data, use a callback in the request options object, or an event listener.
12938 * Note: If you are doing a file upload, you will not get a normal response object sent back to
12939 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
12940 * The response object is created using the innerHTML of the IFRAME's document as the responseText
12941 * property and, if present, the IFRAME's XML document as the responseXML property.
12943 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
12944 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
12945 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
12946 * standard DOM methods.
12948 * @param {Object} config a configuration object.
12950 Roo.data.Connection = function(config){
12951 Roo.apply(this, config);
12954 * @event beforerequest
12955 * Fires before a network request is made to retrieve a data object.
12956 * @param {Connection} conn This Connection object.
12957 * @param {Object} options The options config object passed to the {@link #request} method.
12959 "beforerequest" : true,
12961 * @event requestcomplete
12962 * Fires if the request was successfully completed.
12963 * @param {Connection} conn This Connection object.
12964 * @param {Object} response The XHR object containing the response data.
12965 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12966 * @param {Object} options The options config object passed to the {@link #request} method.
12968 "requestcomplete" : true,
12970 * @event requestexception
12971 * Fires if an error HTTP status was returned from the server.
12972 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
12973 * @param {Connection} conn This Connection object.
12974 * @param {Object} response The XHR object containing the response data.
12975 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12976 * @param {Object} options The options config object passed to the {@link #request} method.
12978 "requestexception" : true
12980 Roo.data.Connection.superclass.constructor.call(this);
12983 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
12985 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12988 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12989 * extra parameters to each request made by this object. (defaults to undefined)
12992 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12993 * to each request made by this object. (defaults to undefined)
12996 * @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)
12999 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
13003 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
13009 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
13012 disableCaching: true,
13015 * Sends an HTTP request to a remote server.
13016 * @param {Object} options An object which may contain the following properties:<ul>
13017 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
13018 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
13019 * request, a url encoded string or a function to call to get either.</li>
13020 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
13021 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
13022 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
13023 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
13024 * <li>options {Object} The parameter to the request call.</li>
13025 * <li>success {Boolean} True if the request succeeded.</li>
13026 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
13028 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
13029 * The callback is passed the following parameters:<ul>
13030 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
13031 * <li>options {Object} The parameter to the request call.</li>
13033 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
13034 * The callback is passed the following parameters:<ul>
13035 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
13036 * <li>options {Object} The parameter to the request call.</li>
13038 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
13039 * for the callback function. Defaults to the browser window.</li>
13040 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
13041 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
13042 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
13043 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
13044 * params for the post data. Any params will be appended to the URL.</li>
13045 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
13047 * @return {Number} transactionId
13049 request : function(o){
13050 if(this.fireEvent("beforerequest", this, o) !== false){
13053 if(typeof p == "function"){
13054 p = p.call(o.scope||window, o);
13056 if(typeof p == "object"){
13057 p = Roo.urlEncode(o.params);
13059 if(this.extraParams){
13060 var extras = Roo.urlEncode(this.extraParams);
13061 p = p ? (p + '&' + extras) : extras;
13064 var url = o.url || this.url;
13065 if(typeof url == 'function'){
13066 url = url.call(o.scope||window, o);
13070 var form = Roo.getDom(o.form);
13071 url = url || form.action;
13073 var enctype = form.getAttribute("enctype");
13076 return this.doFormDataUpload(o, url);
13079 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
13080 return this.doFormUpload(o, p, url);
13082 var f = Roo.lib.Ajax.serializeForm(form);
13083 p = p ? (p + '&' + f) : f;
13086 if (!o.form && o.formData) {
13087 o.formData = o.formData === true ? new FormData() : o.formData;
13088 for (var k in o.params) {
13089 o.formData.append(k,o.params[k]);
13092 return this.doFormDataUpload(o, url);
13096 var hs = o.headers;
13097 if(this.defaultHeaders){
13098 hs = Roo.apply(hs || {}, this.defaultHeaders);
13105 success: this.handleResponse,
13106 failure: this.handleFailure,
13108 argument: {options: o},
13109 timeout : o.timeout || this.timeout
13112 var method = o.method||this.method||(p ? "POST" : "GET");
13114 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
13115 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
13118 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
13122 }else if(this.autoAbort !== false){
13126 if((method == 'GET' && p) || o.xmlData){
13127 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
13130 Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
13131 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
13132 Roo.lib.Ajax.useDefaultHeader == true;
13133 return this.transId;
13135 Roo.callback(o.callback, o.scope, [o, null, null]);
13141 * Determine whether this object has a request outstanding.
13142 * @param {Number} transactionId (Optional) defaults to the last transaction
13143 * @return {Boolean} True if there is an outstanding request.
13145 isLoading : function(transId){
13147 return Roo.lib.Ajax.isCallInProgress(transId);
13149 return this.transId ? true : false;
13154 * Aborts any outstanding request.
13155 * @param {Number} transactionId (Optional) defaults to the last transaction
13157 abort : function(transId){
13158 if(transId || this.isLoading()){
13159 Roo.lib.Ajax.abort(transId || this.transId);
13164 handleResponse : function(response){
13165 this.transId = false;
13166 var options = response.argument.options;
13167 response.argument = options ? options.argument : null;
13168 this.fireEvent("requestcomplete", this, response, options);
13169 Roo.callback(options.success, options.scope, [response, options]);
13170 Roo.callback(options.callback, options.scope, [options, true, response]);
13174 handleFailure : function(response, e){
13175 this.transId = false;
13176 var options = response.argument.options;
13177 response.argument = options ? options.argument : null;
13178 this.fireEvent("requestexception", this, response, options, e);
13179 Roo.callback(options.failure, options.scope, [response, options]);
13180 Roo.callback(options.callback, options.scope, [options, false, response]);
13184 doFormUpload : function(o, ps, url){
13186 var frame = document.createElement('iframe');
13189 frame.className = 'x-hidden';
13191 frame.src = Roo.SSL_SECURE_URL;
13193 document.body.appendChild(frame);
13196 document.frames[id].name = id;
13199 var form = Roo.getDom(o.form);
13201 form.method = 'POST';
13202 form.enctype = form.encoding = 'multipart/form-data';
13208 if(ps){ // add dynamic params
13210 ps = Roo.urlDecode(ps, false);
13212 if(ps.hasOwnProperty(k)){
13213 hd = document.createElement('input');
13214 hd.type = 'hidden';
13217 form.appendChild(hd);
13224 var r = { // bogus response object
13229 r.argument = o ? o.argument : null;
13234 doc = frame.contentWindow.document;
13236 doc = (frame.contentDocument || window.frames[id].document);
13238 if(doc && doc.body){
13239 r.responseText = doc.body.innerHTML;
13241 if(doc && doc.XMLDocument){
13242 r.responseXML = doc.XMLDocument;
13244 r.responseXML = doc;
13251 Roo.EventManager.removeListener(frame, 'load', cb, this);
13253 this.fireEvent("requestcomplete", this, r, o);
13254 Roo.callback(o.success, o.scope, [r, o]);
13255 Roo.callback(o.callback, o.scope, [o, true, r]);
13257 setTimeout(function(){document.body.removeChild(frame);}, 100);
13260 Roo.EventManager.on(frame, 'load', cb, this);
13263 if(hiddens){ // remove dynamic params
13264 for(var i = 0, len = hiddens.length; i < len; i++){
13265 form.removeChild(hiddens[i]);
13269 // this is a 'formdata version???'
13272 doFormDataUpload : function(o, url)
13276 var form = Roo.getDom(o.form);
13277 form.enctype = form.encoding = 'multipart/form-data';
13278 formData = o.formData === true ? new FormData(form) : o.formData;
13280 formData = o.formData === true ? new FormData() : o.formData;
13285 success: this.handleResponse,
13286 failure: this.handleFailure,
13288 argument: {options: o},
13289 timeout : o.timeout || this.timeout
13292 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
13296 }else if(this.autoAbort !== false){
13300 //Roo.lib.Ajax.defaultPostHeader = null;
13301 Roo.lib.Ajax.useDefaultHeader = false;
13302 this.transId = Roo.lib.Ajax.request( "POST", url, cb, formData, o);
13303 Roo.lib.Ajax.useDefaultHeader = true;
13311 * Ext JS Library 1.1.1
13312 * Copyright(c) 2006-2007, Ext JS, LLC.
13314 * Originally Released Under LGPL - original licence link has changed is not relivant.
13317 * <script type="text/javascript">
13321 * Global Ajax request class.
13324 * @extends Roo.data.Connection
13327 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
13328 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
13329 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
13330 * @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)
13331 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
13332 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
13333 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
13335 Roo.Ajax = new Roo.data.Connection({
13344 * Serialize the passed form into a url encoded string
13346 * @param {String/HTMLElement} form
13349 serializeForm : function(form){
13350 return Roo.lib.Ajax.serializeForm(form);
13354 * Ext JS Library 1.1.1
13355 * Copyright(c) 2006-2007, Ext JS, LLC.
13357 * Originally Released Under LGPL - original licence link has changed is not relivant.
13360 * <script type="text/javascript">
13365 * @class Roo.UpdateManager
13366 * @extends Roo.util.Observable
13367 * Provides AJAX-style update for Element object.<br><br>
13370 * // Get it from a Roo.Element object
13371 * var el = Roo.get("foo");
13372 * var mgr = el.getUpdateManager();
13373 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
13375 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
13377 * // or directly (returns the same UpdateManager instance)
13378 * var mgr = new Roo.UpdateManager("myElementId");
13379 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
13380 * mgr.on("update", myFcnNeedsToKnow);
13382 // short handed call directly from the element object
13383 Roo.get("foo").load({
13387 text: "Loading Foo..."
13391 * Create new UpdateManager directly.
13392 * @param {String/HTMLElement/Roo.Element} el The element to update
13393 * @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).
13395 Roo.UpdateManager = function(el, forceNew){
13397 if(!forceNew && el.updateManager){
13398 return el.updateManager;
13401 * The Element object
13402 * @type Roo.Element
13406 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
13409 this.defaultUrl = null;
13413 * @event beforeupdate
13414 * Fired before an update is made, return false from your handler and the update is cancelled.
13415 * @param {Roo.Element} el
13416 * @param {String/Object/Function} url
13417 * @param {String/Object} params
13419 "beforeupdate": true,
13422 * Fired after successful update is made.
13423 * @param {Roo.Element} el
13424 * @param {Object} oResponseObject The response Object
13429 * Fired on update failure.
13430 * @param {Roo.Element} el
13431 * @param {Object} oResponseObject The response Object
13435 var d = Roo.UpdateManager.defaults;
13437 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
13440 this.sslBlankUrl = d.sslBlankUrl;
13442 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
13445 this.disableCaching = d.disableCaching;
13447 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
13450 this.indicatorText = d.indicatorText;
13452 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
13455 this.showLoadIndicator = d.showLoadIndicator;
13457 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
13460 this.timeout = d.timeout;
13463 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
13466 this.loadScripts = d.loadScripts;
13469 * Transaction object of current executing transaction
13471 this.transaction = null;
13476 this.autoRefreshProcId = null;
13478 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
13481 this.refreshDelegate = this.refresh.createDelegate(this);
13483 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
13486 this.updateDelegate = this.update.createDelegate(this);
13488 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
13491 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
13495 this.successDelegate = this.processSuccess.createDelegate(this);
13499 this.failureDelegate = this.processFailure.createDelegate(this);
13501 if(!this.renderer){
13503 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
13505 this.renderer = new Roo.UpdateManager.BasicRenderer();
13508 Roo.UpdateManager.superclass.constructor.call(this);
13511 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
13513 * Get the Element this UpdateManager is bound to
13514 * @return {Roo.Element} The element
13516 getEl : function(){
13520 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
13521 * @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:
13524 url: "your-url.php",<br/>
13525 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
13526 callback: yourFunction,<br/>
13527 scope: yourObject, //(optional scope) <br/>
13528 discardUrl: false, <br/>
13529 nocache: false,<br/>
13530 text: "Loading...",<br/>
13532 scripts: false<br/>
13535 * The only required property is url. The optional properties nocache, text and scripts
13536 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
13537 * @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}
13538 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13539 * @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.
13541 update : function(url, params, callback, discardUrl){
13542 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
13543 var method = this.method,
13545 if(typeof url == "object"){ // must be config object
13548 params = params || cfg.params;
13549 callback = callback || cfg.callback;
13550 discardUrl = discardUrl || cfg.discardUrl;
13551 if(callback && cfg.scope){
13552 callback = callback.createDelegate(cfg.scope);
13554 if(typeof cfg.method != "undefined"){method = cfg.method;};
13555 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
13556 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
13557 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
13558 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
13560 this.showLoading();
13562 this.defaultUrl = url;
13564 if(typeof url == "function"){
13565 url = url.call(this);
13568 method = method || (params ? "POST" : "GET");
13569 if(method == "GET"){
13570 url = this.prepareUrl(url);
13573 var o = Roo.apply(cfg ||{}, {
13576 success: this.successDelegate,
13577 failure: this.failureDelegate,
13578 callback: undefined,
13579 timeout: (this.timeout*1000),
13580 argument: {"url": url, "form": null, "callback": callback, "params": params}
13582 Roo.log("updated manager called with timeout of " + o.timeout);
13583 this.transaction = Roo.Ajax.request(o);
13588 * 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.
13589 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
13590 * @param {String/HTMLElement} form The form Id or form element
13591 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
13592 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
13593 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13595 formUpdate : function(form, url, reset, callback){
13596 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
13597 if(typeof url == "function"){
13598 url = url.call(this);
13600 form = Roo.getDom(form);
13601 this.transaction = Roo.Ajax.request({
13604 success: this.successDelegate,
13605 failure: this.failureDelegate,
13606 timeout: (this.timeout*1000),
13607 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
13609 this.showLoading.defer(1, this);
13614 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
13615 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13617 refresh : function(callback){
13618 if(this.defaultUrl == null){
13621 this.update(this.defaultUrl, null, callback, true);
13625 * Set this element to auto refresh.
13626 * @param {Number} interval How often to update (in seconds).
13627 * @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)
13628 * @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}
13629 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13630 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
13632 startAutoRefresh : function(interval, url, params, callback, refreshNow){
13634 this.update(url || this.defaultUrl, params, callback, true);
13636 if(this.autoRefreshProcId){
13637 clearInterval(this.autoRefreshProcId);
13639 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
13643 * Stop auto refresh on this element.
13645 stopAutoRefresh : function(){
13646 if(this.autoRefreshProcId){
13647 clearInterval(this.autoRefreshProcId);
13648 delete this.autoRefreshProcId;
13652 isAutoRefreshing : function(){
13653 return this.autoRefreshProcId ? true : false;
13656 * Called to update the element to "Loading" state. Override to perform custom action.
13658 showLoading : function(){
13659 if(this.showLoadIndicator){
13660 this.el.update(this.indicatorText);
13665 * Adds unique parameter to query string if disableCaching = true
13668 prepareUrl : function(url){
13669 if(this.disableCaching){
13670 var append = "_dc=" + (new Date().getTime());
13671 if(url.indexOf("?") !== -1){
13672 url += "&" + append;
13674 url += "?" + append;
13683 processSuccess : function(response){
13684 this.transaction = null;
13685 if(response.argument.form && response.argument.reset){
13686 try{ // put in try/catch since some older FF releases had problems with this
13687 response.argument.form.reset();
13690 if(this.loadScripts){
13691 this.renderer.render(this.el, response, this,
13692 this.updateComplete.createDelegate(this, [response]));
13694 this.renderer.render(this.el, response, this);
13695 this.updateComplete(response);
13699 updateComplete : function(response){
13700 this.fireEvent("update", this.el, response);
13701 if(typeof response.argument.callback == "function"){
13702 response.argument.callback(this.el, true, response);
13709 processFailure : function(response){
13710 this.transaction = null;
13711 this.fireEvent("failure", this.el, response);
13712 if(typeof response.argument.callback == "function"){
13713 response.argument.callback(this.el, false, response);
13718 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
13719 * @param {Object} renderer The object implementing the render() method
13721 setRenderer : function(renderer){
13722 this.renderer = renderer;
13725 getRenderer : function(){
13726 return this.renderer;
13730 * Set the defaultUrl used for updates
13731 * @param {String/Function} defaultUrl The url or a function to call to get the url
13733 setDefaultUrl : function(defaultUrl){
13734 this.defaultUrl = defaultUrl;
13738 * Aborts the executing transaction
13740 abort : function(){
13741 if(this.transaction){
13742 Roo.Ajax.abort(this.transaction);
13747 * Returns true if an update is in progress
13748 * @return {Boolean}
13750 isUpdating : function(){
13751 if(this.transaction){
13752 return Roo.Ajax.isLoading(this.transaction);
13759 * @class Roo.UpdateManager.defaults
13760 * @static (not really - but it helps the doc tool)
13761 * The defaults collection enables customizing the default properties of UpdateManager
13763 Roo.UpdateManager.defaults = {
13765 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
13771 * True to process scripts by default (Defaults to false).
13774 loadScripts : false,
13777 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
13780 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
13782 * Whether to append unique parameter on get request to disable caching (Defaults to false).
13785 disableCaching : false,
13787 * Whether to show indicatorText when loading (Defaults to true).
13790 showLoadIndicator : true,
13792 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
13795 indicatorText : '<div class="loading-indicator">Loading...</div>'
13799 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
13801 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
13802 * @param {String/HTMLElement/Roo.Element} el The element to update
13803 * @param {String} url The url
13804 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
13805 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
13808 * @member Roo.UpdateManager
13810 Roo.UpdateManager.updateElement = function(el, url, params, options){
13811 var um = Roo.get(el, true).getUpdateManager();
13812 Roo.apply(um, options);
13813 um.update(url, params, options ? options.callback : null);
13815 // alias for backwards compat
13816 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
13818 * @class Roo.UpdateManager.BasicRenderer
13819 * Default Content renderer. Updates the elements innerHTML with the responseText.
13821 Roo.UpdateManager.BasicRenderer = function(){};
13823 Roo.UpdateManager.BasicRenderer.prototype = {
13825 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
13826 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
13827 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
13828 * @param {Roo.Element} el The element being rendered
13829 * @param {Object} response The YUI Connect response object
13830 * @param {UpdateManager} updateManager The calling update manager
13831 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
13833 render : function(el, response, updateManager, callback){
13834 el.update(response.responseText, updateManager.loadScripts, callback);
13840 * (c)) Alan Knowles
13846 * @class Roo.DomTemplate
13847 * @extends Roo.Template
13848 * An effort at a dom based template engine..
13850 * Similar to XTemplate, except it uses dom parsing to create the template..
13852 * Supported features:
13857 {a_variable} - output encoded.
13858 {a_variable.format:("Y-m-d")} - call a method on the variable
13859 {a_variable:raw} - unencoded output
13860 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
13861 {a_variable:this.method_on_template(...)} - call a method on the template object.
13866 <div roo-for="a_variable or condition.."></div>
13867 <div roo-if="a_variable or condition"></div>
13868 <div roo-exec="some javascript"></div>
13869 <div roo-name="named_template"></div>
13874 Roo.DomTemplate = function()
13876 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
13883 Roo.extend(Roo.DomTemplate, Roo.Template, {
13885 * id counter for sub templates.
13889 * flag to indicate if dom parser is inside a pre,
13890 * it will strip whitespace if not.
13895 * The various sub templates
13903 * basic tag replacing syntax
13906 * // you can fake an object call by doing this
13910 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
13911 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
13913 iterChild : function (node, method) {
13915 var oldPre = this.inPre;
13916 if (node.tagName == 'PRE') {
13919 for( var i = 0; i < node.childNodes.length; i++) {
13920 method.call(this, node.childNodes[i]);
13922 this.inPre = oldPre;
13928 * compile the template
13930 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
13933 compile: function()
13937 // covert the html into DOM...
13941 doc = document.implementation.createHTMLDocument("");
13942 doc.documentElement.innerHTML = this.html ;
13943 div = doc.documentElement;
13945 // old IE... - nasty -- it causes all sorts of issues.. with
13946 // images getting pulled from server..
13947 div = document.createElement('div');
13948 div.innerHTML = this.html;
13950 //doc.documentElement.innerHTML = htmlBody
13956 this.iterChild(div, function(n) {_t.compileNode(n, true); });
13958 var tpls = this.tpls;
13960 // create a top level template from the snippet..
13962 //Roo.log(div.innerHTML);
13969 body : div.innerHTML,
13982 Roo.each(tpls, function(tp){
13983 this.compileTpl(tp);
13984 this.tpls[tp.id] = tp;
13987 this.master = tpls[0];
13993 compileNode : function(node, istop) {
13998 // skip anything not a tag..
13999 if (node.nodeType != 1) {
14000 if (node.nodeType == 3 && !this.inPre) {
14001 // reduce white space..
14002 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
14025 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
14026 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
14027 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
14028 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
14034 // just itterate children..
14035 this.iterChild(node,this.compileNode);
14038 tpl.uid = this.id++;
14039 tpl.value = node.getAttribute('roo-' + tpl.attr);
14040 node.removeAttribute('roo-'+ tpl.attr);
14041 if (tpl.attr != 'name') {
14042 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
14043 node.parentNode.replaceChild(placeholder, node);
14046 var placeholder = document.createElement('span');
14047 placeholder.className = 'roo-tpl-' + tpl.value;
14048 node.parentNode.replaceChild(placeholder, node);
14051 // parent now sees '{domtplXXXX}
14052 this.iterChild(node,this.compileNode);
14054 // we should now have node body...
14055 var div = document.createElement('div');
14056 div.appendChild(node);
14058 // this has the unfortunate side effect of converting tagged attributes
14059 // eg. href="{...}" into %7C...%7D
14060 // this has been fixed by searching for those combo's although it's a bit hacky..
14063 tpl.body = div.innerHTML;
14070 switch (tpl.value) {
14071 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
14072 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
14073 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
14078 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
14082 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
14086 tpl.id = tpl.value; // replace non characters???
14092 this.tpls.push(tpl);
14102 * Compile a segment of the template into a 'sub-template'
14108 compileTpl : function(tpl)
14110 var fm = Roo.util.Format;
14111 var useF = this.disableFormats !== true;
14113 var sep = Roo.isGecko ? "+\n" : ",\n";
14115 var undef = function(str) {
14116 Roo.debug && Roo.log("Property not found :" + str);
14120 //Roo.log(tpl.body);
14124 var fn = function(m, lbrace, name, format, args)
14127 //Roo.log(arguments);
14128 args = args ? args.replace(/\\'/g,"'") : args;
14129 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
14130 if (typeof(format) == 'undefined') {
14131 format = 'htmlEncode';
14133 if (format == 'raw' ) {
14137 if(name.substr(0, 6) == 'domtpl'){
14138 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
14141 // build an array of options to determine if value is undefined..
14143 // basically get 'xxxx.yyyy' then do
14144 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
14145 // (function () { Roo.log("Property not found"); return ''; })() :
14150 Roo.each(name.split('.'), function(st) {
14151 lookfor += (lookfor.length ? '.': '') + st;
14152 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
14155 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
14158 if(format && useF){
14160 args = args ? ',' + args : "";
14162 if(format.substr(0, 5) != "this."){
14163 format = "fm." + format + '(';
14165 format = 'this.call("'+ format.substr(5) + '", ';
14169 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
14172 if (args && args.length) {
14173 // called with xxyx.yuu:(test,test)
14175 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
14177 // raw.. - :raw modifier..
14178 return "'"+ sep + udef_st + name + ")"+sep+"'";
14182 // branched to use + in gecko and [].join() in others
14184 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
14185 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
14188 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
14189 body.push(tpl.body.replace(/(\r\n|\n)/g,
14190 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
14191 body.push("'].join('');};};");
14192 body = body.join('');
14195 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
14197 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
14204 * same as applyTemplate, except it's done to one of the subTemplates
14205 * when using named templates, you can do:
14207 * var str = pl.applySubTemplate('your-name', values);
14210 * @param {Number} id of the template
14211 * @param {Object} values to apply to template
14212 * @param {Object} parent (normaly the instance of this object)
14214 applySubTemplate : function(id, values, parent)
14218 var t = this.tpls[id];
14222 if(t.ifCall && !t.ifCall.call(this, values, parent)){
14223 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
14227 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
14234 if(t.execCall && t.execCall.call(this, values, parent)){
14238 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
14244 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
14245 parent = t.target ? values : parent;
14246 if(t.forCall && vs instanceof Array){
14248 for(var i = 0, len = vs.length; i < len; i++){
14250 buf[buf.length] = t.compiled.call(this, vs[i], parent);
14252 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
14254 //Roo.log(t.compiled);
14258 return buf.join('');
14261 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
14266 return t.compiled.call(this, vs, parent);
14268 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
14270 //Roo.log(t.compiled);
14278 applyTemplate : function(values){
14279 return this.master.compiled.call(this, values, {});
14280 //var s = this.subs;
14283 apply : function(){
14284 return this.applyTemplate.apply(this, arguments);
14289 Roo.DomTemplate.from = function(el){
14290 el = Roo.getDom(el);
14291 return new Roo.Domtemplate(el.value || el.innerHTML);
14294 * Ext JS Library 1.1.1
14295 * Copyright(c) 2006-2007, Ext JS, LLC.
14297 * Originally Released Under LGPL - original licence link has changed is not relivant.
14300 * <script type="text/javascript">
14304 * @class Roo.util.DelayedTask
14305 * Provides a convenient method of performing setTimeout where a new
14306 * timeout cancels the old timeout. An example would be performing validation on a keypress.
14307 * You can use this class to buffer
14308 * the keypress events for a certain number of milliseconds, and perform only if they stop
14309 * for that amount of time.
14310 * @constructor The parameters to this constructor serve as defaults and are not required.
14311 * @param {Function} fn (optional) The default function to timeout
14312 * @param {Object} scope (optional) The default scope of that timeout
14313 * @param {Array} args (optional) The default Array of arguments
14315 Roo.util.DelayedTask = function(fn, scope, args){
14316 var id = null, d, t;
14318 var call = function(){
14319 var now = new Date().getTime();
14323 fn.apply(scope, args || []);
14327 * Cancels any pending timeout and queues a new one
14328 * @param {Number} delay The milliseconds to delay
14329 * @param {Function} newFn (optional) Overrides function passed to constructor
14330 * @param {Object} newScope (optional) Overrides scope passed to constructor
14331 * @param {Array} newArgs (optional) Overrides args passed to constructor
14333 this.delay = function(delay, newFn, newScope, newArgs){
14334 if(id && delay != d){
14338 t = new Date().getTime();
14340 scope = newScope || scope;
14341 args = newArgs || args;
14343 id = setInterval(call, d);
14348 * Cancel the last queued timeout
14350 this.cancel = function(){
14358 * Ext JS Library 1.1.1
14359 * Copyright(c) 2006-2007, Ext JS, LLC.
14361 * Originally Released Under LGPL - original licence link has changed is not relivant.
14364 * <script type="text/javascript">
14367 * @class Roo.util.TaskRunner
14368 * Manage background tasks - not sure why this is better that setInterval?
14373 Roo.util.TaskRunner = function(interval){
14374 interval = interval || 10;
14375 var tasks = [], removeQueue = [];
14377 var running = false;
14379 var stopThread = function(){
14385 var startThread = function(){
14388 id = setInterval(runTasks, interval);
14392 var removeTask = function(task){
14393 removeQueue.push(task);
14399 var runTasks = function(){
14400 if(removeQueue.length > 0){
14401 for(var i = 0, len = removeQueue.length; i < len; i++){
14402 tasks.remove(removeQueue[i]);
14405 if(tasks.length < 1){
14410 var now = new Date().getTime();
14411 for(var i = 0, len = tasks.length; i < len; ++i){
14413 var itime = now - t.taskRunTime;
14414 if(t.interval <= itime){
14415 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
14416 t.taskRunTime = now;
14417 if(rt === false || t.taskRunCount === t.repeat){
14422 if(t.duration && t.duration <= (now - t.taskStartTime)){
14429 * Queues a new task.
14430 * @param {Object} task
14432 * Task property : interval = how frequent to run.
14433 * Task object should implement
14435 * Task object may implement
14436 * function onStop()
14438 this.start = function(task){
14440 task.taskStartTime = new Date().getTime();
14441 task.taskRunTime = 0;
14442 task.taskRunCount = 0;
14448 * @param {Object} task
14450 this.stop = function(task){
14457 this.stopAll = function(){
14459 for(var i = 0, len = tasks.length; i < len; i++){
14460 if(tasks[i].onStop){
14469 Roo.TaskMgr = new Roo.util.TaskRunner();/*
14471 * Ext JS Library 1.1.1
14472 * Copyright(c) 2006-2007, Ext JS, LLC.
14474 * Originally Released Under LGPL - original licence link has changed is not relivant.
14477 * <script type="text/javascript">
14482 * @class Roo.util.MixedCollection
14483 * @extends Roo.util.Observable
14484 * A Collection class that maintains both numeric indexes and keys and exposes events.
14486 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
14487 * collection (defaults to false)
14488 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
14489 * and return the key value for that item. This is used when available to look up the key on items that
14490 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
14491 * equivalent to providing an implementation for the {@link #getKey} method.
14493 Roo.util.MixedCollection = function(allowFunctions, keyFn){
14501 * Fires when the collection is cleared.
14506 * Fires when an item is added to the collection.
14507 * @param {Number} index The index at which the item was added.
14508 * @param {Object} o The item added.
14509 * @param {String} key The key associated with the added item.
14514 * Fires when an item is replaced in the collection.
14515 * @param {String} key he key associated with the new added.
14516 * @param {Object} old The item being replaced.
14517 * @param {Object} new The new item.
14522 * Fires when an item is removed from the collection.
14523 * @param {Object} o The item being removed.
14524 * @param {String} key (optional) The key associated with the removed item.
14529 this.allowFunctions = allowFunctions === true;
14531 this.getKey = keyFn;
14533 Roo.util.MixedCollection.superclass.constructor.call(this);
14536 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
14537 allowFunctions : false,
14540 * Adds an item to the collection.
14541 * @param {String} key The key to associate with the item
14542 * @param {Object} o The item to add.
14543 * @return {Object} The item added.
14545 add : function(key, o){
14546 if(arguments.length == 1){
14548 key = this.getKey(o);
14550 if(typeof key == "undefined" || key === null){
14552 this.items.push(o);
14553 this.keys.push(null);
14555 var old = this.map[key];
14557 return this.replace(key, o);
14560 this.items.push(o);
14562 this.keys.push(key);
14564 this.fireEvent("add", this.length-1, o, key);
14569 * MixedCollection has a generic way to fetch keys if you implement getKey.
14572 var mc = new Roo.util.MixedCollection();
14573 mc.add(someEl.dom.id, someEl);
14574 mc.add(otherEl.dom.id, otherEl);
14578 var mc = new Roo.util.MixedCollection();
14579 mc.getKey = function(el){
14585 // or via the constructor
14586 var mc = new Roo.util.MixedCollection(false, function(el){
14592 * @param o {Object} The item for which to find the key.
14593 * @return {Object} The key for the passed item.
14595 getKey : function(o){
14600 * Replaces an item in the collection.
14601 * @param {String} key The key associated with the item to replace, or the item to replace.
14602 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
14603 * @return {Object} The new item.
14605 replace : function(key, o){
14606 if(arguments.length == 1){
14608 key = this.getKey(o);
14610 var old = this.item(key);
14611 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
14612 return this.add(key, o);
14614 var index = this.indexOfKey(key);
14615 this.items[index] = o;
14617 this.fireEvent("replace", key, old, o);
14622 * Adds all elements of an Array or an Object to the collection.
14623 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
14624 * an Array of values, each of which are added to the collection.
14626 addAll : function(objs){
14627 if(arguments.length > 1 || objs instanceof Array){
14628 var args = arguments.length > 1 ? arguments : objs;
14629 for(var i = 0, len = args.length; i < len; i++){
14633 for(var key in objs){
14634 if(this.allowFunctions || typeof objs[key] != "function"){
14635 this.add(key, objs[key]);
14642 * Executes the specified function once for every item in the collection, passing each
14643 * item as the first and only parameter. returning false from the function will stop the iteration.
14644 * @param {Function} fn The function to execute for each item.
14645 * @param {Object} scope (optional) The scope in which to execute the function.
14647 each : function(fn, scope){
14648 var items = [].concat(this.items); // each safe for removal
14649 for(var i = 0, len = items.length; i < len; i++){
14650 if(fn.call(scope || items[i], items[i], i, len) === false){
14657 * Executes the specified function once for every key in the collection, passing each
14658 * key, and its associated item as the first two parameters.
14659 * @param {Function} fn The function to execute for each item.
14660 * @param {Object} scope (optional) The scope in which to execute the function.
14662 eachKey : function(fn, scope){
14663 for(var i = 0, len = this.keys.length; i < len; i++){
14664 fn.call(scope || window, this.keys[i], this.items[i], i, len);
14669 * Returns the first item in the collection which elicits a true return value from the
14670 * passed selection function.
14671 * @param {Function} fn The selection function to execute for each item.
14672 * @param {Object} scope (optional) The scope in which to execute the function.
14673 * @return {Object} The first item in the collection which returned true from the selection function.
14675 find : function(fn, scope){
14676 for(var i = 0, len = this.items.length; i < len; i++){
14677 if(fn.call(scope || window, this.items[i], this.keys[i])){
14678 return this.items[i];
14685 * Inserts an item at the specified index in the collection.
14686 * @param {Number} index The index to insert the item at.
14687 * @param {String} key The key to associate with the new item, or the item itself.
14688 * @param {Object} o (optional) If the second parameter was a key, the new item.
14689 * @return {Object} The item inserted.
14691 insert : function(index, key, o){
14692 if(arguments.length == 2){
14694 key = this.getKey(o);
14696 if(index >= this.length){
14697 return this.add(key, o);
14700 this.items.splice(index, 0, o);
14701 if(typeof key != "undefined" && key != null){
14704 this.keys.splice(index, 0, key);
14705 this.fireEvent("add", index, o, key);
14710 * Removed an item from the collection.
14711 * @param {Object} o The item to remove.
14712 * @return {Object} The item removed.
14714 remove : function(o){
14715 return this.removeAt(this.indexOf(o));
14719 * Remove an item from a specified index in the collection.
14720 * @param {Number} index The index within the collection of the item to remove.
14722 removeAt : function(index){
14723 if(index < this.length && index >= 0){
14725 var o = this.items[index];
14726 this.items.splice(index, 1);
14727 var key = this.keys[index];
14728 if(typeof key != "undefined"){
14729 delete this.map[key];
14731 this.keys.splice(index, 1);
14732 this.fireEvent("remove", o, key);
14737 * Removed an item associated with the passed key fom the collection.
14738 * @param {String} key The key of the item to remove.
14740 removeKey : function(key){
14741 return this.removeAt(this.indexOfKey(key));
14745 * Returns the number of items in the collection.
14746 * @return {Number} the number of items in the collection.
14748 getCount : function(){
14749 return this.length;
14753 * Returns index within the collection of the passed Object.
14754 * @param {Object} o The item to find the index of.
14755 * @return {Number} index of the item.
14757 indexOf : function(o){
14758 if(!this.items.indexOf){
14759 for(var i = 0, len = this.items.length; i < len; i++){
14760 if(this.items[i] == o) {
14766 return this.items.indexOf(o);
14771 * Returns index within the collection of the passed key.
14772 * @param {String} key The key to find the index of.
14773 * @return {Number} index of the key.
14775 indexOfKey : function(key){
14776 if(!this.keys.indexOf){
14777 for(var i = 0, len = this.keys.length; i < len; i++){
14778 if(this.keys[i] == key) {
14784 return this.keys.indexOf(key);
14789 * Returns the item associated with the passed key OR index. Key has priority over index.
14790 * @param {String/Number} key The key or index of the item.
14791 * @return {Object} The item associated with the passed key.
14793 item : function(key){
14794 if (key === 'length') {
14797 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
14798 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
14802 * Returns the item at the specified index.
14803 * @param {Number} index The index of the item.
14806 itemAt : function(index){
14807 return this.items[index];
14811 * Returns the item associated with the passed key.
14812 * @param {String/Number} key The key of the item.
14813 * @return {Object} The item associated with the passed key.
14815 key : function(key){
14816 return this.map[key];
14820 * Returns true if the collection contains the passed Object as an item.
14821 * @param {Object} o The Object to look for in the collection.
14822 * @return {Boolean} True if the collection contains the Object as an item.
14824 contains : function(o){
14825 return this.indexOf(o) != -1;
14829 * Returns true if the collection contains the passed Object as a key.
14830 * @param {String} key The key to look for in the collection.
14831 * @return {Boolean} True if the collection contains the Object as a key.
14833 containsKey : function(key){
14834 return typeof this.map[key] != "undefined";
14838 * Removes all items from the collection.
14840 clear : function(){
14845 this.fireEvent("clear");
14849 * Returns the first item in the collection.
14850 * @return {Object} the first item in the collection..
14852 first : function(){
14853 return this.items[0];
14857 * Returns the last item in the collection.
14858 * @return {Object} the last item in the collection..
14861 return this.items[this.length-1];
14864 _sort : function(property, dir, fn){
14865 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
14866 fn = fn || function(a, b){
14869 var c = [], k = this.keys, items = this.items;
14870 for(var i = 0, len = items.length; i < len; i++){
14871 c[c.length] = {key: k[i], value: items[i], index: i};
14873 c.sort(function(a, b){
14874 var v = fn(a[property], b[property]) * dsc;
14876 v = (a.index < b.index ? -1 : 1);
14880 for(var i = 0, len = c.length; i < len; i++){
14881 items[i] = c[i].value;
14884 this.fireEvent("sort", this);
14888 * Sorts this collection with the passed comparison function
14889 * @param {String} direction (optional) "ASC" or "DESC"
14890 * @param {Function} fn (optional) comparison function
14892 sort : function(dir, fn){
14893 this._sort("value", dir, fn);
14897 * Sorts this collection by keys
14898 * @param {String} direction (optional) "ASC" or "DESC"
14899 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
14901 keySort : function(dir, fn){
14902 this._sort("key", dir, fn || function(a, b){
14903 return String(a).toUpperCase()-String(b).toUpperCase();
14908 * Returns a range of items in this collection
14909 * @param {Number} startIndex (optional) defaults to 0
14910 * @param {Number} endIndex (optional) default to the last item
14911 * @return {Array} An array of items
14913 getRange : function(start, end){
14914 var items = this.items;
14915 if(items.length < 1){
14918 start = start || 0;
14919 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
14922 for(var i = start; i <= end; i++) {
14923 r[r.length] = items[i];
14926 for(var i = start; i >= end; i--) {
14927 r[r.length] = items[i];
14934 * Filter the <i>objects</i> in this collection by a specific property.
14935 * Returns a new collection that has been filtered.
14936 * @param {String} property A property on your objects
14937 * @param {String/RegExp} value Either string that the property values
14938 * should start with or a RegExp to test against the property
14939 * @return {MixedCollection} The new filtered collection
14941 filter : function(property, value){
14942 if(!value.exec){ // not a regex
14943 value = String(value);
14944 if(value.length == 0){
14945 return this.clone();
14947 value = new RegExp("^" + Roo.escapeRe(value), "i");
14949 return this.filterBy(function(o){
14950 return o && value.test(o[property]);
14955 * Filter by a function. * Returns a new collection that has been filtered.
14956 * The passed function will be called with each
14957 * object in the collection. If the function returns true, the value is included
14958 * otherwise it is filtered.
14959 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
14960 * @param {Object} scope (optional) The scope of the function (defaults to this)
14961 * @return {MixedCollection} The new filtered collection
14963 filterBy : function(fn, scope){
14964 var r = new Roo.util.MixedCollection();
14965 r.getKey = this.getKey;
14966 var k = this.keys, it = this.items;
14967 for(var i = 0, len = it.length; i < len; i++){
14968 if(fn.call(scope||this, it[i], k[i])){
14969 r.add(k[i], it[i]);
14976 * Creates a duplicate of this collection
14977 * @return {MixedCollection}
14979 clone : function(){
14980 var r = new Roo.util.MixedCollection();
14981 var k = this.keys, it = this.items;
14982 for(var i = 0, len = it.length; i < len; i++){
14983 r.add(k[i], it[i]);
14985 r.getKey = this.getKey;
14990 * Returns the item associated with the passed key or index.
14992 * @param {String/Number} key The key or index of the item.
14993 * @return {Object} The item associated with the passed key.
14995 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
14997 * Ext JS Library 1.1.1
14998 * Copyright(c) 2006-2007, Ext JS, LLC.
15000 * Originally Released Under LGPL - original licence link has changed is not relivant.
15003 * <script type="text/javascript">
15006 * @class Roo.util.JSON
15007 * Modified version of Douglas Crockford"s json.js that doesn"t
15008 * mess with the Object prototype
15009 * http://www.json.org/js.html
15012 Roo.util.JSON = new (function(){
15013 var useHasOwn = {}.hasOwnProperty ? true : false;
15015 // crashes Safari in some instances
15016 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
15018 var pad = function(n) {
15019 return n < 10 ? "0" + n : n;
15032 var encodeString = function(s){
15033 if (/["\\\x00-\x1f]/.test(s)) {
15034 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
15039 c = b.charCodeAt();
15041 Math.floor(c / 16).toString(16) +
15042 (c % 16).toString(16);
15045 return '"' + s + '"';
15048 var encodeArray = function(o){
15049 var a = ["["], b, i, l = o.length, v;
15050 for (i = 0; i < l; i += 1) {
15052 switch (typeof v) {
15061 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
15069 var encodeDate = function(o){
15070 return '"' + o.getFullYear() + "-" +
15071 pad(o.getMonth() + 1) + "-" +
15072 pad(o.getDate()) + "T" +
15073 pad(o.getHours()) + ":" +
15074 pad(o.getMinutes()) + ":" +
15075 pad(o.getSeconds()) + '"';
15079 * Encodes an Object, Array or other value
15080 * @param {Mixed} o The variable to encode
15081 * @return {String} The JSON string
15083 this.encode = function(o)
15085 // should this be extended to fully wrap stringify..
15087 if(typeof o == "undefined" || o === null){
15089 }else if(o instanceof Array){
15090 return encodeArray(o);
15091 }else if(o instanceof Date){
15092 return encodeDate(o);
15093 }else if(typeof o == "string"){
15094 return encodeString(o);
15095 }else if(typeof o == "number"){
15096 return isFinite(o) ? String(o) : "null";
15097 }else if(typeof o == "boolean"){
15100 var a = ["{"], b, i, v;
15102 if(!useHasOwn || o.hasOwnProperty(i)) {
15104 switch (typeof v) {
15113 a.push(this.encode(i), ":",
15114 v === null ? "null" : this.encode(v));
15125 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
15126 * @param {String} json The JSON string
15127 * @return {Object} The resulting object
15129 this.decode = function(json){
15131 return /** eval:var:json */ eval("(" + json + ')');
15135 * Shorthand for {@link Roo.util.JSON#encode}
15136 * @member Roo encode
15138 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
15140 * Shorthand for {@link Roo.util.JSON#decode}
15141 * @member Roo decode
15143 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
15146 * Ext JS Library 1.1.1
15147 * Copyright(c) 2006-2007, Ext JS, LLC.
15149 * Originally Released Under LGPL - original licence link has changed is not relivant.
15152 * <script type="text/javascript">
15156 * @class Roo.util.Format
15157 * Reusable data formatting functions
15160 Roo.util.Format = function(){
15161 var trimRe = /^\s+|\s+$/g;
15164 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
15165 * @param {String} value The string to truncate
15166 * @param {Number} length The maximum length to allow before truncating
15167 * @return {String} The converted text
15169 ellipsis : function(value, len){
15170 if(value && value.length > len){
15171 return value.substr(0, len-3)+"...";
15177 * Checks a reference and converts it to empty string if it is undefined
15178 * @param {Mixed} value Reference to check
15179 * @return {Mixed} Empty string if converted, otherwise the original value
15181 undef : function(value){
15182 return typeof value != "undefined" ? value : "";
15186 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
15187 * @param {String} value The string to encode
15188 * @return {String} The encoded text
15190 htmlEncode : function(value){
15191 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
15195 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
15196 * @param {String} value The string to decode
15197 * @return {String} The decoded text
15199 htmlDecode : function(value){
15200 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
15204 * Trims any whitespace from either side of a string
15205 * @param {String} value The text to trim
15206 * @return {String} The trimmed text
15208 trim : function(value){
15209 return String(value).replace(trimRe, "");
15213 * Returns a substring from within an original string
15214 * @param {String} value The original text
15215 * @param {Number} start The start index of the substring
15216 * @param {Number} length The length of the substring
15217 * @return {String} The substring
15219 substr : function(value, start, length){
15220 return String(value).substr(start, length);
15224 * Converts a string to all lower case letters
15225 * @param {String} value The text to convert
15226 * @return {String} The converted text
15228 lowercase : function(value){
15229 return String(value).toLowerCase();
15233 * Converts a string to all upper case letters
15234 * @param {String} value The text to convert
15235 * @return {String} The converted text
15237 uppercase : function(value){
15238 return String(value).toUpperCase();
15242 * Converts the first character only of a string to upper case
15243 * @param {String} value The text to convert
15244 * @return {String} The converted text
15246 capitalize : function(value){
15247 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
15251 call : function(value, fn){
15252 if(arguments.length > 2){
15253 var args = Array.prototype.slice.call(arguments, 2);
15254 args.unshift(value);
15256 return /** eval:var:value */ eval(fn).apply(window, args);
15258 /** eval:var:value */
15259 return /** eval:var:value */ eval(fn).call(window, value);
15265 * safer version of Math.toFixed..??/
15266 * @param {Number/String} value The numeric value to format
15267 * @param {Number/String} value Decimal places
15268 * @return {String} The formatted currency string
15270 toFixed : function(v, n)
15272 // why not use to fixed - precision is buggered???
15274 return Math.round(v-0);
15276 var fact = Math.pow(10,n+1);
15277 v = (Math.round((v-0)*fact))/fact;
15278 var z = (''+fact).substring(2);
15279 if (v == Math.floor(v)) {
15280 return Math.floor(v) + '.' + z;
15283 // now just padd decimals..
15284 var ps = String(v).split('.');
15285 var fd = (ps[1] + z);
15286 var r = fd.substring(0,n);
15287 var rm = fd.substring(n);
15289 return ps[0] + '.' + r;
15291 r*=1; // turn it into a number;
15293 if (String(r).length != n) {
15296 r = String(r).substring(1); // chop the end off.
15299 return ps[0] + '.' + r;
15304 * Format a number as US currency
15305 * @param {Number/String} value The numeric value to format
15306 * @return {String} The formatted currency string
15308 usMoney : function(v){
15309 return '$' + Roo.util.Format.number(v);
15314 * eventually this should probably emulate php's number_format
15315 * @param {Number/String} value The numeric value to format
15316 * @param {Number} decimals number of decimal places
15317 * @param {String} delimiter for thousands (default comma)
15318 * @return {String} The formatted currency string
15320 number : function(v, decimals, thousandsDelimiter)
15322 // multiply and round.
15323 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
15324 thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
15326 var mul = Math.pow(10, decimals);
15327 var zero = String(mul).substring(1);
15328 v = (Math.round((v-0)*mul))/mul;
15330 // if it's '0' number.. then
15332 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
15334 var ps = v.split('.');
15337 var r = /(\d+)(\d{3})/;
15340 if(thousandsDelimiter.length != 0) {
15341 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
15346 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
15347 // does not have decimals
15348 (decimals ? ('.' + zero) : '');
15351 return whole + sub ;
15355 * Parse a value into a formatted date using the specified format pattern.
15356 * @param {Mixed} value The value to format
15357 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
15358 * @return {String} The formatted date string
15360 date : function(v, format){
15364 if(!(v instanceof Date)){
15365 v = new Date(Date.parse(v));
15367 return v.dateFormat(format || Roo.util.Format.defaults.date);
15371 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
15372 * @param {String} format Any valid date format string
15373 * @return {Function} The date formatting function
15375 dateRenderer : function(format){
15376 return function(v){
15377 return Roo.util.Format.date(v, format);
15382 stripTagsRE : /<\/?[^>]+>/gi,
15385 * Strips all HTML tags
15386 * @param {Mixed} value The text from which to strip tags
15387 * @return {String} The stripped text
15389 stripTags : function(v){
15390 return !v ? v : String(v).replace(this.stripTagsRE, "");
15394 * Size in Mb,Gb etc.
15395 * @param {Number} value The number to be formated
15396 * @param {number} decimals how many decimal places
15397 * @return {String} the formated string
15399 size : function(value, decimals)
15401 var sizes = ['b', 'k', 'M', 'G', 'T'];
15405 var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
15406 return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals) + sizes[i];
15413 Roo.util.Format.defaults = {
15417 * Ext JS Library 1.1.1
15418 * Copyright(c) 2006-2007, Ext JS, LLC.
15420 * Originally Released Under LGPL - original licence link has changed is not relivant.
15423 * <script type="text/javascript">
15430 * @class Roo.MasterTemplate
15431 * @extends Roo.Template
15432 * Provides a template that can have child templates. The syntax is:
15434 var t = new Roo.MasterTemplate(
15435 '<select name="{name}">',
15436 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
15439 t.add('options', {value: 'foo', text: 'bar'});
15440 // or you can add multiple child elements in one shot
15441 t.addAll('options', [
15442 {value: 'foo', text: 'bar'},
15443 {value: 'foo2', text: 'bar2'},
15444 {value: 'foo3', text: 'bar3'}
15446 // then append, applying the master template values
15447 t.append('my-form', {name: 'my-select'});
15449 * A name attribute for the child template is not required if you have only one child
15450 * template or you want to refer to them by index.
15452 Roo.MasterTemplate = function(){
15453 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
15454 this.originalHtml = this.html;
15456 var m, re = this.subTemplateRe;
15459 while(m = re.exec(this.html)){
15460 var name = m[1], content = m[2];
15465 tpl : new Roo.Template(content)
15468 st[name] = st[subIndex];
15470 st[subIndex].tpl.compile();
15471 st[subIndex].tpl.call = this.call.createDelegate(this);
15474 this.subCount = subIndex;
15477 Roo.extend(Roo.MasterTemplate, Roo.Template, {
15479 * The regular expression used to match sub templates
15483 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
15486 * Applies the passed values to a child template.
15487 * @param {String/Number} name (optional) The name or index of the child template
15488 * @param {Array/Object} values The values to be applied to the template
15489 * @return {MasterTemplate} this
15491 add : function(name, values){
15492 if(arguments.length == 1){
15493 values = arguments[0];
15496 var s = this.subs[name];
15497 s.buffer[s.buffer.length] = s.tpl.apply(values);
15502 * Applies all the passed values to a child template.
15503 * @param {String/Number} name (optional) The name or index of the child template
15504 * @param {Array} values The values to be applied to the template, this should be an array of objects.
15505 * @param {Boolean} reset (optional) True to reset the template first
15506 * @return {MasterTemplate} this
15508 fill : function(name, values, reset){
15510 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
15518 for(var i = 0, len = values.length; i < len; i++){
15519 this.add(name, values[i]);
15525 * Resets the template for reuse
15526 * @return {MasterTemplate} this
15528 reset : function(){
15530 for(var i = 0; i < this.subCount; i++){
15536 applyTemplate : function(values){
15538 var replaceIndex = -1;
15539 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
15540 return s[++replaceIndex].buffer.join("");
15542 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
15545 apply : function(){
15546 return this.applyTemplate.apply(this, arguments);
15549 compile : function(){return this;}
15553 * Alias for fill().
15556 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
15558 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
15559 * var tpl = Roo.MasterTemplate.from('element-id');
15560 * @param {String/HTMLElement} el
15561 * @param {Object} config
15564 Roo.MasterTemplate.from = function(el, config){
15565 el = Roo.getDom(el);
15566 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
15569 * Ext JS Library 1.1.1
15570 * Copyright(c) 2006-2007, Ext JS, LLC.
15572 * Originally Released Under LGPL - original licence link has changed is not relivant.
15575 * <script type="text/javascript">
15580 * @class Roo.util.CSS
15581 * Utility class for manipulating CSS rules
15585 Roo.util.CSS = function(){
15587 var doc = document;
15589 var camelRe = /(-[a-z])/gi;
15590 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
15594 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
15595 * tag and appended to the HEAD of the document.
15596 * @param {String|Object} cssText The text containing the css rules
15597 * @param {String} id An id to add to the stylesheet for later removal
15598 * @return {StyleSheet}
15600 createStyleSheet : function(cssText, id){
15602 var head = doc.getElementsByTagName("head")[0];
15603 var nrules = doc.createElement("style");
15604 nrules.setAttribute("type", "text/css");
15606 nrules.setAttribute("id", id);
15608 if (typeof(cssText) != 'string') {
15609 // support object maps..
15610 // not sure if this a good idea..
15611 // perhaps it should be merged with the general css handling
15612 // and handle js style props.
15613 var cssTextNew = [];
15614 for(var n in cssText) {
15616 for(var k in cssText[n]) {
15617 citems.push( k + ' : ' +cssText[n][k] + ';' );
15619 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
15622 cssText = cssTextNew.join("\n");
15628 head.appendChild(nrules);
15629 ss = nrules.styleSheet;
15630 ss.cssText = cssText;
15633 nrules.appendChild(doc.createTextNode(cssText));
15635 nrules.cssText = cssText;
15637 head.appendChild(nrules);
15638 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
15640 this.cacheStyleSheet(ss);
15645 * Removes a style or link tag by id
15646 * @param {String} id The id of the tag
15648 removeStyleSheet : function(id){
15649 var existing = doc.getElementById(id);
15651 existing.parentNode.removeChild(existing);
15656 * Dynamically swaps an existing stylesheet reference for a new one
15657 * @param {String} id The id of an existing link tag to remove
15658 * @param {String} url The href of the new stylesheet to include
15660 swapStyleSheet : function(id, url){
15661 this.removeStyleSheet(id);
15662 var ss = doc.createElement("link");
15663 ss.setAttribute("rel", "stylesheet");
15664 ss.setAttribute("type", "text/css");
15665 ss.setAttribute("id", id);
15666 ss.setAttribute("href", url);
15667 doc.getElementsByTagName("head")[0].appendChild(ss);
15671 * Refresh the rule cache if you have dynamically added stylesheets
15672 * @return {Object} An object (hash) of rules indexed by selector
15674 refreshCache : function(){
15675 return this.getRules(true);
15679 cacheStyleSheet : function(stylesheet){
15683 try{// try catch for cross domain access issue
15684 var ssRules = stylesheet.cssRules || stylesheet.rules;
15685 for(var j = ssRules.length-1; j >= 0; --j){
15686 rules[ssRules[j].selectorText] = ssRules[j];
15692 * Gets all css rules for the document
15693 * @param {Boolean} refreshCache true to refresh the internal cache
15694 * @return {Object} An object (hash) of rules indexed by selector
15696 getRules : function(refreshCache){
15697 if(rules == null || refreshCache){
15699 var ds = doc.styleSheets;
15700 for(var i =0, len = ds.length; i < len; i++){
15702 this.cacheStyleSheet(ds[i]);
15710 * Gets an an individual CSS rule by selector(s)
15711 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
15712 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
15713 * @return {CSSRule} The CSS rule or null if one is not found
15715 getRule : function(selector, refreshCache){
15716 var rs = this.getRules(refreshCache);
15717 if(!(selector instanceof Array)){
15718 return rs[selector];
15720 for(var i = 0; i < selector.length; i++){
15721 if(rs[selector[i]]){
15722 return rs[selector[i]];
15730 * Updates a rule property
15731 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
15732 * @param {String} property The css property
15733 * @param {String} value The new value for the property
15734 * @return {Boolean} true If a rule was found and updated
15736 updateRule : function(selector, property, value){
15737 if(!(selector instanceof Array)){
15738 var rule = this.getRule(selector);
15740 rule.style[property.replace(camelRe, camelFn)] = value;
15744 for(var i = 0; i < selector.length; i++){
15745 if(this.updateRule(selector[i], property, value)){
15755 * Ext JS Library 1.1.1
15756 * Copyright(c) 2006-2007, Ext JS, LLC.
15758 * Originally Released Under LGPL - original licence link has changed is not relivant.
15761 * <script type="text/javascript">
15767 * @class Roo.util.ClickRepeater
15768 * @extends Roo.util.Observable
15770 * A wrapper class which can be applied to any element. Fires a "click" event while the
15771 * mouse is pressed. The interval between firings may be specified in the config but
15772 * defaults to 10 milliseconds.
15774 * Optionally, a CSS class may be applied to the element during the time it is pressed.
15776 * @cfg {String/HTMLElement/Element} el The element to act as a button.
15777 * @cfg {Number} delay The initial delay before the repeating event begins firing.
15778 * Similar to an autorepeat key delay.
15779 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
15780 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
15781 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
15782 * "interval" and "delay" are ignored. "immediate" is honored.
15783 * @cfg {Boolean} preventDefault True to prevent the default click event
15784 * @cfg {Boolean} stopDefault True to stop the default click event
15787 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
15788 * 2007-02-02 jvs Renamed to ClickRepeater
15789 * 2007-02-03 jvs Modifications for FF Mac and Safari
15792 * @param {String/HTMLElement/Element} el The element to listen on
15793 * @param {Object} config
15795 Roo.util.ClickRepeater = function(el, config)
15797 this.el = Roo.get(el);
15798 this.el.unselectable();
15800 Roo.apply(this, config);
15805 * Fires when the mouse button is depressed.
15806 * @param {Roo.util.ClickRepeater} this
15808 "mousedown" : true,
15811 * Fires on a specified interval during the time the element is pressed.
15812 * @param {Roo.util.ClickRepeater} this
15817 * Fires when the mouse key is released.
15818 * @param {Roo.util.ClickRepeater} this
15823 this.el.on("mousedown", this.handleMouseDown, this);
15824 if(this.preventDefault || this.stopDefault){
15825 this.el.on("click", function(e){
15826 if(this.preventDefault){
15827 e.preventDefault();
15829 if(this.stopDefault){
15835 // allow inline handler
15837 this.on("click", this.handler, this.scope || this);
15840 Roo.util.ClickRepeater.superclass.constructor.call(this);
15843 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
15846 preventDefault : true,
15847 stopDefault : false,
15851 handleMouseDown : function(){
15852 clearTimeout(this.timer);
15854 if(this.pressClass){
15855 this.el.addClass(this.pressClass);
15857 this.mousedownTime = new Date();
15859 Roo.get(document).on("mouseup", this.handleMouseUp, this);
15860 this.el.on("mouseout", this.handleMouseOut, this);
15862 this.fireEvent("mousedown", this);
15863 this.fireEvent("click", this);
15865 this.timer = this.click.defer(this.delay || this.interval, this);
15869 click : function(){
15870 this.fireEvent("click", this);
15871 this.timer = this.click.defer(this.getInterval(), this);
15875 getInterval: function(){
15876 if(!this.accelerate){
15877 return this.interval;
15879 var pressTime = this.mousedownTime.getElapsed();
15880 if(pressTime < 500){
15882 }else if(pressTime < 1700){
15884 }else if(pressTime < 2600){
15886 }else if(pressTime < 3500){
15888 }else if(pressTime < 4400){
15890 }else if(pressTime < 5300){
15892 }else if(pressTime < 6200){
15900 handleMouseOut : function(){
15901 clearTimeout(this.timer);
15902 if(this.pressClass){
15903 this.el.removeClass(this.pressClass);
15905 this.el.on("mouseover", this.handleMouseReturn, this);
15909 handleMouseReturn : function(){
15910 this.el.un("mouseover", this.handleMouseReturn);
15911 if(this.pressClass){
15912 this.el.addClass(this.pressClass);
15918 handleMouseUp : function(){
15919 clearTimeout(this.timer);
15920 this.el.un("mouseover", this.handleMouseReturn);
15921 this.el.un("mouseout", this.handleMouseOut);
15922 Roo.get(document).un("mouseup", this.handleMouseUp);
15923 this.el.removeClass(this.pressClass);
15924 this.fireEvent("mouseup", this);
15927 * @class Roo.util.Clipboard
15933 Roo.util.Clipboard = {
15935 * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
15936 * @param {String} text to copy to clipboard
15938 write : function(text) {
15939 // navigator clipboard api needs a secure context (https)
15940 if (navigator.clipboard && window.isSecureContext) {
15941 // navigator clipboard api method'
15942 navigator.clipboard.writeText(text);
15945 // text area method
15946 var ta = document.createElement("textarea");
15948 // make the textarea out of viewport
15949 ta.style.position = "fixed";
15950 ta.style.left = "-999999px";
15951 ta.style.top = "-999999px";
15952 document.body.appendChild(ta);
15955 document.execCommand('copy');
15965 * Ext JS Library 1.1.1
15966 * Copyright(c) 2006-2007, Ext JS, LLC.
15968 * Originally Released Under LGPL - original licence link has changed is not relivant.
15971 * <script type="text/javascript">
15976 * @class Roo.KeyNav
15977 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
15978 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
15979 * way to implement custom navigation schemes for any UI component.</p>
15980 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
15981 * pageUp, pageDown, del, home, end. Usage:</p>
15983 var nav = new Roo.KeyNav("my-element", {
15984 "left" : function(e){
15985 this.moveLeft(e.ctrlKey);
15987 "right" : function(e){
15988 this.moveRight(e.ctrlKey);
15990 "enter" : function(e){
15997 * @param {String/HTMLElement/Roo.Element} el The element to bind to
15998 * @param {Object} config The config
16000 Roo.KeyNav = function(el, config){
16001 this.el = Roo.get(el);
16002 Roo.apply(this, config);
16003 if(!this.disabled){
16004 this.disabled = true;
16009 Roo.KeyNav.prototype = {
16011 * @cfg {Boolean} disabled
16012 * True to disable this KeyNav instance (defaults to false)
16016 * @cfg {String} defaultEventAction
16017 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
16018 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
16019 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
16021 defaultEventAction: "stopEvent",
16023 * @cfg {Boolean} forceKeyDown
16024 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
16025 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
16026 * handle keydown instead of keypress.
16028 forceKeyDown : false,
16031 prepareEvent : function(e){
16032 var k = e.getKey();
16033 var h = this.keyToHandler[k];
16034 //if(h && this[h]){
16035 // e.stopPropagation();
16037 if(Roo.isSafari && h && k >= 37 && k <= 40){
16043 relay : function(e){
16044 var k = e.getKey();
16045 var h = this.keyToHandler[k];
16047 if(this.doRelay(e, this[h], h) !== true){
16048 e[this.defaultEventAction]();
16054 doRelay : function(e, h, hname){
16055 return h.call(this.scope || this, e);
16058 // possible handlers
16072 // quick lookup hash
16089 * Enable this KeyNav
16091 enable: function(){
16093 // ie won't do special keys on keypress, no one else will repeat keys with keydown
16094 // the EventObject will normalize Safari automatically
16095 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
16096 this.el.on("keydown", this.relay, this);
16098 this.el.on("keydown", this.prepareEvent, this);
16099 this.el.on("keypress", this.relay, this);
16101 this.disabled = false;
16106 * Disable this KeyNav
16108 disable: function(){
16109 if(!this.disabled){
16110 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
16111 this.el.un("keydown", this.relay);
16113 this.el.un("keydown", this.prepareEvent);
16114 this.el.un("keypress", this.relay);
16116 this.disabled = true;
16121 * Ext JS Library 1.1.1
16122 * Copyright(c) 2006-2007, Ext JS, LLC.
16124 * Originally Released Under LGPL - original licence link has changed is not relivant.
16127 * <script type="text/javascript">
16132 * @class Roo.KeyMap
16133 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
16134 * The constructor accepts the same config object as defined by {@link #addBinding}.
16135 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
16136 * combination it will call the function with this signature (if the match is a multi-key
16137 * combination the callback will still be called only once): (String key, Roo.EventObject e)
16138 * A KeyMap can also handle a string representation of keys.<br />
16141 // map one key by key code
16142 var map = new Roo.KeyMap("my-element", {
16143 key: 13, // or Roo.EventObject.ENTER
16148 // map multiple keys to one action by string
16149 var map = new Roo.KeyMap("my-element", {
16155 // map multiple keys to multiple actions by strings and array of codes
16156 var map = new Roo.KeyMap("my-element", [
16159 fn: function(){ alert("Return was pressed"); }
16162 fn: function(){ alert('a, b or c was pressed'); }
16167 fn: function(){ alert('Control + shift + tab was pressed.'); }
16171 * <b>Note: A KeyMap starts enabled</b>
16173 * @param {String/HTMLElement/Roo.Element} el The element to bind to
16174 * @param {Object} config The config (see {@link #addBinding})
16175 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
16177 Roo.KeyMap = function(el, config, eventName){
16178 this.el = Roo.get(el);
16179 this.eventName = eventName || "keydown";
16180 this.bindings = [];
16182 this.addBinding(config);
16187 Roo.KeyMap.prototype = {
16189 * True to stop the event from bubbling and prevent the default browser action if the
16190 * key was handled by the KeyMap (defaults to false)
16196 * Add a new binding to this KeyMap. The following config object properties are supported:
16198 Property Type Description
16199 ---------- --------------- ----------------------------------------------------------------------
16200 key String/Array A single keycode or an array of keycodes to handle
16201 shift Boolean True to handle key only when shift is pressed (defaults to false)
16202 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
16203 alt Boolean True to handle key only when alt is pressed (defaults to false)
16204 fn Function The function to call when KeyMap finds the expected key combination
16205 scope Object The scope of the callback function
16211 var map = new Roo.KeyMap(document, {
16212 key: Roo.EventObject.ENTER,
16217 //Add a new binding to the existing KeyMap later
16225 * @param {Object/Array} config A single KeyMap config or an array of configs
16227 addBinding : function(config){
16228 if(config instanceof Array){
16229 for(var i = 0, len = config.length; i < len; i++){
16230 this.addBinding(config[i]);
16234 var keyCode = config.key,
16235 shift = config.shift,
16236 ctrl = config.ctrl,
16239 scope = config.scope;
16240 if(typeof keyCode == "string"){
16242 var keyString = keyCode.toUpperCase();
16243 for(var j = 0, len = keyString.length; j < len; j++){
16244 ks.push(keyString.charCodeAt(j));
16248 var keyArray = keyCode instanceof Array;
16249 var handler = function(e){
16250 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
16251 var k = e.getKey();
16253 for(var i = 0, len = keyCode.length; i < len; i++){
16254 if(keyCode[i] == k){
16255 if(this.stopEvent){
16258 fn.call(scope || window, k, e);
16264 if(this.stopEvent){
16267 fn.call(scope || window, k, e);
16272 this.bindings.push(handler);
16276 * Shorthand for adding a single key listener
16277 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
16278 * following options:
16279 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
16280 * @param {Function} fn The function to call
16281 * @param {Object} scope (optional) The scope of the function
16283 on : function(key, fn, scope){
16284 var keyCode, shift, ctrl, alt;
16285 if(typeof key == "object" && !(key instanceof Array)){
16304 handleKeyDown : function(e){
16305 if(this.enabled){ //just in case
16306 var b = this.bindings;
16307 for(var i = 0, len = b.length; i < len; i++){
16308 b[i].call(this, e);
16314 * Returns true if this KeyMap is enabled
16315 * @return {Boolean}
16317 isEnabled : function(){
16318 return this.enabled;
16322 * Enables this KeyMap
16324 enable: function(){
16326 this.el.on(this.eventName, this.handleKeyDown, this);
16327 this.enabled = true;
16332 * Disable this KeyMap
16334 disable: function(){
16336 this.el.removeListener(this.eventName, this.handleKeyDown, this);
16337 this.enabled = false;
16342 * Ext JS Library 1.1.1
16343 * Copyright(c) 2006-2007, Ext JS, LLC.
16345 * Originally Released Under LGPL - original licence link has changed is not relivant.
16348 * <script type="text/javascript">
16353 * @class Roo.util.TextMetrics
16354 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
16355 * wide, in pixels, a given block of text will be.
16358 Roo.util.TextMetrics = function(){
16362 * Measures the size of the specified text
16363 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
16364 * that can affect the size of the rendered text
16365 * @param {String} text The text to measure
16366 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
16367 * in order to accurately measure the text height
16368 * @return {Object} An object containing the text's size {width: (width), height: (height)}
16370 measure : function(el, text, fixedWidth){
16372 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
16375 shared.setFixedWidth(fixedWidth || 'auto');
16376 return shared.getSize(text);
16380 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
16381 * the overhead of multiple calls to initialize the style properties on each measurement.
16382 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
16383 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
16384 * in order to accurately measure the text height
16385 * @return {Roo.util.TextMetrics.Instance} instance The new instance
16387 createInstance : function(el, fixedWidth){
16388 return Roo.util.TextMetrics.Instance(el, fixedWidth);
16394 * @class Roo.util.TextMetrics.Instance
16395 * Instance of TextMetrics Calcuation
16397 * Create a new TextMetrics Instance
16398 * @param {Object} bindto
16399 * @param {Boolean} fixedWidth
16402 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth)
16404 var ml = new Roo.Element(document.createElement('div'));
16405 document.body.appendChild(ml.dom);
16406 ml.position('absolute');
16407 ml.setLeftTop(-1000, -1000);
16411 ml.setWidth(fixedWidth);
16416 * Returns the size of the specified text based on the internal element's style and width properties
16417 * @param {String} text The text to measure
16418 * @return {Object} An object containing the text's size {width: (width), height: (height)}
16420 getSize : function(text){
16422 var s = ml.getSize();
16428 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
16429 * that can affect the size of the rendered text
16430 * @param {String/HTMLElement} el The element, dom node or id
16432 bind : function(el){
16434 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
16439 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
16440 * to set a fixed width in order to accurately measure the text height.
16441 * @param {Number} width The width to set on the element
16443 setFixedWidth : function(width){
16444 ml.setWidth(width);
16448 * Returns the measured width of the specified text
16449 * @param {String} text The text to measure
16450 * @return {Number} width The width in pixels
16452 getWidth : function(text){
16453 ml.dom.style.width = 'auto';
16454 return this.getSize(text).width;
16458 * Returns the measured height of the specified text. For multiline text, be sure to call
16459 * {@link #setFixedWidth} if necessary.
16460 * @param {String} text The text to measure
16461 * @return {Number} height The height in pixels
16463 getHeight : function(text){
16464 return this.getSize(text).height;
16468 instance.bind(bindTo);
16473 // backwards compat
16474 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
16476 * Ext JS Library 1.1.1
16477 * Copyright(c) 2006-2007, Ext JS, LLC.
16479 * Originally Released Under LGPL - original licence link has changed is not relivant.
16482 * <script type="text/javascript">
16486 * @class Roo.state.Provider
16487 * Abstract base class for state provider implementations. This class provides methods
16488 * for encoding and decoding <b>typed</b> variables including dates and defines the
16489 * Provider interface.
16491 Roo.state.Provider = function(){
16493 * @event statechange
16494 * Fires when a state change occurs.
16495 * @param {Provider} this This state provider
16496 * @param {String} key The state key which was changed
16497 * @param {String} value The encoded value for the state
16500 "statechange": true
16503 Roo.state.Provider.superclass.constructor.call(this);
16505 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
16507 * Returns the current value for a key
16508 * @param {String} name The key name
16509 * @param {Mixed} defaultValue A default value to return if the key's value is not found
16510 * @return {Mixed} The state data
16512 get : function(name, defaultValue){
16513 return typeof this.state[name] == "undefined" ?
16514 defaultValue : this.state[name];
16518 * Clears a value from the state
16519 * @param {String} name The key name
16521 clear : function(name){
16522 delete this.state[name];
16523 this.fireEvent("statechange", this, name, null);
16527 * Sets the value for a key
16528 * @param {String} name The key name
16529 * @param {Mixed} value The value to set
16531 set : function(name, value){
16532 this.state[name] = value;
16533 this.fireEvent("statechange", this, name, value);
16537 * Decodes a string previously encoded with {@link #encodeValue}.
16538 * @param {String} value The value to decode
16539 * @return {Mixed} The decoded value
16541 decodeValue : function(cookie){
16542 var re = /^(a|n|d|b|s|o)\:(.*)$/;
16543 var matches = re.exec(unescape(cookie));
16544 if(!matches || !matches[1]) {
16545 return; // non state cookie
16547 var type = matches[1];
16548 var v = matches[2];
16551 return parseFloat(v);
16553 return new Date(Date.parse(v));
16558 var values = v.split("^");
16559 for(var i = 0, len = values.length; i < len; i++){
16560 all.push(this.decodeValue(values[i]));
16565 var values = v.split("^");
16566 for(var i = 0, len = values.length; i < len; i++){
16567 var kv = values[i].split("=");
16568 all[kv[0]] = this.decodeValue(kv[1]);
16577 * Encodes a value including type information. Decode with {@link #decodeValue}.
16578 * @param {Mixed} value The value to encode
16579 * @return {String} The encoded value
16581 encodeValue : function(v){
16583 if(typeof v == "number"){
16585 }else if(typeof v == "boolean"){
16586 enc = "b:" + (v ? "1" : "0");
16587 }else if(v instanceof Date){
16588 enc = "d:" + v.toGMTString();
16589 }else if(v instanceof Array){
16591 for(var i = 0, len = v.length; i < len; i++){
16592 flat += this.encodeValue(v[i]);
16598 }else if(typeof v == "object"){
16601 if(typeof v[key] != "function"){
16602 flat += key + "=" + this.encodeValue(v[key]) + "^";
16605 enc = "o:" + flat.substring(0, flat.length-1);
16609 return escape(enc);
16615 * Ext JS Library 1.1.1
16616 * Copyright(c) 2006-2007, Ext JS, LLC.
16618 * Originally Released Under LGPL - original licence link has changed is not relivant.
16621 * <script type="text/javascript">
16624 * @class Roo.state.Manager
16625 * This is the global state manager. By default all components that are "state aware" check this class
16626 * for state information if you don't pass them a custom state provider. In order for this class
16627 * to be useful, it must be initialized with a provider when your application initializes.
16629 // in your initialization function
16631 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
16633 // supposed you have a {@link Roo.BorderLayout}
16634 var layout = new Roo.BorderLayout(...);
16635 layout.restoreState();
16636 // or a {Roo.BasicDialog}
16637 var dialog = new Roo.BasicDialog(...);
16638 dialog.restoreState();
16642 Roo.state.Manager = function(){
16643 var provider = new Roo.state.Provider();
16647 * Configures the default state provider for your application
16648 * @param {Provider} stateProvider The state provider to set
16650 setProvider : function(stateProvider){
16651 provider = stateProvider;
16655 * Returns the current value for a key
16656 * @param {String} name The key name
16657 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
16658 * @return {Mixed} The state data
16660 get : function(key, defaultValue){
16661 return provider.get(key, defaultValue);
16665 * Sets the value for a key
16666 * @param {String} name The key name
16667 * @param {Mixed} value The state data
16669 set : function(key, value){
16670 provider.set(key, value);
16674 * Clears a value from the state
16675 * @param {String} name The key name
16677 clear : function(key){
16678 provider.clear(key);
16682 * Gets the currently configured state provider
16683 * @return {Provider} The state provider
16685 getProvider : function(){
16692 * Ext JS Library 1.1.1
16693 * Copyright(c) 2006-2007, Ext JS, LLC.
16695 * Originally Released Under LGPL - original licence link has changed is not relivant.
16698 * <script type="text/javascript">
16701 * @class Roo.state.CookieProvider
16702 * @extends Roo.state.Provider
16703 * The default Provider implementation which saves state via cookies.
16706 var cp = new Roo.state.CookieProvider({
16708 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
16709 domain: "roojs.com"
16711 Roo.state.Manager.setProvider(cp);
16713 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
16714 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
16715 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
16716 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
16717 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
16718 * domain the page is running on including the 'www' like 'www.roojs.com')
16719 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
16721 * Create a new CookieProvider
16722 * @param {Object} config The configuration object
16724 Roo.state.CookieProvider = function(config){
16725 Roo.state.CookieProvider.superclass.constructor.call(this);
16727 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
16728 this.domain = null;
16729 this.secure = false;
16730 Roo.apply(this, config);
16731 this.state = this.readCookies();
16734 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
16736 set : function(name, value){
16737 if(typeof value == "undefined" || value === null){
16741 this.setCookie(name, value);
16742 Roo.state.CookieProvider.superclass.set.call(this, name, value);
16746 clear : function(name){
16747 this.clearCookie(name);
16748 Roo.state.CookieProvider.superclass.clear.call(this, name);
16752 readCookies : function(){
16754 var c = document.cookie + ";";
16755 var re = /\s?(.*?)=(.*?);/g;
16757 while((matches = re.exec(c)) != null){
16758 var name = matches[1];
16759 var value = matches[2];
16760 if(name && name.substring(0,3) == "ys-"){
16761 cookies[name.substr(3)] = this.decodeValue(value);
16768 setCookie : function(name, value){
16769 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
16770 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
16771 ((this.path == null) ? "" : ("; path=" + this.path)) +
16772 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16773 ((this.secure == true) ? "; secure" : "");
16777 clearCookie : function(name){
16778 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
16779 ((this.path == null) ? "" : ("; path=" + this.path)) +
16780 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16781 ((this.secure == true) ? "; secure" : "");
16785 * Ext JS Library 1.1.1
16786 * Copyright(c) 2006-2007, Ext JS, LLC.
16788 * Originally Released Under LGPL - original licence link has changed is not relivant.
16791 * <script type="text/javascript">
16796 * @class Roo.ComponentMgr
16797 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
16800 Roo.ComponentMgr = function(){
16801 var all = new Roo.util.MixedCollection();
16805 * Registers a component.
16806 * @param {Roo.Component} c The component
16808 register : function(c){
16813 * Unregisters a component.
16814 * @param {Roo.Component} c The component
16816 unregister : function(c){
16821 * Returns a component by id
16822 * @param {String} id The component id
16824 get : function(id){
16825 return all.get(id);
16829 * Registers a function that will be called when a specified component is added to ComponentMgr
16830 * @param {String} id The component id
16831 * @param {Funtction} fn The callback function
16832 * @param {Object} scope The scope of the callback
16834 onAvailable : function(id, fn, scope){
16835 all.on("add", function(index, o){
16837 fn.call(scope || o, o);
16838 all.un("add", fn, scope);
16845 * Ext JS Library 1.1.1
16846 * Copyright(c) 2006-2007, Ext JS, LLC.
16848 * Originally Released Under LGPL - original licence link has changed is not relivant.
16851 * <script type="text/javascript">
16855 * @class Roo.Component
16856 * @extends Roo.util.Observable
16857 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
16858 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
16859 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
16860 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
16861 * All visual components (widgets) that require rendering into a layout should subclass Component.
16863 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
16864 * 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
16865 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
16867 Roo.Component = function(config){
16868 config = config || {};
16869 if(config.tagName || config.dom || typeof config == "string"){ // element object
16870 config = {el: config, id: config.id || config};
16872 this.initialConfig = config;
16874 Roo.apply(this, config);
16878 * Fires after the component is disabled.
16879 * @param {Roo.Component} this
16884 * Fires after the component is enabled.
16885 * @param {Roo.Component} this
16889 * @event beforeshow
16890 * Fires before the component is shown. Return false to stop the show.
16891 * @param {Roo.Component} this
16896 * Fires after the component is shown.
16897 * @param {Roo.Component} this
16901 * @event beforehide
16902 * Fires before the component is hidden. Return false to stop the hide.
16903 * @param {Roo.Component} this
16908 * Fires after the component is hidden.
16909 * @param {Roo.Component} this
16913 * @event beforerender
16914 * Fires before the component is rendered. Return false to stop the render.
16915 * @param {Roo.Component} this
16917 beforerender : true,
16920 * Fires after the component is rendered.
16921 * @param {Roo.Component} this
16925 * @event beforedestroy
16926 * Fires before the component is destroyed. Return false to stop the destroy.
16927 * @param {Roo.Component} this
16929 beforedestroy : true,
16932 * Fires after the component is destroyed.
16933 * @param {Roo.Component} this
16938 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
16940 Roo.ComponentMgr.register(this);
16941 Roo.Component.superclass.constructor.call(this);
16942 this.initComponent();
16943 if(this.renderTo){ // not supported by all components yet. use at your own risk!
16944 this.render(this.renderTo);
16945 delete this.renderTo;
16950 Roo.Component.AUTO_ID = 1000;
16952 Roo.extend(Roo.Component, Roo.util.Observable, {
16954 * @scope Roo.Component.prototype
16956 * true if this component is hidden. Read-only.
16961 * true if this component is disabled. Read-only.
16966 * true if this component has been rendered. Read-only.
16970 /** @cfg {String} disableClass
16971 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
16973 disabledClass : "x-item-disabled",
16974 /** @cfg {Boolean} allowDomMove
16975 * Whether the component can move the Dom node when rendering (defaults to true).
16977 allowDomMove : true,
16978 /** @cfg {String} hideMode (display|visibility)
16979 * How this component should hidden. Supported values are
16980 * "visibility" (css visibility), "offsets" (negative offset position) and
16981 * "display" (css display) - defaults to "display".
16983 hideMode: 'display',
16986 ctype : "Roo.Component",
16989 * @cfg {String} actionMode
16990 * which property holds the element that used for hide() / show() / disable() / enable()
16991 * default is 'el' for forms you probably want to set this to fieldEl
16996 * @cfg {String} style
16997 * css styles to add to component
16998 * eg. text-align:right;
17003 getActionEl : function(){
17004 return this[this.actionMode];
17007 initComponent : Roo.emptyFn,
17009 * If this is a lazy rendering component, render it to its container element.
17010 * @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.
17012 render : function(container, position){
17018 if(this.fireEvent("beforerender", this) === false){
17022 if(!container && this.el){
17023 this.el = Roo.get(this.el);
17024 container = this.el.dom.parentNode;
17025 this.allowDomMove = false;
17027 this.container = Roo.get(container);
17028 this.rendered = true;
17029 if(position !== undefined){
17030 if(typeof position == 'number'){
17031 position = this.container.dom.childNodes[position];
17033 position = Roo.getDom(position);
17036 this.onRender(this.container, position || null);
17038 this.el.addClass(this.cls);
17042 this.el.applyStyles(this.style);
17045 this.fireEvent("render", this);
17046 this.afterRender(this.container);
17059 // default function is not really useful
17060 onRender : function(ct, position){
17062 this.el = Roo.get(this.el);
17063 if(this.allowDomMove !== false){
17064 ct.dom.insertBefore(this.el.dom, position);
17070 getAutoCreate : function(){
17071 var cfg = typeof this.autoCreate == "object" ?
17072 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
17073 if(this.id && !cfg.id){
17080 afterRender : Roo.emptyFn,
17083 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
17084 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
17086 destroy : function(){
17087 if(this.fireEvent("beforedestroy", this) !== false){
17088 this.purgeListeners();
17089 this.beforeDestroy();
17091 this.el.removeAllListeners();
17093 if(this.actionMode == "container"){
17094 this.container.remove();
17098 Roo.ComponentMgr.unregister(this);
17099 this.fireEvent("destroy", this);
17104 beforeDestroy : function(){
17109 onDestroy : function(){
17114 * Returns the underlying {@link Roo.Element}.
17115 * @return {Roo.Element} The element
17117 getEl : function(){
17122 * Returns the id of this component.
17125 getId : function(){
17130 * Try to focus this component.
17131 * @param {Boolean} selectText True to also select the text in this component (if applicable)
17132 * @return {Roo.Component} this
17134 focus : function(selectText){
17137 if(selectText === true){
17138 this.el.dom.select();
17153 * Disable this component.
17154 * @return {Roo.Component} this
17156 disable : function(){
17160 this.disabled = true;
17161 this.fireEvent("disable", this);
17166 onDisable : function(){
17167 this.getActionEl().addClass(this.disabledClass);
17168 this.el.dom.disabled = true;
17172 * Enable this component.
17173 * @return {Roo.Component} this
17175 enable : function(){
17179 this.disabled = false;
17180 this.fireEvent("enable", this);
17185 onEnable : function(){
17186 this.getActionEl().removeClass(this.disabledClass);
17187 this.el.dom.disabled = false;
17191 * Convenience function for setting disabled/enabled by boolean.
17192 * @param {Boolean} disabled
17194 setDisabled : function(disabled){
17195 this[disabled ? "disable" : "enable"]();
17199 * Show this component.
17200 * @return {Roo.Component} this
17203 if(this.fireEvent("beforeshow", this) !== false){
17204 this.hidden = false;
17208 this.fireEvent("show", this);
17214 onShow : function(){
17215 var ae = this.getActionEl();
17216 if(this.hideMode == 'visibility'){
17217 ae.dom.style.visibility = "visible";
17218 }else if(this.hideMode == 'offsets'){
17219 ae.removeClass('x-hidden');
17221 ae.dom.style.display = "";
17226 * Hide this component.
17227 * @return {Roo.Component} this
17230 if(this.fireEvent("beforehide", this) !== false){
17231 this.hidden = true;
17235 this.fireEvent("hide", this);
17241 onHide : function(){
17242 var ae = this.getActionEl();
17243 if(this.hideMode == 'visibility'){
17244 ae.dom.style.visibility = "hidden";
17245 }else if(this.hideMode == 'offsets'){
17246 ae.addClass('x-hidden');
17248 ae.dom.style.display = "none";
17253 * Convenience function to hide or show this component by boolean.
17254 * @param {Boolean} visible True to show, false to hide
17255 * @return {Roo.Component} this
17257 setVisible: function(visible){
17267 * Returns true if this component is visible.
17269 isVisible : function(){
17270 return this.getActionEl().isVisible();
17273 cloneConfig : function(overrides){
17274 overrides = overrides || {};
17275 var id = overrides.id || Roo.id();
17276 var cfg = Roo.applyIf(overrides, this.initialConfig);
17277 cfg.id = id; // prevent dup id
17278 return new this.constructor(cfg);
17282 * Ext JS Library 1.1.1
17283 * Copyright(c) 2006-2007, Ext JS, LLC.
17285 * Originally Released Under LGPL - original licence link has changed is not relivant.
17288 * <script type="text/javascript">
17292 * @class Roo.BoxComponent
17293 * @extends Roo.Component
17294 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
17295 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
17296 * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
17297 * layout containers.
17299 * @param {Roo.Element/String/Object} config The configuration options.
17301 Roo.BoxComponent = function(config){
17302 Roo.Component.call(this, config);
17306 * Fires after the component is resized.
17307 * @param {Roo.Component} this
17308 * @param {Number} adjWidth The box-adjusted width that was set
17309 * @param {Number} adjHeight The box-adjusted height that was set
17310 * @param {Number} rawWidth The width that was originally specified
17311 * @param {Number} rawHeight The height that was originally specified
17316 * Fires after the component is moved.
17317 * @param {Roo.Component} this
17318 * @param {Number} x The new x position
17319 * @param {Number} y The new y position
17325 Roo.extend(Roo.BoxComponent, Roo.Component, {
17326 // private, set in afterRender to signify that the component has been rendered
17328 // private, used to defer height settings to subclasses
17329 deferHeight: false,
17330 /** @cfg {Number} width
17331 * width (optional) size of component
17333 /** @cfg {Number} height
17334 * height (optional) size of component
17338 * Sets the width and height of the component. This method fires the resize event. This method can accept
17339 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
17340 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
17341 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
17342 * @return {Roo.BoxComponent} this
17344 setSize : function(w, h){
17345 // support for standard size objects
17346 if(typeof w == 'object'){
17351 if(!this.boxReady){
17357 // prevent recalcs when not needed
17358 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
17361 this.lastSize = {width: w, height: h};
17363 var adj = this.adjustSize(w, h);
17364 var aw = adj.width, ah = adj.height;
17365 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
17366 var rz = this.getResizeEl();
17367 if(!this.deferHeight && aw !== undefined && ah !== undefined){
17368 rz.setSize(aw, ah);
17369 }else if(!this.deferHeight && ah !== undefined){
17371 }else if(aw !== undefined){
17374 this.onResize(aw, ah, w, h);
17375 this.fireEvent('resize', this, aw, ah, w, h);
17381 * Gets the current size of the component's underlying element.
17382 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
17384 getSize : function(){
17385 return this.el.getSize();
17389 * Gets the current XY position of the component's underlying element.
17390 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
17391 * @return {Array} The XY position of the element (e.g., [100, 200])
17393 getPosition : function(local){
17394 if(local === true){
17395 return [this.el.getLeft(true), this.el.getTop(true)];
17397 return this.xy || this.el.getXY();
17401 * Gets the current box measurements of the component's underlying element.
17402 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
17403 * @returns {Object} box An object in the format {x, y, width, height}
17405 getBox : function(local){
17406 var s = this.el.getSize();
17408 s.x = this.el.getLeft(true);
17409 s.y = this.el.getTop(true);
17411 var xy = this.xy || this.el.getXY();
17419 * Sets the current box measurements of the component's underlying element.
17420 * @param {Object} box An object in the format {x, y, width, height}
17421 * @returns {Roo.BoxComponent} this
17423 updateBox : function(box){
17424 this.setSize(box.width, box.height);
17425 this.setPagePosition(box.x, box.y);
17430 getResizeEl : function(){
17431 return this.resizeEl || this.el;
17435 getPositionEl : function(){
17436 return this.positionEl || this.el;
17440 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
17441 * This method fires the move event.
17442 * @param {Number} left The new left
17443 * @param {Number} top The new top
17444 * @returns {Roo.BoxComponent} this
17446 setPosition : function(x, y){
17449 if(!this.boxReady){
17452 var adj = this.adjustPosition(x, y);
17453 var ax = adj.x, ay = adj.y;
17455 var el = this.getPositionEl();
17456 if(ax !== undefined || ay !== undefined){
17457 if(ax !== undefined && ay !== undefined){
17458 el.setLeftTop(ax, ay);
17459 }else if(ax !== undefined){
17461 }else if(ay !== undefined){
17464 this.onPosition(ax, ay);
17465 this.fireEvent('move', this, ax, ay);
17471 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
17472 * This method fires the move event.
17473 * @param {Number} x The new x position
17474 * @param {Number} y The new y position
17475 * @returns {Roo.BoxComponent} this
17477 setPagePosition : function(x, y){
17480 if(!this.boxReady){
17483 if(x === undefined || y === undefined){ // cannot translate undefined points
17486 var p = this.el.translatePoints(x, y);
17487 this.setPosition(p.left, p.top);
17492 onRender : function(ct, position){
17493 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
17495 this.resizeEl = Roo.get(this.resizeEl);
17497 if(this.positionEl){
17498 this.positionEl = Roo.get(this.positionEl);
17503 afterRender : function(){
17504 Roo.BoxComponent.superclass.afterRender.call(this);
17505 this.boxReady = true;
17506 this.setSize(this.width, this.height);
17507 if(this.x || this.y){
17508 this.setPosition(this.x, this.y);
17510 if(this.pageX || this.pageY){
17511 this.setPagePosition(this.pageX, this.pageY);
17516 * Force the component's size to recalculate based on the underlying element's current height and width.
17517 * @returns {Roo.BoxComponent} this
17519 syncSize : function(){
17520 delete this.lastSize;
17521 this.setSize(this.el.getWidth(), this.el.getHeight());
17526 * Called after the component is resized, this method is empty by default but can be implemented by any
17527 * subclass that needs to perform custom logic after a resize occurs.
17528 * @param {Number} adjWidth The box-adjusted width that was set
17529 * @param {Number} adjHeight The box-adjusted height that was set
17530 * @param {Number} rawWidth The width that was originally specified
17531 * @param {Number} rawHeight The height that was originally specified
17533 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
17538 * Called after the component is moved, this method is empty by default but can be implemented by any
17539 * subclass that needs to perform custom logic after a move occurs.
17540 * @param {Number} x The new x position
17541 * @param {Number} y The new y position
17543 onPosition : function(x, y){
17548 adjustSize : function(w, h){
17549 if(this.autoWidth){
17552 if(this.autoHeight){
17555 return {width : w, height: h};
17559 adjustPosition : function(x, y){
17560 return {x : x, y: y};
17564 * Ext JS Library 1.1.1
17565 * Copyright(c) 2006-2007, Ext JS, LLC.
17567 * Originally Released Under LGPL - original licence link has changed is not relivant.
17570 * <script type="text/javascript">
17575 * @extends Roo.Element
17576 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
17577 * automatic maintaining of shadow/shim positions.
17578 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
17579 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
17580 * you can pass a string with a CSS class name. False turns off the shadow.
17581 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
17582 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
17583 * @cfg {String} cls CSS class to add to the element
17584 * @cfg {Number} zindex Starting z-index (defaults to 11000)
17585 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
17587 * @param {Object} config An object with config options.
17588 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
17591 Roo.Layer = function(config, existingEl){
17592 config = config || {};
17593 var dh = Roo.DomHelper;
17594 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
17596 this.dom = Roo.getDom(existingEl);
17599 var o = config.dh || {tag: "div", cls: "x-layer"};
17600 this.dom = dh.append(pel, o);
17603 this.addClass(config.cls);
17605 this.constrain = config.constrain !== false;
17606 this.visibilityMode = Roo.Element.VISIBILITY;
17608 this.id = this.dom.id = config.id;
17610 this.id = Roo.id(this.dom);
17612 this.zindex = config.zindex || this.getZIndex();
17613 this.position("absolute", this.zindex);
17615 this.shadowOffset = config.shadowOffset || 4;
17616 this.shadow = new Roo.Shadow({
17617 offset : this.shadowOffset,
17618 mode : config.shadow
17621 this.shadowOffset = 0;
17623 this.useShim = config.shim !== false && Roo.useShims;
17624 this.useDisplay = config.useDisplay;
17628 var supr = Roo.Element.prototype;
17630 // shims are shared among layer to keep from having 100 iframes
17633 Roo.extend(Roo.Layer, Roo.Element, {
17635 getZIndex : function(){
17636 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
17639 getShim : function(){
17646 var shim = shims.shift();
17648 shim = this.createShim();
17649 shim.enableDisplayMode('block');
17650 shim.dom.style.display = 'none';
17651 shim.dom.style.visibility = 'visible';
17653 var pn = this.dom.parentNode;
17654 if(shim.dom.parentNode != pn){
17655 pn.insertBefore(shim.dom, this.dom);
17657 shim.setStyle('z-index', this.getZIndex()-2);
17662 hideShim : function(){
17664 this.shim.setDisplayed(false);
17665 shims.push(this.shim);
17670 disableShadow : function(){
17672 this.shadowDisabled = true;
17673 this.shadow.hide();
17674 this.lastShadowOffset = this.shadowOffset;
17675 this.shadowOffset = 0;
17679 enableShadow : function(show){
17681 this.shadowDisabled = false;
17682 this.shadowOffset = this.lastShadowOffset;
17683 delete this.lastShadowOffset;
17691 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
17692 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
17693 sync : function(doShow){
17694 var sw = this.shadow;
17695 if(!this.updating && this.isVisible() && (sw || this.useShim)){
17696 var sh = this.getShim();
17698 var w = this.getWidth(),
17699 h = this.getHeight();
17701 var l = this.getLeft(true),
17702 t = this.getTop(true);
17704 if(sw && !this.shadowDisabled){
17705 if(doShow && !sw.isVisible()){
17708 sw.realign(l, t, w, h);
17714 // fit the shim behind the shadow, so it is shimmed too
17715 var a = sw.adjusts, s = sh.dom.style;
17716 s.left = (Math.min(l, l+a.l))+"px";
17717 s.top = (Math.min(t, t+a.t))+"px";
17718 s.width = (w+a.w)+"px";
17719 s.height = (h+a.h)+"px";
17726 sh.setLeftTop(l, t);
17733 destroy : function(){
17736 this.shadow.hide();
17738 this.removeAllListeners();
17739 var pn = this.dom.parentNode;
17741 pn.removeChild(this.dom);
17743 Roo.Element.uncache(this.id);
17746 remove : function(){
17751 beginUpdate : function(){
17752 this.updating = true;
17756 endUpdate : function(){
17757 this.updating = false;
17762 hideUnders : function(negOffset){
17764 this.shadow.hide();
17770 constrainXY : function(){
17771 if(this.constrain){
17772 var vw = Roo.lib.Dom.getViewWidth(),
17773 vh = Roo.lib.Dom.getViewHeight();
17774 var s = Roo.get(document).getScroll();
17776 var xy = this.getXY();
17777 var x = xy[0], y = xy[1];
17778 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
17779 // only move it if it needs it
17781 // first validate right/bottom
17782 if((x + w) > vw+s.left){
17783 x = vw - w - this.shadowOffset;
17786 if((y + h) > vh+s.top){
17787 y = vh - h - this.shadowOffset;
17790 // then make sure top/left isn't negative
17801 var ay = this.avoidY;
17802 if(y <= ay && (y+h) >= ay){
17808 supr.setXY.call(this, xy);
17814 isVisible : function(){
17815 return this.visible;
17819 showAction : function(){
17820 this.visible = true; // track visibility to prevent getStyle calls
17821 if(this.useDisplay === true){
17822 this.setDisplayed("");
17823 }else if(this.lastXY){
17824 supr.setXY.call(this, this.lastXY);
17825 }else if(this.lastLT){
17826 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
17831 hideAction : function(){
17832 this.visible = false;
17833 if(this.useDisplay === true){
17834 this.setDisplayed(false);
17836 this.setLeftTop(-10000,-10000);
17840 // overridden Element method
17841 setVisible : function(v, a, d, c, e){
17846 var cb = function(){
17851 }.createDelegate(this);
17852 supr.setVisible.call(this, true, true, d, cb, e);
17855 this.hideUnders(true);
17864 }.createDelegate(this);
17866 supr.setVisible.call(this, v, a, d, cb, e);
17875 storeXY : function(xy){
17876 delete this.lastLT;
17880 storeLeftTop : function(left, top){
17881 delete this.lastXY;
17882 this.lastLT = [left, top];
17886 beforeFx : function(){
17887 this.beforeAction();
17888 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
17892 afterFx : function(){
17893 Roo.Layer.superclass.afterFx.apply(this, arguments);
17894 this.sync(this.isVisible());
17898 beforeAction : function(){
17899 if(!this.updating && this.shadow){
17900 this.shadow.hide();
17904 // overridden Element method
17905 setLeft : function(left){
17906 this.storeLeftTop(left, this.getTop(true));
17907 supr.setLeft.apply(this, arguments);
17911 setTop : function(top){
17912 this.storeLeftTop(this.getLeft(true), top);
17913 supr.setTop.apply(this, arguments);
17917 setLeftTop : function(left, top){
17918 this.storeLeftTop(left, top);
17919 supr.setLeftTop.apply(this, arguments);
17923 setXY : function(xy, a, d, c, e){
17925 this.beforeAction();
17927 var cb = this.createCB(c);
17928 supr.setXY.call(this, xy, a, d, cb, e);
17935 createCB : function(c){
17946 // overridden Element method
17947 setX : function(x, a, d, c, e){
17948 this.setXY([x, this.getY()], a, d, c, e);
17951 // overridden Element method
17952 setY : function(y, a, d, c, e){
17953 this.setXY([this.getX(), y], a, d, c, e);
17956 // overridden Element method
17957 setSize : function(w, h, a, d, c, e){
17958 this.beforeAction();
17959 var cb = this.createCB(c);
17960 supr.setSize.call(this, w, h, a, d, cb, e);
17966 // overridden Element method
17967 setWidth : function(w, a, d, c, e){
17968 this.beforeAction();
17969 var cb = this.createCB(c);
17970 supr.setWidth.call(this, w, a, d, cb, e);
17976 // overridden Element method
17977 setHeight : function(h, a, d, c, e){
17978 this.beforeAction();
17979 var cb = this.createCB(c);
17980 supr.setHeight.call(this, h, a, d, cb, e);
17986 // overridden Element method
17987 setBounds : function(x, y, w, h, a, d, c, e){
17988 this.beforeAction();
17989 var cb = this.createCB(c);
17991 this.storeXY([x, y]);
17992 supr.setXY.call(this, [x, y]);
17993 supr.setSize.call(this, w, h, a, d, cb, e);
17996 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
18002 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
18003 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
18004 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
18005 * @param {Number} zindex The new z-index to set
18006 * @return {this} The Layer
18008 setZIndex : function(zindex){
18009 this.zindex = zindex;
18010 this.setStyle("z-index", zindex + 2);
18012 this.shadow.setZIndex(zindex + 1);
18015 this.shim.setStyle("z-index", zindex);
18020 * Original code for Roojs - LGPL
18021 * <script type="text/javascript">
18025 * @class Roo.XComponent
18026 * A delayed Element creator...
18027 * Or a way to group chunks of interface together.
18028 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
18029 * used in conjunction with XComponent.build() it will create an instance of each element,
18030 * then call addxtype() to build the User interface.
18032 * Mypart.xyx = new Roo.XComponent({
18034 parent : 'Mypart.xyz', // empty == document.element.!!
18038 disabled : function() {}
18040 tree : function() { // return an tree of xtype declared components
18044 xtype : 'NestedLayoutPanel',
18051 * It can be used to build a big heiracy, with parent etc.
18052 * or you can just use this to render a single compoent to a dom element
18053 * MYPART.render(Roo.Element | String(id) | dom_element )
18060 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
18061 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
18063 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
18065 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
18066 * - if mulitple topModules exist, the last one is defined as the top module.
18070 * When the top level or multiple modules are to embedded into a existing HTML page,
18071 * the parent element can container '#id' of the element where the module will be drawn.
18075 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
18076 * it relies more on a include mechanism, where sub modules are included into an outer page.
18077 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
18079 * Bootstrap Roo Included elements
18081 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
18082 * hence confusing the component builder as it thinks there are multiple top level elements.
18084 * String Over-ride & Translations
18086 * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
18087 * and also the 'overlaying of string values - needed when different versions of the same application with different text content
18088 * are needed. @see Roo.XComponent.overlayString
18092 * @extends Roo.util.Observable
18094 * @param cfg {Object} configuration of component
18097 Roo.XComponent = function(cfg) {
18098 Roo.apply(this, cfg);
18102 * Fires when this the componnt is built
18103 * @param {Roo.XComponent} c the component
18108 this.region = this.region || 'center'; // default..
18109 Roo.XComponent.register(this);
18110 this.modules = false;
18111 this.el = false; // where the layout goes..
18115 Roo.extend(Roo.XComponent, Roo.util.Observable, {
18118 * The created element (with Roo.factory())
18119 * @type {Roo.Layout}
18125 * for BC - use el in new code
18126 * @type {Roo.Layout}
18132 * for BC - use el in new code
18133 * @type {Roo.Layout}
18138 * @cfg {Function|boolean} disabled
18139 * If this module is disabled by some rule, return true from the funtion
18144 * @cfg {String} parent
18145 * Name of parent element which it get xtype added to..
18150 * @cfg {String} order
18151 * Used to set the order in which elements are created (usefull for multiple tabs)
18156 * @cfg {String} name
18157 * String to display while loading.
18161 * @cfg {String} region
18162 * Region to render component to (defaults to center)
18167 * @cfg {Array} items
18168 * A single item array - the first element is the root of the tree..
18169 * It's done this way to stay compatible with the Xtype system...
18175 * The method that retuns the tree of parts that make up this compoennt
18182 * render element to dom or tree
18183 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
18186 render : function(el)
18190 var hp = this.parent ? 1 : 0;
18191 Roo.debug && Roo.log(this);
18193 var tree = this._tree ? this._tree() : this.tree();
18196 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
18197 // if parent is a '#.....' string, then let's use that..
18198 var ename = this.parent.substr(1);
18199 this.parent = false;
18200 Roo.debug && Roo.log(ename);
18202 case 'bootstrap-body':
18203 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
18204 // this is the BorderLayout standard?
18205 this.parent = { el : true };
18208 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
18209 // need to insert stuff...
18211 el : new Roo.bootstrap.layout.Border({
18212 el : document.body,
18218 tabPosition: 'top',
18219 //resizeTabs: true,
18220 alwaysShowTabs: true,
18230 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
18231 this.parent = { el : new Roo.bootstrap.Body() };
18232 Roo.debug && Roo.log("setting el to doc body");
18235 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
18239 this.parent = { el : true};
18242 el = Roo.get(ename);
18243 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
18244 this.parent = { el : true};
18251 if (!el && !this.parent) {
18252 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
18257 Roo.debug && Roo.log("EL:");
18258 Roo.debug && Roo.log(el);
18259 Roo.debug && Roo.log("this.parent.el:");
18260 Roo.debug && Roo.log(this.parent.el);
18263 // altertive root elements ??? - we need a better way to indicate these.
18264 var is_alt = Roo.XComponent.is_alt ||
18265 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
18266 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
18267 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
18271 if (!this.parent && is_alt) {
18272 //el = Roo.get(document.body);
18273 this.parent = { el : true };
18278 if (!this.parent) {
18280 Roo.debug && Roo.log("no parent - creating one");
18282 el = el ? Roo.get(el) : false;
18284 if (typeof(Roo.BorderLayout) == 'undefined' ) {
18287 el : new Roo.bootstrap.layout.Border({
18288 el: el || document.body,
18294 tabPosition: 'top',
18295 //resizeTabs: true,
18296 alwaysShowTabs: false,
18299 overflow: 'visible'
18305 // it's a top level one..
18307 el : new Roo.BorderLayout(el || document.body, {
18312 tabPosition: 'top',
18313 //resizeTabs: true,
18314 alwaysShowTabs: el && hp? false : true,
18315 hideTabs: el || !hp ? true : false,
18323 if (!this.parent.el) {
18324 // probably an old style ctor, which has been disabled.
18328 // The 'tree' method is '_tree now'
18330 tree.region = tree.region || this.region;
18331 var is_body = false;
18332 if (this.parent.el === true) {
18333 // bootstrap... - body..
18337 this.parent.el = Roo.factory(tree);
18341 this.el = this.parent.el.addxtype(tree, undefined, is_body);
18342 this.fireEvent('built', this);
18344 this.panel = this.el;
18345 this.layout = this.panel.layout;
18346 this.parentLayout = this.parent.layout || false;
18352 Roo.apply(Roo.XComponent, {
18354 * @property hideProgress
18355 * true to disable the building progress bar.. usefull on single page renders.
18358 hideProgress : false,
18360 * @property buildCompleted
18361 * True when the builder has completed building the interface.
18364 buildCompleted : false,
18367 * @property topModule
18368 * the upper most module - uses document.element as it's constructor.
18375 * @property modules
18376 * array of modules to be created by registration system.
18377 * @type {Array} of Roo.XComponent
18382 * @property elmodules
18383 * array of modules to be created by which use #ID
18384 * @type {Array} of Roo.XComponent
18391 * Is an alternative Root - normally used by bootstrap or other systems,
18392 * where the top element in the tree can wrap 'body'
18393 * @type {boolean} (default false)
18398 * @property build_from_html
18399 * Build elements from html - used by bootstrap HTML stuff
18400 * - this is cleared after build is completed
18401 * @type {boolean} (default false)
18404 build_from_html : false,
18406 * Register components to be built later.
18408 * This solves the following issues
18409 * - Building is not done on page load, but after an authentication process has occured.
18410 * - Interface elements are registered on page load
18411 * - Parent Interface elements may not be loaded before child, so this handles that..
18418 module : 'Pman.Tab.projectMgr',
18420 parent : 'Pman.layout',
18421 disabled : false, // or use a function..
18424 * * @param {Object} details about module
18426 register : function(obj) {
18428 Roo.XComponent.event.fireEvent('register', obj);
18429 switch(typeof(obj.disabled) ) {
18435 if ( obj.disabled() ) {
18441 if (obj.disabled || obj.region == '#disabled') {
18447 this.modules.push(obj);
18451 * convert a string to an object..
18452 * eg. 'AAA.BBB' -> finds AAA.BBB
18456 toObject : function(str)
18458 if (!str || typeof(str) == 'object') {
18461 if (str.substring(0,1) == '#') {
18465 var ar = str.split('.');
18470 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
18472 throw "Module not found : " + str;
18476 throw "Module not found : " + str;
18478 Roo.each(ar, function(e) {
18479 if (typeof(o[e]) == 'undefined') {
18480 throw "Module not found : " + str;
18491 * move modules into their correct place in the tree..
18494 preBuild : function ()
18497 Roo.each(this.modules , function (obj)
18499 Roo.XComponent.event.fireEvent('beforebuild', obj);
18501 var opar = obj.parent;
18503 obj.parent = this.toObject(opar);
18505 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
18510 Roo.debug && Roo.log("GOT top level module");
18511 Roo.debug && Roo.log(obj);
18512 obj.modules = new Roo.util.MixedCollection(false,
18513 function(o) { return o.order + '' }
18515 this.topModule = obj;
18518 // parent is a string (usually a dom element name..)
18519 if (typeof(obj.parent) == 'string') {
18520 this.elmodules.push(obj);
18523 if (obj.parent.constructor != Roo.XComponent) {
18524 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
18526 if (!obj.parent.modules) {
18527 obj.parent.modules = new Roo.util.MixedCollection(false,
18528 function(o) { return o.order + '' }
18531 if (obj.parent.disabled) {
18532 obj.disabled = true;
18534 obj.parent.modules.add(obj);
18539 * make a list of modules to build.
18540 * @return {Array} list of modules.
18543 buildOrder : function()
18546 var cmp = function(a,b) {
18547 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
18549 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
18550 throw "No top level modules to build";
18553 // make a flat list in order of modules to build.
18554 var mods = this.topModule ? [ this.topModule ] : [];
18557 // elmodules (is a list of DOM based modules )
18558 Roo.each(this.elmodules, function(e) {
18560 if (!this.topModule &&
18561 typeof(e.parent) == 'string' &&
18562 e.parent.substring(0,1) == '#' &&
18563 Roo.get(e.parent.substr(1))
18566 _this.topModule = e;
18572 // add modules to their parents..
18573 var addMod = function(m) {
18574 Roo.debug && Roo.log("build Order: add: " + m.name);
18577 if (m.modules && !m.disabled) {
18578 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
18579 m.modules.keySort('ASC', cmp );
18580 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
18582 m.modules.each(addMod);
18584 Roo.debug && Roo.log("build Order: no child modules");
18586 // not sure if this is used any more..
18588 m.finalize.name = m.name + " (clean up) ";
18589 mods.push(m.finalize);
18593 if (this.topModule && this.topModule.modules) {
18594 this.topModule.modules.keySort('ASC', cmp );
18595 this.topModule.modules.each(addMod);
18601 * Build the registered modules.
18602 * @param {Object} parent element.
18603 * @param {Function} optional method to call after module has been added.
18607 build : function(opts)
18610 if (typeof(opts) != 'undefined') {
18611 Roo.apply(this,opts);
18615 var mods = this.buildOrder();
18617 //this.allmods = mods;
18618 //Roo.debug && Roo.log(mods);
18620 if (!mods.length) { // should not happen
18621 throw "NO modules!!!";
18625 var msg = "Building Interface...";
18626 // flash it up as modal - so we store the mask!?
18627 if (!this.hideProgress && Roo.MessageBox) {
18628 Roo.MessageBox.show({ title: 'loading' });
18629 Roo.MessageBox.show({
18630 title: "Please wait...",
18640 var total = mods.length;
18643 var progressRun = function() {
18644 if (!mods.length) {
18645 Roo.debug && Roo.log('hide?');
18646 if (!this.hideProgress && Roo.MessageBox) {
18647 Roo.MessageBox.hide();
18649 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
18651 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
18657 var m = mods.shift();
18660 Roo.debug && Roo.log(m);
18661 // not sure if this is supported any more.. - modules that are are just function
18662 if (typeof(m) == 'function') {
18664 return progressRun.defer(10, _this);
18668 msg = "Building Interface " + (total - mods.length) +
18670 (m.name ? (' - ' + m.name) : '');
18671 Roo.debug && Roo.log(msg);
18672 if (!_this.hideProgress && Roo.MessageBox) {
18673 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
18677 // is the module disabled?
18678 var disabled = (typeof(m.disabled) == 'function') ?
18679 m.disabled.call(m.module.disabled) : m.disabled;
18683 return progressRun(); // we do not update the display!
18691 // it's 10 on top level, and 1 on others??? why...
18692 return progressRun.defer(10, _this);
18695 progressRun.defer(1, _this);
18701 * Overlay a set of modified strings onto a component
18702 * This is dependant on our builder exporting the strings and 'named strings' elements.
18704 * @param {Object} element to overlay on - eg. Pman.Dialog.Login
18705 * @param {Object} associative array of 'named' string and it's new value.
18708 overlayStrings : function( component, strings )
18710 if (typeof(component['_named_strings']) == 'undefined') {
18711 throw "ERROR: component does not have _named_strings";
18713 for ( var k in strings ) {
18714 var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
18715 if (md !== false) {
18716 component['_strings'][md] = strings[k];
18718 Roo.log('could not find named string: ' + k + ' in');
18719 Roo.log(component);
18734 * wrapper for event.on - aliased later..
18735 * Typically use to register a event handler for register:
18737 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
18746 Roo.XComponent.event = new Roo.util.Observable({
18750 * Fires when an Component is registered,
18751 * set the disable property on the Component to stop registration.
18752 * @param {Roo.XComponent} c the component being registerd.
18757 * @event beforebuild
18758 * Fires before each Component is built
18759 * can be used to apply permissions.
18760 * @param {Roo.XComponent} c the component being registerd.
18763 'beforebuild' : true,
18765 * @event buildcomplete
18766 * Fires on the top level element when all elements have been built
18767 * @param {Roo.XComponent} the top level component.
18769 'buildcomplete' : true
18774 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
18777 * marked - a markdown parser
18778 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
18779 * https://github.com/chjj/marked
18785 * Roo.Markdown - is a very crude wrapper around marked..
18789 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
18791 * Note: move the sample code to the bottom of this
18792 * file before uncommenting it.
18797 Roo.Markdown.toHtml = function(text) {
18799 var c = new Roo.Markdown.marked.setOptions({
18800 renderer: new Roo.Markdown.marked.Renderer(),
18811 text = text.replace(/\\\n/g,' ');
18812 return Roo.Markdown.marked(text);
18817 // Wraps all "globals" so that the only thing
18818 // exposed is makeHtml().
18824 * eval:var:unescape
18832 var escape = function (html, encode) {
18834 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
18835 .replace(/</g, '<')
18836 .replace(/>/g, '>')
18837 .replace(/"/g, '"')
18838 .replace(/'/g, ''');
18841 var unescape = function (html) {
18842 // explicitly match decimal, hex, and named HTML entities
18843 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
18844 n = n.toLowerCase();
18845 if (n === 'colon') { return ':'; }
18846 if (n.charAt(0) === '#') {
18847 return n.charAt(1) === 'x'
18848 ? String.fromCharCode(parseInt(n.substring(2), 16))
18849 : String.fromCharCode(+n.substring(1));
18855 var replace = function (regex, opt) {
18856 regex = regex.source;
18858 return function self(name, val) {
18859 if (!name) { return new RegExp(regex, opt); }
18860 val = val.source || val;
18861 val = val.replace(/(^|[^\[])\^/g, '$1');
18862 regex = regex.replace(name, val);
18871 var noop = function () {}
18877 var merge = function (obj) {
18882 for (; i < arguments.length; i++) {
18883 target = arguments[i];
18884 for (key in target) {
18885 if (Object.prototype.hasOwnProperty.call(target, key)) {
18886 obj[key] = target[key];
18896 * Block-Level Grammar
18904 code: /^( {4}[^\n]+\n*)+/,
18906 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
18907 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
18909 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
18910 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
18911 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
18912 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
18913 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
18915 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
18919 block.bullet = /(?:[*+-]|\d+\.)/;
18920 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
18921 block.item = replace(block.item, 'gm')
18922 (/bull/g, block.bullet)
18925 block.list = replace(block.list)
18926 (/bull/g, block.bullet)
18927 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
18928 ('def', '\\n+(?=' + block.def.source + ')')
18931 block.blockquote = replace(block.blockquote)
18935 block._tag = '(?!(?:'
18936 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
18937 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
18938 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
18940 block.html = replace(block.html)
18941 ('comment', /<!--[\s\S]*?-->/)
18942 ('closed', /<(tag)[\s\S]+?<\/\1>/)
18943 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
18944 (/tag/g, block._tag)
18947 block.paragraph = replace(block.paragraph)
18949 ('heading', block.heading)
18950 ('lheading', block.lheading)
18951 ('blockquote', block.blockquote)
18952 ('tag', '<' + block._tag)
18957 * Normal Block Grammar
18960 block.normal = merge({}, block);
18963 * GFM Block Grammar
18966 block.gfm = merge({}, block.normal, {
18967 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
18969 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
18972 block.gfm.paragraph = replace(block.paragraph)
18974 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
18975 + block.list.source.replace('\\1', '\\3') + '|')
18979 * GFM + Tables Block Grammar
18982 block.tables = merge({}, block.gfm, {
18983 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
18984 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
18991 var Lexer = function (options) {
18993 this.tokens.links = {};
18994 this.options = options || marked.defaults;
18995 this.rules = block.normal;
18997 if (this.options.gfm) {
18998 if (this.options.tables) {
18999 this.rules = block.tables;
19001 this.rules = block.gfm;
19007 * Expose Block Rules
19010 Lexer.rules = block;
19013 * Static Lex Method
19016 Lexer.lex = function(src, options) {
19017 var lexer = new Lexer(options);
19018 return lexer.lex(src);
19025 Lexer.prototype.lex = function(src) {
19027 .replace(/\r\n|\r/g, '\n')
19028 .replace(/\t/g, ' ')
19029 .replace(/\u00a0/g, ' ')
19030 .replace(/\u2424/g, '\n');
19032 return this.token(src, true);
19039 Lexer.prototype.token = function(src, top, bq) {
19040 var src = src.replace(/^ +$/gm, '')
19053 if (cap = this.rules.newline.exec(src)) {
19054 src = src.substring(cap[0].length);
19055 if (cap[0].length > 1) {
19063 if (cap = this.rules.code.exec(src)) {
19064 src = src.substring(cap[0].length);
19065 cap = cap[0].replace(/^ {4}/gm, '');
19068 text: !this.options.pedantic
19069 ? cap.replace(/\n+$/, '')
19076 if (cap = this.rules.fences.exec(src)) {
19077 src = src.substring(cap[0].length);
19087 if (cap = this.rules.heading.exec(src)) {
19088 src = src.substring(cap[0].length);
19091 depth: cap[1].length,
19097 // table no leading pipe (gfm)
19098 if (top && (cap = this.rules.nptable.exec(src))) {
19099 src = src.substring(cap[0].length);
19103 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
19104 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
19105 cells: cap[3].replace(/\n$/, '').split('\n')
19108 for (i = 0; i < item.align.length; i++) {
19109 if (/^ *-+: *$/.test(item.align[i])) {
19110 item.align[i] = 'right';
19111 } else if (/^ *:-+: *$/.test(item.align[i])) {
19112 item.align[i] = 'center';
19113 } else if (/^ *:-+ *$/.test(item.align[i])) {
19114 item.align[i] = 'left';
19116 item.align[i] = null;
19120 for (i = 0; i < item.cells.length; i++) {
19121 item.cells[i] = item.cells[i].split(/ *\| */);
19124 this.tokens.push(item);
19130 if (cap = this.rules.lheading.exec(src)) {
19131 src = src.substring(cap[0].length);
19134 depth: cap[2] === '=' ? 1 : 2,
19141 if (cap = this.rules.hr.exec(src)) {
19142 src = src.substring(cap[0].length);
19150 if (cap = this.rules.blockquote.exec(src)) {
19151 src = src.substring(cap[0].length);
19154 type: 'blockquote_start'
19157 cap = cap[0].replace(/^ *> ?/gm, '');
19159 // Pass `top` to keep the current
19160 // "toplevel" state. This is exactly
19161 // how markdown.pl works.
19162 this.token(cap, top, true);
19165 type: 'blockquote_end'
19172 if (cap = this.rules.list.exec(src)) {
19173 src = src.substring(cap[0].length);
19177 type: 'list_start',
19178 ordered: bull.length > 1
19181 // Get each top-level item.
19182 cap = cap[0].match(this.rules.item);
19188 for (; i < l; i++) {
19191 // Remove the list item's bullet
19192 // so it is seen as the next token.
19193 space = item.length;
19194 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
19196 // Outdent whatever the
19197 // list item contains. Hacky.
19198 if (~item.indexOf('\n ')) {
19199 space -= item.length;
19200 item = !this.options.pedantic
19201 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
19202 : item.replace(/^ {1,4}/gm, '');
19205 // Determine whether the next list item belongs here.
19206 // Backpedal if it does not belong in this list.
19207 if (this.options.smartLists && i !== l - 1) {
19208 b = block.bullet.exec(cap[i + 1])[0];
19209 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
19210 src = cap.slice(i + 1).join('\n') + src;
19215 // Determine whether item is loose or not.
19216 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
19217 // for discount behavior.
19218 loose = next || /\n\n(?!\s*$)/.test(item);
19220 next = item.charAt(item.length - 1) === '\n';
19221 if (!loose) { loose = next; }
19226 ? 'loose_item_start'
19227 : 'list_item_start'
19231 this.token(item, false, bq);
19234 type: 'list_item_end'
19246 if (cap = this.rules.html.exec(src)) {
19247 src = src.substring(cap[0].length);
19249 type: this.options.sanitize
19252 pre: !this.options.sanitizer
19253 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
19260 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
19261 src = src.substring(cap[0].length);
19262 this.tokens.links[cap[1].toLowerCase()] = {
19270 if (top && (cap = this.rules.table.exec(src))) {
19271 src = src.substring(cap[0].length);
19275 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
19276 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
19277 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
19280 for (i = 0; i < item.align.length; i++) {
19281 if (/^ *-+: *$/.test(item.align[i])) {
19282 item.align[i] = 'right';
19283 } else if (/^ *:-+: *$/.test(item.align[i])) {
19284 item.align[i] = 'center';
19285 } else if (/^ *:-+ *$/.test(item.align[i])) {
19286 item.align[i] = 'left';
19288 item.align[i] = null;
19292 for (i = 0; i < item.cells.length; i++) {
19293 item.cells[i] = item.cells[i]
19294 .replace(/^ *\| *| *\| *$/g, '')
19298 this.tokens.push(item);
19303 // top-level paragraph
19304 if (top && (cap = this.rules.paragraph.exec(src))) {
19305 src = src.substring(cap[0].length);
19308 text: cap[1].charAt(cap[1].length - 1) === '\n'
19309 ? cap[1].slice(0, -1)
19316 if (cap = this.rules.text.exec(src)) {
19317 // Top-level should never reach here.
19318 src = src.substring(cap[0].length);
19328 Error('Infinite loop on byte: ' + src.charCodeAt(0));
19332 return this.tokens;
19336 * Inline-Level Grammar
19340 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
19341 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
19343 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
19344 link: /^!?\[(inside)\]\(href\)/,
19345 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
19346 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
19347 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
19348 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
19349 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
19350 br: /^ {2,}\n(?!\s*$)/,
19352 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
19355 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
19356 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
19358 inline.link = replace(inline.link)
19359 ('inside', inline._inside)
19360 ('href', inline._href)
19363 inline.reflink = replace(inline.reflink)
19364 ('inside', inline._inside)
19368 * Normal Inline Grammar
19371 inline.normal = merge({}, inline);
19374 * Pedantic Inline Grammar
19377 inline.pedantic = merge({}, inline.normal, {
19378 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
19379 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
19383 * GFM Inline Grammar
19386 inline.gfm = merge({}, inline.normal, {
19387 escape: replace(inline.escape)('])', '~|])')(),
19388 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
19389 del: /^~~(?=\S)([\s\S]*?\S)~~/,
19390 text: replace(inline.text)
19392 ('|', '|https?://|')
19397 * GFM + Line Breaks Inline Grammar
19400 inline.breaks = merge({}, inline.gfm, {
19401 br: replace(inline.br)('{2,}', '*')(),
19402 text: replace(inline.gfm.text)('{2,}', '*')()
19406 * Inline Lexer & Compiler
19409 var InlineLexer = function (links, options) {
19410 this.options = options || marked.defaults;
19411 this.links = links;
19412 this.rules = inline.normal;
19413 this.renderer = this.options.renderer || new Renderer;
19414 this.renderer.options = this.options;
19418 Error('Tokens array requires a `links` property.');
19421 if (this.options.gfm) {
19422 if (this.options.breaks) {
19423 this.rules = inline.breaks;
19425 this.rules = inline.gfm;
19427 } else if (this.options.pedantic) {
19428 this.rules = inline.pedantic;
19433 * Expose Inline Rules
19436 InlineLexer.rules = inline;
19439 * Static Lexing/Compiling Method
19442 InlineLexer.output = function(src, links, options) {
19443 var inline = new InlineLexer(links, options);
19444 return inline.output(src);
19451 InlineLexer.prototype.output = function(src) {
19460 if (cap = this.rules.escape.exec(src)) {
19461 src = src.substring(cap[0].length);
19467 if (cap = this.rules.autolink.exec(src)) {
19468 src = src.substring(cap[0].length);
19469 if (cap[2] === '@') {
19470 text = cap[1].charAt(6) === ':'
19471 ? this.mangle(cap[1].substring(7))
19472 : this.mangle(cap[1]);
19473 href = this.mangle('mailto:') + text;
19475 text = escape(cap[1]);
19478 out += this.renderer.link(href, null, text);
19483 if (!this.inLink && (cap = this.rules.url.exec(src))) {
19484 src = src.substring(cap[0].length);
19485 text = escape(cap[1]);
19487 out += this.renderer.link(href, null, text);
19492 if (cap = this.rules.tag.exec(src)) {
19493 if (!this.inLink && /^<a /i.test(cap[0])) {
19494 this.inLink = true;
19495 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
19496 this.inLink = false;
19498 src = src.substring(cap[0].length);
19499 out += this.options.sanitize
19500 ? this.options.sanitizer
19501 ? this.options.sanitizer(cap[0])
19508 if (cap = this.rules.link.exec(src)) {
19509 src = src.substring(cap[0].length);
19510 this.inLink = true;
19511 out += this.outputLink(cap, {
19515 this.inLink = false;
19520 if ((cap = this.rules.reflink.exec(src))
19521 || (cap = this.rules.nolink.exec(src))) {
19522 src = src.substring(cap[0].length);
19523 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
19524 link = this.links[link.toLowerCase()];
19525 if (!link || !link.href) {
19526 out += cap[0].charAt(0);
19527 src = cap[0].substring(1) + src;
19530 this.inLink = true;
19531 out += this.outputLink(cap, link);
19532 this.inLink = false;
19537 if (cap = this.rules.strong.exec(src)) {
19538 src = src.substring(cap[0].length);
19539 out += this.renderer.strong(this.output(cap[2] || cap[1]));
19544 if (cap = this.rules.em.exec(src)) {
19545 src = src.substring(cap[0].length);
19546 out += this.renderer.em(this.output(cap[2] || cap[1]));
19551 if (cap = this.rules.code.exec(src)) {
19552 src = src.substring(cap[0].length);
19553 out += this.renderer.codespan(escape(cap[2], true));
19558 if (cap = this.rules.br.exec(src)) {
19559 src = src.substring(cap[0].length);
19560 out += this.renderer.br();
19565 if (cap = this.rules.del.exec(src)) {
19566 src = src.substring(cap[0].length);
19567 out += this.renderer.del(this.output(cap[1]));
19572 if (cap = this.rules.text.exec(src)) {
19573 src = src.substring(cap[0].length);
19574 out += this.renderer.text(escape(this.smartypants(cap[0])));
19580 Error('Infinite loop on byte: ' + src.charCodeAt(0));
19591 InlineLexer.prototype.outputLink = function(cap, link) {
19592 var href = escape(link.href)
19593 , title = link.title ? escape(link.title) : null;
19595 return cap[0].charAt(0) !== '!'
19596 ? this.renderer.link(href, title, this.output(cap[1]))
19597 : this.renderer.image(href, title, escape(cap[1]));
19601 * Smartypants Transformations
19604 InlineLexer.prototype.smartypants = function(text) {
19605 if (!this.options.smartypants) { return text; }
19608 .replace(/---/g, '\u2014')
19610 .replace(/--/g, '\u2013')
19612 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
19613 // closing singles & apostrophes
19614 .replace(/'/g, '\u2019')
19616 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
19618 .replace(/"/g, '\u201d')
19620 .replace(/\.{3}/g, '\u2026');
19627 InlineLexer.prototype.mangle = function(text) {
19628 if (!this.options.mangle) { return text; }
19634 for (; i < l; i++) {
19635 ch = text.charCodeAt(i);
19636 if (Math.random() > 0.5) {
19637 ch = 'x' + ch.toString(16);
19639 out += '&#' + ch + ';';
19650 * eval:var:Renderer
19653 var Renderer = function (options) {
19654 this.options = options || {};
19657 Renderer.prototype.code = function(code, lang, escaped) {
19658 if (this.options.highlight) {
19659 var out = this.options.highlight(code, lang);
19660 if (out != null && out !== code) {
19665 // hack!!! - it's already escapeD?
19670 return '<pre><code>'
19671 + (escaped ? code : escape(code, true))
19672 + '\n</code></pre>';
19675 return '<pre><code class="'
19676 + this.options.langPrefix
19677 + escape(lang, true)
19679 + (escaped ? code : escape(code, true))
19680 + '\n</code></pre>\n';
19683 Renderer.prototype.blockquote = function(quote) {
19684 return '<blockquote>\n' + quote + '</blockquote>\n';
19687 Renderer.prototype.html = function(html) {
19691 Renderer.prototype.heading = function(text, level, raw) {
19695 + this.options.headerPrefix
19696 + raw.toLowerCase().replace(/[^\w]+/g, '-')
19704 Renderer.prototype.hr = function() {
19705 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
19708 Renderer.prototype.list = function(body, ordered) {
19709 var type = ordered ? 'ol' : 'ul';
19710 return '<' + type + '>\n' + body + '</' + type + '>\n';
19713 Renderer.prototype.listitem = function(text) {
19714 return '<li>' + text + '</li>\n';
19717 Renderer.prototype.paragraph = function(text) {
19718 return '<p>' + text + '</p>\n';
19721 Renderer.prototype.table = function(header, body) {
19722 return '<table class="table table-striped">\n'
19732 Renderer.prototype.tablerow = function(content) {
19733 return '<tr>\n' + content + '</tr>\n';
19736 Renderer.prototype.tablecell = function(content, flags) {
19737 var type = flags.header ? 'th' : 'td';
19738 var tag = flags.align
19739 ? '<' + type + ' style="text-align:' + flags.align + '">'
19740 : '<' + type + '>';
19741 return tag + content + '</' + type + '>\n';
19744 // span level renderer
19745 Renderer.prototype.strong = function(text) {
19746 return '<strong>' + text + '</strong>';
19749 Renderer.prototype.em = function(text) {
19750 return '<em>' + text + '</em>';
19753 Renderer.prototype.codespan = function(text) {
19754 return '<code>' + text + '</code>';
19757 Renderer.prototype.br = function() {
19758 return this.options.xhtml ? '<br/>' : '<br>';
19761 Renderer.prototype.del = function(text) {
19762 return '<del>' + text + '</del>';
19765 Renderer.prototype.link = function(href, title, text) {
19766 if (this.options.sanitize) {
19768 var prot = decodeURIComponent(unescape(href))
19769 .replace(/[^\w:]/g, '')
19774 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
19778 var out = '<a href="' + href + '"';
19780 out += ' title="' + title + '"';
19782 out += '>' + text + '</a>';
19786 Renderer.prototype.image = function(href, title, text) {
19787 var out = '<img src="' + href + '" alt="' + text + '"';
19789 out += ' title="' + title + '"';
19791 out += this.options.xhtml ? '/>' : '>';
19795 Renderer.prototype.text = function(text) {
19800 * Parsing & Compiling
19806 var Parser= function (options) {
19809 this.options = options || marked.defaults;
19810 this.options.renderer = this.options.renderer || new Renderer;
19811 this.renderer = this.options.renderer;
19812 this.renderer.options = this.options;
19816 * Static Parse Method
19819 Parser.parse = function(src, options, renderer) {
19820 var parser = new Parser(options, renderer);
19821 return parser.parse(src);
19828 Parser.prototype.parse = function(src) {
19829 this.inline = new InlineLexer(src.links, this.options, this.renderer);
19830 this.tokens = src.reverse();
19833 while (this.next()) {
19844 Parser.prototype.next = function() {
19845 return this.token = this.tokens.pop();
19849 * Preview Next Token
19852 Parser.prototype.peek = function() {
19853 return this.tokens[this.tokens.length - 1] || 0;
19857 * Parse Text Tokens
19860 Parser.prototype.parseText = function() {
19861 var body = this.token.text;
19863 while (this.peek().type === 'text') {
19864 body += '\n' + this.next().text;
19867 return this.inline.output(body);
19871 * Parse Current Token
19874 Parser.prototype.tok = function() {
19875 switch (this.token.type) {
19880 return this.renderer.hr();
19883 return this.renderer.heading(
19884 this.inline.output(this.token.text),
19889 return this.renderer.code(this.token.text,
19891 this.token.escaped);
19904 for (i = 0; i < this.token.header.length; i++) {
19905 flags = { header: true, align: this.token.align[i] };
19906 cell += this.renderer.tablecell(
19907 this.inline.output(this.token.header[i]),
19908 { header: true, align: this.token.align[i] }
19911 header += this.renderer.tablerow(cell);
19913 for (i = 0; i < this.token.cells.length; i++) {
19914 row = this.token.cells[i];
19917 for (j = 0; j < row.length; j++) {
19918 cell += this.renderer.tablecell(
19919 this.inline.output(row[j]),
19920 { header: false, align: this.token.align[j] }
19924 body += this.renderer.tablerow(cell);
19926 return this.renderer.table(header, body);
19928 case 'blockquote_start': {
19931 while (this.next().type !== 'blockquote_end') {
19932 body += this.tok();
19935 return this.renderer.blockquote(body);
19937 case 'list_start': {
19939 , ordered = this.token.ordered;
19941 while (this.next().type !== 'list_end') {
19942 body += this.tok();
19945 return this.renderer.list(body, ordered);
19947 case 'list_item_start': {
19950 while (this.next().type !== 'list_item_end') {
19951 body += this.token.type === 'text'
19956 return this.renderer.listitem(body);
19958 case 'loose_item_start': {
19961 while (this.next().type !== 'list_item_end') {
19962 body += this.tok();
19965 return this.renderer.listitem(body);
19968 var html = !this.token.pre && !this.options.pedantic
19969 ? this.inline.output(this.token.text)
19971 return this.renderer.html(html);
19973 case 'paragraph': {
19974 return this.renderer.paragraph(this.inline.output(this.token.text));
19977 return this.renderer.paragraph(this.parseText());
19989 var marked = function (src, opt, callback) {
19990 if (callback || typeof opt === 'function') {
19996 opt = merge({}, marked.defaults, opt || {});
19998 var highlight = opt.highlight
20004 tokens = Lexer.lex(src, opt)
20006 return callback(e);
20009 pending = tokens.length;
20013 var done = function(err) {
20015 opt.highlight = highlight;
20016 return callback(err);
20022 out = Parser.parse(tokens, opt);
20027 opt.highlight = highlight;
20031 : callback(null, out);
20034 if (!highlight || highlight.length < 3) {
20038 delete opt.highlight;
20040 if (!pending) { return done(); }
20042 for (; i < tokens.length; i++) {
20044 if (token.type !== 'code') {
20045 return --pending || done();
20047 return highlight(token.text, token.lang, function(err, code) {
20048 if (err) { return done(err); }
20049 if (code == null || code === token.text) {
20050 return --pending || done();
20053 token.escaped = true;
20054 --pending || done();
20062 if (opt) { opt = merge({}, marked.defaults, opt); }
20063 return Parser.parse(Lexer.lex(src, opt), opt);
20065 e.message += '\nPlease report this to https://github.com/chjj/marked.';
20066 if ((opt || marked.defaults).silent) {
20067 return '<p>An error occured:</p><pre>'
20068 + escape(e.message + '', true)
20080 marked.setOptions = function(opt) {
20081 merge(marked.defaults, opt);
20085 marked.defaults = {
20096 langPrefix: 'lang-',
20097 smartypants: false,
20099 renderer: new Renderer,
20107 marked.Parser = Parser;
20108 marked.parser = Parser.parse;
20110 marked.Renderer = Renderer;
20112 marked.Lexer = Lexer;
20113 marked.lexer = Lexer.lex;
20115 marked.InlineLexer = InlineLexer;
20116 marked.inlineLexer = InlineLexer.output;
20118 marked.parse = marked;
20120 Roo.Markdown.marked = marked;
20124 * Ext JS Library 1.1.1
20125 * Copyright(c) 2006-2007, Ext JS, LLC.
20127 * Originally Released Under LGPL - original licence link has changed is not relivant.
20130 * <script type="text/javascript">
20136 * These classes are derivatives of the similarly named classes in the YUI Library.
20137 * The original license:
20138 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
20139 * Code licensed under the BSD License:
20140 * http://developer.yahoo.net/yui/license.txt
20145 var Event=Roo.EventManager;
20146 var Dom=Roo.lib.Dom;
20149 * @class Roo.dd.DragDrop
20150 * @extends Roo.util.Observable
20151 * Defines the interface and base operation of items that that can be
20152 * dragged or can be drop targets. It was designed to be extended, overriding
20153 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
20154 * Up to three html elements can be associated with a DragDrop instance:
20156 * <li>linked element: the element that is passed into the constructor.
20157 * This is the element which defines the boundaries for interaction with
20158 * other DragDrop objects.</li>
20159 * <li>handle element(s): The drag operation only occurs if the element that
20160 * was clicked matches a handle element. By default this is the linked
20161 * element, but there are times that you will want only a portion of the
20162 * linked element to initiate the drag operation, and the setHandleElId()
20163 * method provides a way to define this.</li>
20164 * <li>drag element: this represents the element that would be moved along
20165 * with the cursor during a drag operation. By default, this is the linked
20166 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
20167 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
20170 * This class should not be instantiated until the onload event to ensure that
20171 * the associated elements are available.
20172 * The following would define a DragDrop obj that would interact with any
20173 * other DragDrop obj in the "group1" group:
20175 * dd = new Roo.dd.DragDrop("div1", "group1");
20177 * Since none of the event handlers have been implemented, nothing would
20178 * actually happen if you were to run the code above. Normally you would
20179 * override this class or one of the default implementations, but you can
20180 * also override the methods you want on an instance of the class...
20182 * dd.onDragDrop = function(e, id) {
20183 * alert("dd was dropped on " + id);
20187 * @param {String} id of the element that is linked to this instance
20188 * @param {String} sGroup the group of related DragDrop objects
20189 * @param {object} config an object containing configurable attributes
20190 * Valid properties for DragDrop:
20191 * padding, isTarget, maintainOffset, primaryButtonOnly
20193 Roo.dd.DragDrop = function(id, sGroup, config) {
20195 this.init(id, sGroup, config);
20200 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
20203 * The id of the element associated with this object. This is what we
20204 * refer to as the "linked element" because the size and position of
20205 * this element is used to determine when the drag and drop objects have
20213 * Configuration attributes passed into the constructor
20220 * The id of the element that will be dragged. By default this is same
20221 * as the linked element , but could be changed to another element. Ex:
20223 * @property dragElId
20230 * the id of the element that initiates the drag operation. By default
20231 * this is the linked element, but could be changed to be a child of this
20232 * element. This lets us do things like only starting the drag when the
20233 * header element within the linked html element is clicked.
20234 * @property handleElId
20241 * An associative array of HTML tags that will be ignored if clicked.
20242 * @property invalidHandleTypes
20243 * @type {string: string}
20245 invalidHandleTypes: null,
20248 * An associative array of ids for elements that will be ignored if clicked
20249 * @property invalidHandleIds
20250 * @type {string: string}
20252 invalidHandleIds: null,
20255 * An indexted array of css class names for elements that will be ignored
20257 * @property invalidHandleClasses
20260 invalidHandleClasses: null,
20263 * The linked element's absolute X position at the time the drag was
20265 * @property startPageX
20272 * The linked element's absolute X position at the time the drag was
20274 * @property startPageY
20281 * The group defines a logical collection of DragDrop objects that are
20282 * related. Instances only get events when interacting with other
20283 * DragDrop object in the same group. This lets us define multiple
20284 * groups using a single DragDrop subclass if we want.
20286 * @type {string: string}
20291 * Individual drag/drop instances can be locked. This will prevent
20292 * onmousedown start drag.
20300 * Lock this instance
20303 lock: function() { this.locked = true; },
20306 * Unlock this instace
20309 unlock: function() { this.locked = false; },
20312 * By default, all insances can be a drop target. This can be disabled by
20313 * setting isTarget to false.
20320 * The padding configured for this drag and drop object for calculating
20321 * the drop zone intersection with this object.
20328 * Cached reference to the linked element
20329 * @property _domRef
20335 * Internal typeof flag
20336 * @property __ygDragDrop
20339 __ygDragDrop: true,
20342 * Set to true when horizontal contraints are applied
20343 * @property constrainX
20350 * Set to true when vertical contraints are applied
20351 * @property constrainY
20358 * The left constraint
20366 * The right constraint
20374 * The up constraint
20383 * The down constraint
20391 * Maintain offsets when we resetconstraints. Set to true when you want
20392 * the position of the element relative to its parent to stay the same
20393 * when the page changes
20395 * @property maintainOffset
20398 maintainOffset: false,
20401 * Array of pixel locations the element will snap to if we specified a
20402 * horizontal graduation/interval. This array is generated automatically
20403 * when you define a tick interval.
20410 * Array of pixel locations the element will snap to if we specified a
20411 * vertical graduation/interval. This array is generated automatically
20412 * when you define a tick interval.
20419 * By default the drag and drop instance will only respond to the primary
20420 * button click (left button for a right-handed mouse). Set to true to
20421 * allow drag and drop to start with any mouse click that is propogated
20423 * @property primaryButtonOnly
20426 primaryButtonOnly: true,
20429 * The availabe property is false until the linked dom element is accessible.
20430 * @property available
20436 * By default, drags can only be initiated if the mousedown occurs in the
20437 * region the linked element is. This is done in part to work around a
20438 * bug in some browsers that mis-report the mousedown if the previous
20439 * mouseup happened outside of the window. This property is set to true
20440 * if outer handles are defined.
20442 * @property hasOuterHandles
20446 hasOuterHandles: false,
20449 * Code that executes immediately before the startDrag event
20450 * @method b4StartDrag
20453 b4StartDrag: function(x, y) { },
20456 * Abstract method called after a drag/drop object is clicked
20457 * and the drag or mousedown time thresholds have beeen met.
20458 * @method startDrag
20459 * @param {int} X click location
20460 * @param {int} Y click location
20462 startDrag: function(x, y) { /* override this */ },
20465 * Code that executes immediately before the onDrag event
20469 b4Drag: function(e) { },
20472 * Abstract method called during the onMouseMove event while dragging an
20475 * @param {Event} e the mousemove event
20477 onDrag: function(e) { /* override this */ },
20480 * Abstract method called when this element fist begins hovering over
20481 * another DragDrop obj
20482 * @method onDragEnter
20483 * @param {Event} e the mousemove event
20484 * @param {String|DragDrop[]} id In POINT mode, the element
20485 * id this is hovering over. In INTERSECT mode, an array of one or more
20486 * dragdrop items being hovered over.
20488 onDragEnter: function(e, id) { /* override this */ },
20491 * Code that executes immediately before the onDragOver event
20492 * @method b4DragOver
20495 b4DragOver: function(e) { },
20498 * Abstract method called when this element is hovering over another
20500 * @method onDragOver
20501 * @param {Event} e the mousemove event
20502 * @param {String|DragDrop[]} id In POINT mode, the element
20503 * id this is hovering over. In INTERSECT mode, an array of dd items
20504 * being hovered over.
20506 onDragOver: function(e, id) { /* override this */ },
20509 * Code that executes immediately before the onDragOut event
20510 * @method b4DragOut
20513 b4DragOut: function(e) { },
20516 * Abstract method called when we are no longer hovering over an element
20517 * @method onDragOut
20518 * @param {Event} e the mousemove event
20519 * @param {String|DragDrop[]} id In POINT mode, the element
20520 * id this was hovering over. In INTERSECT mode, an array of dd items
20521 * that the mouse is no longer over.
20523 onDragOut: function(e, id) { /* override this */ },
20526 * Code that executes immediately before the onDragDrop event
20527 * @method b4DragDrop
20530 b4DragDrop: function(e) { },
20533 * Abstract method called when this item is dropped on another DragDrop
20535 * @method onDragDrop
20536 * @param {Event} e the mouseup event
20537 * @param {String|DragDrop[]} id In POINT mode, the element
20538 * id this was dropped on. In INTERSECT mode, an array of dd items this
20541 onDragDrop: function(e, id) { /* override this */ },
20544 * Abstract method called when this item is dropped on an area with no
20546 * @method onInvalidDrop
20547 * @param {Event} e the mouseup event
20549 onInvalidDrop: function(e) { /* override this */ },
20552 * Code that executes immediately before the endDrag event
20553 * @method b4EndDrag
20556 b4EndDrag: function(e) { },
20559 * Fired when we are done dragging the object
20561 * @param {Event} e the mouseup event
20563 endDrag: function(e) { /* override this */ },
20566 * Code executed immediately before the onMouseDown event
20567 * @method b4MouseDown
20568 * @param {Event} e the mousedown event
20571 b4MouseDown: function(e) { },
20574 * Event handler that fires when a drag/drop obj gets a mousedown
20575 * @method onMouseDown
20576 * @param {Event} e the mousedown event
20578 onMouseDown: function(e) { /* override this */ },
20581 * Event handler that fires when a drag/drop obj gets a mouseup
20582 * @method onMouseUp
20583 * @param {Event} e the mouseup event
20585 onMouseUp: function(e) { /* override this */ },
20588 * Override the onAvailable method to do what is needed after the initial
20589 * position was determined.
20590 * @method onAvailable
20592 onAvailable: function () {
20596 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
20599 defaultPadding : {left:0, right:0, top:0, bottom:0},
20602 * Initializes the drag drop object's constraints to restrict movement to a certain element.
20606 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
20607 { dragElId: "existingProxyDiv" });
20608 dd.startDrag = function(){
20609 this.constrainTo("parent-id");
20612 * Or you can initalize it using the {@link Roo.Element} object:
20614 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
20615 startDrag : function(){
20616 this.constrainTo("parent-id");
20620 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
20621 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
20622 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
20623 * an object containing the sides to pad. For example: {right:10, bottom:10}
20624 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
20626 constrainTo : function(constrainTo, pad, inContent){
20627 if(typeof pad == "number"){
20628 pad = {left: pad, right:pad, top:pad, bottom:pad};
20630 pad = pad || this.defaultPadding;
20631 var b = Roo.get(this.getEl()).getBox();
20632 var ce = Roo.get(constrainTo);
20633 var s = ce.getScroll();
20634 var c, cd = ce.dom;
20635 if(cd == document.body){
20636 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
20639 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
20643 var topSpace = b.y - c.y;
20644 var leftSpace = b.x - c.x;
20646 this.resetConstraints();
20647 this.setXConstraint(leftSpace - (pad.left||0), // left
20648 c.width - leftSpace - b.width - (pad.right||0) //right
20650 this.setYConstraint(topSpace - (pad.top||0), //top
20651 c.height - topSpace - b.height - (pad.bottom||0) //bottom
20656 * Returns a reference to the linked element
20658 * @return {HTMLElement} the html element
20660 getEl: function() {
20661 if (!this._domRef) {
20662 this._domRef = Roo.getDom(this.id);
20665 return this._domRef;
20669 * Returns a reference to the actual element to drag. By default this is
20670 * the same as the html element, but it can be assigned to another
20671 * element. An example of this can be found in Roo.dd.DDProxy
20672 * @method getDragEl
20673 * @return {HTMLElement} the html element
20675 getDragEl: function() {
20676 return Roo.getDom(this.dragElId);
20680 * Sets up the DragDrop object. Must be called in the constructor of any
20681 * Roo.dd.DragDrop subclass
20683 * @param id the id of the linked element
20684 * @param {String} sGroup the group of related items
20685 * @param {object} config configuration attributes
20687 init: function(id, sGroup, config) {
20688 this.initTarget(id, sGroup, config);
20689 if (!Roo.isTouch) {
20690 Event.on(this.id, "mousedown", this.handleMouseDown, this);
20692 Event.on(this.id, "touchstart", this.handleMouseDown, this);
20693 // Event.on(this.id, "selectstart", Event.preventDefault);
20697 * Initializes Targeting functionality only... the object does not
20698 * get a mousedown handler.
20699 * @method initTarget
20700 * @param id the id of the linked element
20701 * @param {String} sGroup the group of related items
20702 * @param {object} config configuration attributes
20704 initTarget: function(id, sGroup, config) {
20706 // configuration attributes
20707 this.config = config || {};
20709 // create a local reference to the drag and drop manager
20710 this.DDM = Roo.dd.DDM;
20711 // initialize the groups array
20714 // assume that we have an element reference instead of an id if the
20715 // parameter is not a string
20716 if (typeof id !== "string") {
20723 // add to an interaction group
20724 this.addToGroup((sGroup) ? sGroup : "default");
20726 // We don't want to register this as the handle with the manager
20727 // so we just set the id rather than calling the setter.
20728 this.handleElId = id;
20730 // the linked element is the element that gets dragged by default
20731 this.setDragElId(id);
20733 // by default, clicked anchors will not start drag operations.
20734 this.invalidHandleTypes = { A: "A" };
20735 this.invalidHandleIds = {};
20736 this.invalidHandleClasses = [];
20738 this.applyConfig();
20740 this.handleOnAvailable();
20744 * Applies the configuration parameters that were passed into the constructor.
20745 * This is supposed to happen at each level through the inheritance chain. So
20746 * a DDProxy implentation will execute apply config on DDProxy, DD, and
20747 * DragDrop in order to get all of the parameters that are available in
20749 * @method applyConfig
20751 applyConfig: function() {
20753 // configurable properties:
20754 // padding, isTarget, maintainOffset, primaryButtonOnly
20755 this.padding = this.config.padding || [0, 0, 0, 0];
20756 this.isTarget = (this.config.isTarget !== false);
20757 this.maintainOffset = (this.config.maintainOffset);
20758 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
20763 * Executed when the linked element is available
20764 * @method handleOnAvailable
20767 handleOnAvailable: function() {
20768 this.available = true;
20769 this.resetConstraints();
20770 this.onAvailable();
20774 * Configures the padding for the target zone in px. Effectively expands
20775 * (or reduces) the virtual object size for targeting calculations.
20776 * Supports css-style shorthand; if only one parameter is passed, all sides
20777 * will have that padding, and if only two are passed, the top and bottom
20778 * will have the first param, the left and right the second.
20779 * @method setPadding
20780 * @param {int} iTop Top pad
20781 * @param {int} iRight Right pad
20782 * @param {int} iBot Bot pad
20783 * @param {int} iLeft Left pad
20785 setPadding: function(iTop, iRight, iBot, iLeft) {
20786 // this.padding = [iLeft, iRight, iTop, iBot];
20787 if (!iRight && 0 !== iRight) {
20788 this.padding = [iTop, iTop, iTop, iTop];
20789 } else if (!iBot && 0 !== iBot) {
20790 this.padding = [iTop, iRight, iTop, iRight];
20792 this.padding = [iTop, iRight, iBot, iLeft];
20797 * Stores the initial placement of the linked element.
20798 * @method setInitialPosition
20799 * @param {int} diffX the X offset, default 0
20800 * @param {int} diffY the Y offset, default 0
20802 setInitPosition: function(diffX, diffY) {
20803 var el = this.getEl();
20805 if (!this.DDM.verifyEl(el)) {
20809 var dx = diffX || 0;
20810 var dy = diffY || 0;
20812 var p = Dom.getXY( el );
20814 this.initPageX = p[0] - dx;
20815 this.initPageY = p[1] - dy;
20817 this.lastPageX = p[0];
20818 this.lastPageY = p[1];
20821 this.setStartPosition(p);
20825 * Sets the start position of the element. This is set when the obj
20826 * is initialized, the reset when a drag is started.
20827 * @method setStartPosition
20828 * @param pos current position (from previous lookup)
20831 setStartPosition: function(pos) {
20832 var p = pos || Dom.getXY( this.getEl() );
20833 this.deltaSetXY = null;
20835 this.startPageX = p[0];
20836 this.startPageY = p[1];
20840 * Add this instance to a group of related drag/drop objects. All
20841 * instances belong to at least one group, and can belong to as many
20842 * groups as needed.
20843 * @method addToGroup
20844 * @param sGroup {string} the name of the group
20846 addToGroup: function(sGroup) {
20847 this.groups[sGroup] = true;
20848 this.DDM.regDragDrop(this, sGroup);
20852 * Remove's this instance from the supplied interaction group
20853 * @method removeFromGroup
20854 * @param {string} sGroup The group to drop
20856 removeFromGroup: function(sGroup) {
20857 if (this.groups[sGroup]) {
20858 delete this.groups[sGroup];
20861 this.DDM.removeDDFromGroup(this, sGroup);
20865 * Allows you to specify that an element other than the linked element
20866 * will be moved with the cursor during a drag
20867 * @method setDragElId
20868 * @param id {string} the id of the element that will be used to initiate the drag
20870 setDragElId: function(id) {
20871 this.dragElId = id;
20875 * Allows you to specify a child of the linked element that should be
20876 * used to initiate the drag operation. An example of this would be if
20877 * you have a content div with text and links. Clicking anywhere in the
20878 * content area would normally start the drag operation. Use this method
20879 * to specify that an element inside of the content div is the element
20880 * that starts the drag operation.
20881 * @method setHandleElId
20882 * @param id {string} the id of the element that will be used to
20883 * initiate the drag.
20885 setHandleElId: function(id) {
20886 if (typeof id !== "string") {
20889 this.handleElId = id;
20890 this.DDM.regHandle(this.id, id);
20894 * Allows you to set an element outside of the linked element as a drag
20896 * @method setOuterHandleElId
20897 * @param id the id of the element that will be used to initiate the drag
20899 setOuterHandleElId: function(id) {
20900 if (typeof id !== "string") {
20903 Event.on(id, "mousedown",
20904 this.handleMouseDown, this);
20905 this.setHandleElId(id);
20907 this.hasOuterHandles = true;
20911 * Remove all drag and drop hooks for this element
20914 unreg: function() {
20915 Event.un(this.id, "mousedown",
20916 this.handleMouseDown);
20917 Event.un(this.id, "touchstart",
20918 this.handleMouseDown);
20919 this._domRef = null;
20920 this.DDM._remove(this);
20923 destroy : function(){
20928 * Returns true if this instance is locked, or the drag drop mgr is locked
20929 * (meaning that all drag/drop is disabled on the page.)
20931 * @return {boolean} true if this obj or all drag/drop is locked, else
20934 isLocked: function() {
20935 return (this.DDM.isLocked() || this.locked);
20939 * Fired when this object is clicked
20940 * @method handleMouseDown
20942 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
20945 handleMouseDown: function(e, oDD){
20947 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
20948 //Roo.log('not touch/ button !=0');
20951 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
20952 return; // double touch..
20956 if (this.isLocked()) {
20957 //Roo.log('locked');
20961 this.DDM.refreshCache(this.groups);
20962 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
20963 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
20964 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
20965 //Roo.log('no outer handes or not over target');
20968 // Roo.log('check validator');
20969 if (this.clickValidator(e)) {
20970 // Roo.log('validate success');
20971 // set the initial element position
20972 this.setStartPosition();
20975 this.b4MouseDown(e);
20976 this.onMouseDown(e);
20978 this.DDM.handleMouseDown(e, this);
20980 this.DDM.stopEvent(e);
20988 clickValidator: function(e) {
20989 var target = e.getTarget();
20990 return ( this.isValidHandleChild(target) &&
20991 (this.id == this.handleElId ||
20992 this.DDM.handleWasClicked(target, this.id)) );
20996 * Allows you to specify a tag name that should not start a drag operation
20997 * when clicked. This is designed to facilitate embedding links within a
20998 * drag handle that do something other than start the drag.
20999 * @method addInvalidHandleType
21000 * @param {string} tagName the type of element to exclude
21002 addInvalidHandleType: function(tagName) {
21003 var type = tagName.toUpperCase();
21004 this.invalidHandleTypes[type] = type;
21008 * Lets you to specify an element id for a child of a drag handle
21009 * that should not initiate a drag
21010 * @method addInvalidHandleId
21011 * @param {string} id the element id of the element you wish to ignore
21013 addInvalidHandleId: function(id) {
21014 if (typeof id !== "string") {
21017 this.invalidHandleIds[id] = id;
21021 * Lets you specify a css class of elements that will not initiate a drag
21022 * @method addInvalidHandleClass
21023 * @param {string} cssClass the class of the elements you wish to ignore
21025 addInvalidHandleClass: function(cssClass) {
21026 this.invalidHandleClasses.push(cssClass);
21030 * Unsets an excluded tag name set by addInvalidHandleType
21031 * @method removeInvalidHandleType
21032 * @param {string} tagName the type of element to unexclude
21034 removeInvalidHandleType: function(tagName) {
21035 var type = tagName.toUpperCase();
21036 // this.invalidHandleTypes[type] = null;
21037 delete this.invalidHandleTypes[type];
21041 * Unsets an invalid handle id
21042 * @method removeInvalidHandleId
21043 * @param {string} id the id of the element to re-enable
21045 removeInvalidHandleId: function(id) {
21046 if (typeof id !== "string") {
21049 delete this.invalidHandleIds[id];
21053 * Unsets an invalid css class
21054 * @method removeInvalidHandleClass
21055 * @param {string} cssClass the class of the element(s) you wish to
21058 removeInvalidHandleClass: function(cssClass) {
21059 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
21060 if (this.invalidHandleClasses[i] == cssClass) {
21061 delete this.invalidHandleClasses[i];
21067 * Checks the tag exclusion list to see if this click should be ignored
21068 * @method isValidHandleChild
21069 * @param {HTMLElement} node the HTMLElement to evaluate
21070 * @return {boolean} true if this is a valid tag type, false if not
21072 isValidHandleChild: function(node) {
21075 // var n = (node.nodeName == "#text") ? node.parentNode : node;
21078 nodeName = node.nodeName.toUpperCase();
21080 nodeName = node.nodeName;
21082 valid = valid && !this.invalidHandleTypes[nodeName];
21083 valid = valid && !this.invalidHandleIds[node.id];
21085 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
21086 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
21095 * Create the array of horizontal tick marks if an interval was specified
21096 * in setXConstraint().
21097 * @method setXTicks
21100 setXTicks: function(iStartX, iTickSize) {
21102 this.xTickSize = iTickSize;
21106 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
21108 this.xTicks[this.xTicks.length] = i;
21113 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
21115 this.xTicks[this.xTicks.length] = i;
21120 this.xTicks.sort(this.DDM.numericSort) ;
21124 * Create the array of vertical tick marks if an interval was specified in
21125 * setYConstraint().
21126 * @method setYTicks
21129 setYTicks: function(iStartY, iTickSize) {
21131 this.yTickSize = iTickSize;
21135 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
21137 this.yTicks[this.yTicks.length] = i;
21142 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
21144 this.yTicks[this.yTicks.length] = i;
21149 this.yTicks.sort(this.DDM.numericSort) ;
21153 * By default, the element can be dragged any place on the screen. Use
21154 * this method to limit the horizontal travel of the element. Pass in
21155 * 0,0 for the parameters if you want to lock the drag to the y axis.
21156 * @method setXConstraint
21157 * @param {int} iLeft the number of pixels the element can move to the left
21158 * @param {int} iRight the number of pixels the element can move to the
21160 * @param {int} iTickSize optional parameter for specifying that the
21162 * should move iTickSize pixels at a time.
21164 setXConstraint: function(iLeft, iRight, iTickSize) {
21165 this.leftConstraint = iLeft;
21166 this.rightConstraint = iRight;
21168 this.minX = this.initPageX - iLeft;
21169 this.maxX = this.initPageX + iRight;
21170 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
21172 this.constrainX = true;
21176 * Clears any constraints applied to this instance. Also clears ticks
21177 * since they can't exist independent of a constraint at this time.
21178 * @method clearConstraints
21180 clearConstraints: function() {
21181 this.constrainX = false;
21182 this.constrainY = false;
21187 * Clears any tick interval defined for this instance
21188 * @method clearTicks
21190 clearTicks: function() {
21191 this.xTicks = null;
21192 this.yTicks = null;
21193 this.xTickSize = 0;
21194 this.yTickSize = 0;
21198 * By default, the element can be dragged any place on the screen. Set
21199 * this to limit the vertical travel of the element. Pass in 0,0 for the
21200 * parameters if you want to lock the drag to the x axis.
21201 * @method setYConstraint
21202 * @param {int} iUp the number of pixels the element can move up
21203 * @param {int} iDown the number of pixels the element can move down
21204 * @param {int} iTickSize optional parameter for specifying that the
21205 * element should move iTickSize pixels at a time.
21207 setYConstraint: function(iUp, iDown, iTickSize) {
21208 this.topConstraint = iUp;
21209 this.bottomConstraint = iDown;
21211 this.minY = this.initPageY - iUp;
21212 this.maxY = this.initPageY + iDown;
21213 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
21215 this.constrainY = true;
21220 * resetConstraints must be called if you manually reposition a dd element.
21221 * @method resetConstraints
21222 * @param {boolean} maintainOffset
21224 resetConstraints: function() {
21227 // Maintain offsets if necessary
21228 if (this.initPageX || this.initPageX === 0) {
21229 // figure out how much this thing has moved
21230 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
21231 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
21233 this.setInitPosition(dx, dy);
21235 // This is the first time we have detected the element's position
21237 this.setInitPosition();
21240 if (this.constrainX) {
21241 this.setXConstraint( this.leftConstraint,
21242 this.rightConstraint,
21246 if (this.constrainY) {
21247 this.setYConstraint( this.topConstraint,
21248 this.bottomConstraint,
21254 * Normally the drag element is moved pixel by pixel, but we can specify
21255 * that it move a number of pixels at a time. This method resolves the
21256 * location when we have it set up like this.
21258 * @param {int} val where we want to place the object
21259 * @param {int[]} tickArray sorted array of valid points
21260 * @return {int} the closest tick
21263 getTick: function(val, tickArray) {
21266 // If tick interval is not defined, it is effectively 1 pixel,
21267 // so we return the value passed to us.
21269 } else if (tickArray[0] >= val) {
21270 // The value is lower than the first tick, so we return the first
21272 return tickArray[0];
21274 for (var i=0, len=tickArray.length; i<len; ++i) {
21276 if (tickArray[next] && tickArray[next] >= val) {
21277 var diff1 = val - tickArray[i];
21278 var diff2 = tickArray[next] - val;
21279 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
21283 // The value is larger than the last tick, so we return the last
21285 return tickArray[tickArray.length - 1];
21292 * @return {string} string representation of the dd obj
21294 toString: function() {
21295 return ("DragDrop " + this.id);
21303 * Ext JS Library 1.1.1
21304 * Copyright(c) 2006-2007, Ext JS, LLC.
21306 * Originally Released Under LGPL - original licence link has changed is not relivant.
21309 * <script type="text/javascript">
21314 * The drag and drop utility provides a framework for building drag and drop
21315 * applications. In addition to enabling drag and drop for specific elements,
21316 * the drag and drop elements are tracked by the manager class, and the
21317 * interactions between the various elements are tracked during the drag and
21318 * the implementing code is notified about these important moments.
21321 // Only load the library once. Rewriting the manager class would orphan
21322 // existing drag and drop instances.
21323 if (!Roo.dd.DragDropMgr) {
21326 * @class Roo.dd.DragDropMgr
21327 * DragDropMgr is a singleton that tracks the element interaction for
21328 * all DragDrop items in the window. Generally, you will not call
21329 * this class directly, but it does have helper methods that could
21330 * be useful in your DragDrop implementations.
21333 Roo.dd.DragDropMgr = function() {
21335 var Event = Roo.EventManager;
21340 * Two dimensional Array of registered DragDrop objects. The first
21341 * dimension is the DragDrop item group, the second the DragDrop
21344 * @type {string: string}
21351 * Array of element ids defined as drag handles. Used to determine
21352 * if the element that generated the mousedown event is actually the
21353 * handle and not the html element itself.
21354 * @property handleIds
21355 * @type {string: string}
21362 * the DragDrop object that is currently being dragged
21363 * @property dragCurrent
21371 * the DragDrop object(s) that are being hovered over
21372 * @property dragOvers
21380 * the X distance between the cursor and the object being dragged
21389 * the Y distance between the cursor and the object being dragged
21398 * Flag to determine if we should prevent the default behavior of the
21399 * events we define. By default this is true, but this can be set to
21400 * false if you need the default behavior (not recommended)
21401 * @property preventDefault
21405 preventDefault: true,
21408 * Flag to determine if we should stop the propagation of the events
21409 * we generate. This is true by default but you may want to set it to
21410 * false if the html element contains other features that require the
21412 * @property stopPropagation
21416 stopPropagation: true,
21419 * Internal flag that is set to true when drag and drop has been
21421 * @property initialized
21428 * All drag and drop can be disabled.
21436 * Called the first time an element is registered.
21442 this.initialized = true;
21446 * In point mode, drag and drop interaction is defined by the
21447 * location of the cursor during the drag/drop
21455 * In intersect mode, drag and drop interactio nis defined by the
21456 * overlap of two or more drag and drop objects.
21457 * @property INTERSECT
21464 * The current drag and drop mode. Default: POINT
21472 * Runs method on all drag and drop objects
21473 * @method _execOnAll
21477 _execOnAll: function(sMethod, args) {
21478 for (var i in this.ids) {
21479 for (var j in this.ids[i]) {
21480 var oDD = this.ids[i][j];
21481 if (! this.isTypeOfDD(oDD)) {
21484 oDD[sMethod].apply(oDD, args);
21490 * Drag and drop initialization. Sets up the global event handlers
21495 _onLoad: function() {
21499 if (!Roo.isTouch) {
21500 Event.on(document, "mouseup", this.handleMouseUp, this, true);
21501 Event.on(document, "mousemove", this.handleMouseMove, this, true);
21503 Event.on(document, "touchend", this.handleMouseUp, this, true);
21504 Event.on(document, "touchmove", this.handleMouseMove, this, true);
21506 Event.on(window, "unload", this._onUnload, this, true);
21507 Event.on(window, "resize", this._onResize, this, true);
21508 // Event.on(window, "mouseout", this._test);
21513 * Reset constraints on all drag and drop objs
21514 * @method _onResize
21518 _onResize: function(e) {
21519 this._execOnAll("resetConstraints", []);
21523 * Lock all drag and drop functionality
21527 lock: function() { this.locked = true; },
21530 * Unlock all drag and drop functionality
21534 unlock: function() { this.locked = false; },
21537 * Is drag and drop locked?
21539 * @return {boolean} True if drag and drop is locked, false otherwise.
21542 isLocked: function() { return this.locked; },
21545 * Location cache that is set for all drag drop objects when a drag is
21546 * initiated, cleared when the drag is finished.
21547 * @property locationCache
21554 * Set useCache to false if you want to force object the lookup of each
21555 * drag and drop linked element constantly during a drag.
21556 * @property useCache
21563 * The number of pixels that the mouse needs to move after the
21564 * mousedown before the drag is initiated. Default=3;
21565 * @property clickPixelThresh
21569 clickPixelThresh: 3,
21572 * The number of milliseconds after the mousedown event to initiate the
21573 * drag if we don't get a mouseup event. Default=1000
21574 * @property clickTimeThresh
21578 clickTimeThresh: 350,
21581 * Flag that indicates that either the drag pixel threshold or the
21582 * mousdown time threshold has been met
21583 * @property dragThreshMet
21588 dragThreshMet: false,
21591 * Timeout used for the click time threshold
21592 * @property clickTimeout
21597 clickTimeout: null,
21600 * The X position of the mousedown event stored for later use when a
21601 * drag threshold is met.
21610 * The Y position of the mousedown event stored for later use when a
21611 * drag threshold is met.
21620 * Each DragDrop instance must be registered with the DragDropMgr.
21621 * This is executed in DragDrop.init()
21622 * @method regDragDrop
21623 * @param {DragDrop} oDD the DragDrop object to register
21624 * @param {String} sGroup the name of the group this element belongs to
21627 regDragDrop: function(oDD, sGroup) {
21628 if (!this.initialized) { this.init(); }
21630 if (!this.ids[sGroup]) {
21631 this.ids[sGroup] = {};
21633 this.ids[sGroup][oDD.id] = oDD;
21637 * Removes the supplied dd instance from the supplied group. Executed
21638 * by DragDrop.removeFromGroup, so don't call this function directly.
21639 * @method removeDDFromGroup
21643 removeDDFromGroup: function(oDD, sGroup) {
21644 if (!this.ids[sGroup]) {
21645 this.ids[sGroup] = {};
21648 var obj = this.ids[sGroup];
21649 if (obj && obj[oDD.id]) {
21650 delete obj[oDD.id];
21655 * Unregisters a drag and drop item. This is executed in
21656 * DragDrop.unreg, use that method instead of calling this directly.
21661 _remove: function(oDD) {
21662 for (var g in oDD.groups) {
21663 if (g && this.ids[g][oDD.id]) {
21664 delete this.ids[g][oDD.id];
21667 delete this.handleIds[oDD.id];
21671 * Each DragDrop handle element must be registered. This is done
21672 * automatically when executing DragDrop.setHandleElId()
21673 * @method regHandle
21674 * @param {String} sDDId the DragDrop id this element is a handle for
21675 * @param {String} sHandleId the id of the element that is the drag
21679 regHandle: function(sDDId, sHandleId) {
21680 if (!this.handleIds[sDDId]) {
21681 this.handleIds[sDDId] = {};
21683 this.handleIds[sDDId][sHandleId] = sHandleId;
21687 * Utility function to determine if a given element has been
21688 * registered as a drag drop item.
21689 * @method isDragDrop
21690 * @param {String} id the element id to check
21691 * @return {boolean} true if this element is a DragDrop item,
21695 isDragDrop: function(id) {
21696 return ( this.getDDById(id) ) ? true : false;
21700 * Returns the drag and drop instances that are in all groups the
21701 * passed in instance belongs to.
21702 * @method getRelated
21703 * @param {DragDrop} p_oDD the obj to get related data for
21704 * @param {boolean} bTargetsOnly if true, only return targetable objs
21705 * @return {DragDrop[]} the related instances
21708 getRelated: function(p_oDD, bTargetsOnly) {
21710 for (var i in p_oDD.groups) {
21711 for (j in this.ids[i]) {
21712 var dd = this.ids[i][j];
21713 if (! this.isTypeOfDD(dd)) {
21716 if (!bTargetsOnly || dd.isTarget) {
21717 oDDs[oDDs.length] = dd;
21726 * Returns true if the specified dd target is a legal target for
21727 * the specifice drag obj
21728 * @method isLegalTarget
21729 * @param {DragDrop} the drag obj
21730 * @param {DragDrop} the target
21731 * @return {boolean} true if the target is a legal target for the
21735 isLegalTarget: function (oDD, oTargetDD) {
21736 var targets = this.getRelated(oDD, true);
21737 for (var i=0, len=targets.length;i<len;++i) {
21738 if (targets[i].id == oTargetDD.id) {
21747 * My goal is to be able to transparently determine if an object is
21748 * typeof DragDrop, and the exact subclass of DragDrop. typeof
21749 * returns "object", oDD.constructor.toString() always returns
21750 * "DragDrop" and not the name of the subclass. So for now it just
21751 * evaluates a well-known variable in DragDrop.
21752 * @method isTypeOfDD
21753 * @param {Object} the object to evaluate
21754 * @return {boolean} true if typeof oDD = DragDrop
21757 isTypeOfDD: function (oDD) {
21758 return (oDD && oDD.__ygDragDrop);
21762 * Utility function to determine if a given element has been
21763 * registered as a drag drop handle for the given Drag Drop object.
21765 * @param {String} id the element id to check
21766 * @return {boolean} true if this element is a DragDrop handle, false
21770 isHandle: function(sDDId, sHandleId) {
21771 return ( this.handleIds[sDDId] &&
21772 this.handleIds[sDDId][sHandleId] );
21776 * Returns the DragDrop instance for a given id
21777 * @method getDDById
21778 * @param {String} id the id of the DragDrop object
21779 * @return {DragDrop} the drag drop object, null if it is not found
21782 getDDById: function(id) {
21783 for (var i in this.ids) {
21784 if (this.ids[i][id]) {
21785 return this.ids[i][id];
21792 * Fired after a registered DragDrop object gets the mousedown event.
21793 * Sets up the events required to track the object being dragged
21794 * @method handleMouseDown
21795 * @param {Event} e the event
21796 * @param oDD the DragDrop object being dragged
21800 handleMouseDown: function(e, oDD) {
21802 Roo.QuickTips.disable();
21804 this.currentTarget = e.getTarget();
21806 this.dragCurrent = oDD;
21808 var el = oDD.getEl();
21810 // track start position
21811 this.startX = e.getPageX();
21812 this.startY = e.getPageY();
21814 this.deltaX = this.startX - el.offsetLeft;
21815 this.deltaY = this.startY - el.offsetTop;
21817 this.dragThreshMet = false;
21819 this.clickTimeout = setTimeout(
21821 var DDM = Roo.dd.DDM;
21822 DDM.startDrag(DDM.startX, DDM.startY);
21824 this.clickTimeThresh );
21828 * Fired when either the drag pixel threshol or the mousedown hold
21829 * time threshold has been met.
21830 * @method startDrag
21831 * @param x {int} the X position of the original mousedown
21832 * @param y {int} the Y position of the original mousedown
21835 startDrag: function(x, y) {
21836 clearTimeout(this.clickTimeout);
21837 if (this.dragCurrent) {
21838 this.dragCurrent.b4StartDrag(x, y);
21839 this.dragCurrent.startDrag(x, y);
21841 this.dragThreshMet = true;
21845 * Internal function to handle the mouseup event. Will be invoked
21846 * from the context of the document.
21847 * @method handleMouseUp
21848 * @param {Event} e the event
21852 handleMouseUp: function(e) {
21855 Roo.QuickTips.enable();
21857 if (! this.dragCurrent) {
21861 clearTimeout(this.clickTimeout);
21863 if (this.dragThreshMet) {
21864 this.fireEvents(e, true);
21874 * Utility to stop event propagation and event default, if these
21875 * features are turned on.
21876 * @method stopEvent
21877 * @param {Event} e the event as returned by this.getEvent()
21880 stopEvent: function(e){
21881 if(this.stopPropagation) {
21882 e.stopPropagation();
21885 if (this.preventDefault) {
21886 e.preventDefault();
21891 * Internal function to clean up event handlers after the drag
21892 * operation is complete
21894 * @param {Event} e the event
21898 stopDrag: function(e) {
21899 // Fire the drag end event for the item that was dragged
21900 if (this.dragCurrent) {
21901 if (this.dragThreshMet) {
21902 this.dragCurrent.b4EndDrag(e);
21903 this.dragCurrent.endDrag(e);
21906 this.dragCurrent.onMouseUp(e);
21909 this.dragCurrent = null;
21910 this.dragOvers = {};
21914 * Internal function to handle the mousemove event. Will be invoked
21915 * from the context of the html element.
21917 * @TODO figure out what we can do about mouse events lost when the
21918 * user drags objects beyond the window boundary. Currently we can
21919 * detect this in internet explorer by verifying that the mouse is
21920 * down during the mousemove event. Firefox doesn't give us the
21921 * button state on the mousemove event.
21922 * @method handleMouseMove
21923 * @param {Event} e the event
21927 handleMouseMove: function(e) {
21928 if (! this.dragCurrent) {
21932 // var button = e.which || e.button;
21934 // check for IE mouseup outside of page boundary
21935 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
21937 return this.handleMouseUp(e);
21940 if (!this.dragThreshMet) {
21941 var diffX = Math.abs(this.startX - e.getPageX());
21942 var diffY = Math.abs(this.startY - e.getPageY());
21943 if (diffX > this.clickPixelThresh ||
21944 diffY > this.clickPixelThresh) {
21945 this.startDrag(this.startX, this.startY);
21949 if (this.dragThreshMet) {
21950 this.dragCurrent.b4Drag(e);
21951 this.dragCurrent.onDrag(e);
21952 if(!this.dragCurrent.moveOnly){
21953 this.fireEvents(e, false);
21963 * Iterates over all of the DragDrop elements to find ones we are
21964 * hovering over or dropping on
21965 * @method fireEvents
21966 * @param {Event} e the event
21967 * @param {boolean} isDrop is this a drop op or a mouseover op?
21971 fireEvents: function(e, isDrop) {
21972 var dc = this.dragCurrent;
21974 // If the user did the mouse up outside of the window, we could
21975 // get here even though we have ended the drag.
21976 if (!dc || dc.isLocked()) {
21980 var pt = e.getPoint();
21982 // cache the previous dragOver array
21988 var enterEvts = [];
21990 // Check to see if the object(s) we were hovering over is no longer
21991 // being hovered over so we can fire the onDragOut event
21992 for (var i in this.dragOvers) {
21994 var ddo = this.dragOvers[i];
21996 if (! this.isTypeOfDD(ddo)) {
22000 if (! this.isOverTarget(pt, ddo, this.mode)) {
22001 outEvts.push( ddo );
22004 oldOvers[i] = true;
22005 delete this.dragOvers[i];
22008 for (var sGroup in dc.groups) {
22010 if ("string" != typeof sGroup) {
22014 for (i in this.ids[sGroup]) {
22015 var oDD = this.ids[sGroup][i];
22016 if (! this.isTypeOfDD(oDD)) {
22020 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
22021 if (this.isOverTarget(pt, oDD, this.mode)) {
22022 // look for drop interactions
22024 dropEvts.push( oDD );
22025 // look for drag enter and drag over interactions
22028 // initial drag over: dragEnter fires
22029 if (!oldOvers[oDD.id]) {
22030 enterEvts.push( oDD );
22031 // subsequent drag overs: dragOver fires
22033 overEvts.push( oDD );
22036 this.dragOvers[oDD.id] = oDD;
22044 if (outEvts.length) {
22045 dc.b4DragOut(e, outEvts);
22046 dc.onDragOut(e, outEvts);
22049 if (enterEvts.length) {
22050 dc.onDragEnter(e, enterEvts);
22053 if (overEvts.length) {
22054 dc.b4DragOver(e, overEvts);
22055 dc.onDragOver(e, overEvts);
22058 if (dropEvts.length) {
22059 dc.b4DragDrop(e, dropEvts);
22060 dc.onDragDrop(e, dropEvts);
22064 // fire dragout events
22066 for (i=0, len=outEvts.length; i<len; ++i) {
22067 dc.b4DragOut(e, outEvts[i].id);
22068 dc.onDragOut(e, outEvts[i].id);
22071 // fire enter events
22072 for (i=0,len=enterEvts.length; i<len; ++i) {
22073 // dc.b4DragEnter(e, oDD.id);
22074 dc.onDragEnter(e, enterEvts[i].id);
22077 // fire over events
22078 for (i=0,len=overEvts.length; i<len; ++i) {
22079 dc.b4DragOver(e, overEvts[i].id);
22080 dc.onDragOver(e, overEvts[i].id);
22083 // fire drop events
22084 for (i=0, len=dropEvts.length; i<len; ++i) {
22085 dc.b4DragDrop(e, dropEvts[i].id);
22086 dc.onDragDrop(e, dropEvts[i].id);
22091 // notify about a drop that did not find a target
22092 if (isDrop && !dropEvts.length) {
22093 dc.onInvalidDrop(e);
22099 * Helper function for getting the best match from the list of drag
22100 * and drop objects returned by the drag and drop events when we are
22101 * in INTERSECT mode. It returns either the first object that the
22102 * cursor is over, or the object that has the greatest overlap with
22103 * the dragged element.
22104 * @method getBestMatch
22105 * @param {DragDrop[]} dds The array of drag and drop objects
22107 * @return {DragDrop} The best single match
22110 getBestMatch: function(dds) {
22112 // Return null if the input is not what we expect
22113 //if (!dds || !dds.length || dds.length == 0) {
22115 // If there is only one item, it wins
22116 //} else if (dds.length == 1) {
22118 var len = dds.length;
22123 // Loop through the targeted items
22124 for (var i=0; i<len; ++i) {
22126 // If the cursor is over the object, it wins. If the
22127 // cursor is over multiple matches, the first one we come
22129 if (dd.cursorIsOver) {
22132 // Otherwise the object with the most overlap wins
22135 winner.overlap.getArea() < dd.overlap.getArea()) {
22146 * Refreshes the cache of the top-left and bottom-right points of the
22147 * drag and drop objects in the specified group(s). This is in the
22148 * format that is stored in the drag and drop instance, so typical
22151 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
22155 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
22157 * @TODO this really should be an indexed array. Alternatively this
22158 * method could accept both.
22159 * @method refreshCache
22160 * @param {Object} groups an associative array of groups to refresh
22163 refreshCache: function(groups) {
22164 for (var sGroup in groups) {
22165 if ("string" != typeof sGroup) {
22168 for (var i in this.ids[sGroup]) {
22169 var oDD = this.ids[sGroup][i];
22171 if (this.isTypeOfDD(oDD)) {
22172 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
22173 var loc = this.getLocation(oDD);
22175 this.locationCache[oDD.id] = loc;
22177 delete this.locationCache[oDD.id];
22178 // this will unregister the drag and drop object if
22179 // the element is not in a usable state
22188 * This checks to make sure an element exists and is in the DOM. The
22189 * main purpose is to handle cases where innerHTML is used to remove
22190 * drag and drop objects from the DOM. IE provides an 'unspecified
22191 * error' when trying to access the offsetParent of such an element
22193 * @param {HTMLElement} el the element to check
22194 * @return {boolean} true if the element looks usable
22197 verifyEl: function(el) {
22202 parent = el.offsetParent;
22205 parent = el.offsetParent;
22216 * Returns a Region object containing the drag and drop element's position
22217 * and size, including the padding configured for it
22218 * @method getLocation
22219 * @param {DragDrop} oDD the drag and drop object to get the
22221 * @return {Roo.lib.Region} a Region object representing the total area
22222 * the element occupies, including any padding
22223 * the instance is configured for.
22226 getLocation: function(oDD) {
22227 if (! this.isTypeOfDD(oDD)) {
22231 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
22234 pos= Roo.lib.Dom.getXY(el);
22242 x2 = x1 + el.offsetWidth;
22244 y2 = y1 + el.offsetHeight;
22246 t = y1 - oDD.padding[0];
22247 r = x2 + oDD.padding[1];
22248 b = y2 + oDD.padding[2];
22249 l = x1 - oDD.padding[3];
22251 return new Roo.lib.Region( t, r, b, l );
22255 * Checks the cursor location to see if it over the target
22256 * @method isOverTarget
22257 * @param {Roo.lib.Point} pt The point to evaluate
22258 * @param {DragDrop} oTarget the DragDrop object we are inspecting
22259 * @return {boolean} true if the mouse is over the target
22263 isOverTarget: function(pt, oTarget, intersect) {
22264 // use cache if available
22265 var loc = this.locationCache[oTarget.id];
22266 if (!loc || !this.useCache) {
22267 loc = this.getLocation(oTarget);
22268 this.locationCache[oTarget.id] = loc;
22276 oTarget.cursorIsOver = loc.contains( pt );
22278 // DragDrop is using this as a sanity check for the initial mousedown
22279 // in this case we are done. In POINT mode, if the drag obj has no
22280 // contraints, we are also done. Otherwise we need to evaluate the
22281 // location of the target as related to the actual location of the
22282 // dragged element.
22283 var dc = this.dragCurrent;
22284 if (!dc || !dc.getTargetCoord ||
22285 (!intersect && !dc.constrainX && !dc.constrainY)) {
22286 return oTarget.cursorIsOver;
22289 oTarget.overlap = null;
22291 // Get the current location of the drag element, this is the
22292 // location of the mouse event less the delta that represents
22293 // where the original mousedown happened on the element. We
22294 // need to consider constraints and ticks as well.
22295 var pos = dc.getTargetCoord(pt.x, pt.y);
22297 var el = dc.getDragEl();
22298 var curRegion = new Roo.lib.Region( pos.y,
22299 pos.x + el.offsetWidth,
22300 pos.y + el.offsetHeight,
22303 var overlap = curRegion.intersect(loc);
22306 oTarget.overlap = overlap;
22307 return (intersect) ? true : oTarget.cursorIsOver;
22314 * unload event handler
22315 * @method _onUnload
22319 _onUnload: function(e, me) {
22320 Roo.dd.DragDropMgr.unregAll();
22324 * Cleans up the drag and drop events and objects.
22329 unregAll: function() {
22331 if (this.dragCurrent) {
22333 this.dragCurrent = null;
22336 this._execOnAll("unreg", []);
22338 for (i in this.elementCache) {
22339 delete this.elementCache[i];
22342 this.elementCache = {};
22347 * A cache of DOM elements
22348 * @property elementCache
22355 * Get the wrapper for the DOM element specified
22356 * @method getElWrapper
22357 * @param {String} id the id of the element to get
22358 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
22360 * @deprecated This wrapper isn't that useful
22363 getElWrapper: function(id) {
22364 var oWrapper = this.elementCache[id];
22365 if (!oWrapper || !oWrapper.el) {
22366 oWrapper = this.elementCache[id] =
22367 new this.ElementWrapper(Roo.getDom(id));
22373 * Returns the actual DOM element
22374 * @method getElement
22375 * @param {String} id the id of the elment to get
22376 * @return {Object} The element
22377 * @deprecated use Roo.getDom instead
22380 getElement: function(id) {
22381 return Roo.getDom(id);
22385 * Returns the style property for the DOM element (i.e.,
22386 * document.getElById(id).style)
22388 * @param {String} id the id of the elment to get
22389 * @return {Object} The style property of the element
22390 * @deprecated use Roo.getDom instead
22393 getCss: function(id) {
22394 var el = Roo.getDom(id);
22395 return (el) ? el.style : null;
22399 * Inner class for cached elements
22400 * @class DragDropMgr.ElementWrapper
22405 ElementWrapper: function(el) {
22410 this.el = el || null;
22415 this.id = this.el && el.id;
22417 * A reference to the style property
22420 this.css = this.el && el.style;
22424 * Returns the X position of an html element
22426 * @param el the element for which to get the position
22427 * @return {int} the X coordinate
22429 * @deprecated use Roo.lib.Dom.getX instead
22432 getPosX: function(el) {
22433 return Roo.lib.Dom.getX(el);
22437 * Returns the Y position of an html element
22439 * @param el the element for which to get the position
22440 * @return {int} the Y coordinate
22441 * @deprecated use Roo.lib.Dom.getY instead
22444 getPosY: function(el) {
22445 return Roo.lib.Dom.getY(el);
22449 * Swap two nodes. In IE, we use the native method, for others we
22450 * emulate the IE behavior
22452 * @param n1 the first node to swap
22453 * @param n2 the other node to swap
22456 swapNode: function(n1, n2) {
22460 var p = n2.parentNode;
22461 var s = n2.nextSibling;
22464 p.insertBefore(n1, n2);
22465 } else if (n2 == n1.nextSibling) {
22466 p.insertBefore(n2, n1);
22468 n1.parentNode.replaceChild(n2, n1);
22469 p.insertBefore(n1, s);
22475 * Returns the current scroll position
22476 * @method getScroll
22480 getScroll: function () {
22481 var t, l, dde=document.documentElement, db=document.body;
22482 if (dde && (dde.scrollTop || dde.scrollLeft)) {
22484 l = dde.scrollLeft;
22491 return { top: t, left: l };
22495 * Returns the specified element style property
22497 * @param {HTMLElement} el the element
22498 * @param {string} styleProp the style property
22499 * @return {string} The value of the style property
22500 * @deprecated use Roo.lib.Dom.getStyle
22503 getStyle: function(el, styleProp) {
22504 return Roo.fly(el).getStyle(styleProp);
22508 * Gets the scrollTop
22509 * @method getScrollTop
22510 * @return {int} the document's scrollTop
22513 getScrollTop: function () { return this.getScroll().top; },
22516 * Gets the scrollLeft
22517 * @method getScrollLeft
22518 * @return {int} the document's scrollTop
22521 getScrollLeft: function () { return this.getScroll().left; },
22524 * Sets the x/y position of an element to the location of the
22527 * @param {HTMLElement} moveEl The element to move
22528 * @param {HTMLElement} targetEl The position reference element
22531 moveToEl: function (moveEl, targetEl) {
22532 var aCoord = Roo.lib.Dom.getXY(targetEl);
22533 Roo.lib.Dom.setXY(moveEl, aCoord);
22537 * Numeric array sort function
22538 * @method numericSort
22541 numericSort: function(a, b) { return (a - b); },
22545 * @property _timeoutCount
22552 * Trying to make the load order less important. Without this we get
22553 * an error if this file is loaded before the Event Utility.
22554 * @method _addListeners
22558 _addListeners: function() {
22559 var DDM = Roo.dd.DDM;
22560 if ( Roo.lib.Event && document ) {
22563 if (DDM._timeoutCount > 2000) {
22565 setTimeout(DDM._addListeners, 10);
22566 if (document && document.body) {
22567 DDM._timeoutCount += 1;
22574 * Recursively searches the immediate parent and all child nodes for
22575 * the handle element in order to determine wheter or not it was
22577 * @method handleWasClicked
22578 * @param node the html element to inspect
22581 handleWasClicked: function(node, id) {
22582 if (this.isHandle(id, node.id)) {
22585 // check to see if this is a text node child of the one we want
22586 var p = node.parentNode;
22589 if (this.isHandle(id, p.id)) {
22604 // shorter alias, save a few bytes
22605 Roo.dd.DDM = Roo.dd.DragDropMgr;
22606 Roo.dd.DDM._addListeners();
22610 * Ext JS Library 1.1.1
22611 * Copyright(c) 2006-2007, Ext JS, LLC.
22613 * Originally Released Under LGPL - original licence link has changed is not relivant.
22616 * <script type="text/javascript">
22621 * A DragDrop implementation where the linked element follows the
22622 * mouse cursor during a drag.
22623 * @extends Roo.dd.DragDrop
22625 * @param {String} id the id of the linked element
22626 * @param {String} sGroup the group of related DragDrop items
22627 * @param {object} config an object containing configurable attributes
22628 * Valid properties for DD:
22631 Roo.dd.DD = function(id, sGroup, config) {
22633 this.init(id, sGroup, config);
22637 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
22640 * When set to true, the utility automatically tries to scroll the browser
22641 * window wehn a drag and drop element is dragged near the viewport boundary.
22642 * Defaults to true.
22649 * Sets the pointer offset to the distance between the linked element's top
22650 * left corner and the location the element was clicked
22651 * @method autoOffset
22652 * @param {int} iPageX the X coordinate of the click
22653 * @param {int} iPageY the Y coordinate of the click
22655 autoOffset: function(iPageX, iPageY) {
22656 var x = iPageX - this.startPageX;
22657 var y = iPageY - this.startPageY;
22658 this.setDelta(x, y);
22662 * Sets the pointer offset. You can call this directly to force the
22663 * offset to be in a particular location (e.g., pass in 0,0 to set it
22664 * to the center of the object)
22666 * @param {int} iDeltaX the distance from the left
22667 * @param {int} iDeltaY the distance from the top
22669 setDelta: function(iDeltaX, iDeltaY) {
22670 this.deltaX = iDeltaX;
22671 this.deltaY = iDeltaY;
22675 * Sets the drag element to the location of the mousedown or click event,
22676 * maintaining the cursor location relative to the location on the element
22677 * that was clicked. Override this if you want to place the element in a
22678 * location other than where the cursor is.
22679 * @method setDragElPos
22680 * @param {int} iPageX the X coordinate of the mousedown or drag event
22681 * @param {int} iPageY the Y coordinate of the mousedown or drag event
22683 setDragElPos: function(iPageX, iPageY) {
22684 // the first time we do this, we are going to check to make sure
22685 // the element has css positioning
22687 var el = this.getDragEl();
22688 this.alignElWithMouse(el, iPageX, iPageY);
22692 * Sets the element to the location of the mousedown or click event,
22693 * maintaining the cursor location relative to the location on the element
22694 * that was clicked. Override this if you want to place the element in a
22695 * location other than where the cursor is.
22696 * @method alignElWithMouse
22697 * @param {HTMLElement} el the element to move
22698 * @param {int} iPageX the X coordinate of the mousedown or drag event
22699 * @param {int} iPageY the Y coordinate of the mousedown or drag event
22701 alignElWithMouse: function(el, iPageX, iPageY) {
22702 var oCoord = this.getTargetCoord(iPageX, iPageY);
22703 var fly = el.dom ? el : Roo.fly(el);
22704 if (!this.deltaSetXY) {
22705 var aCoord = [oCoord.x, oCoord.y];
22707 var newLeft = fly.getLeft(true);
22708 var newTop = fly.getTop(true);
22709 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
22711 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
22714 this.cachePosition(oCoord.x, oCoord.y);
22715 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
22720 * Saves the most recent position so that we can reset the constraints and
22721 * tick marks on-demand. We need to know this so that we can calculate the
22722 * number of pixels the element is offset from its original position.
22723 * @method cachePosition
22724 * @param iPageX the current x position (optional, this just makes it so we
22725 * don't have to look it up again)
22726 * @param iPageY the current y position (optional, this just makes it so we
22727 * don't have to look it up again)
22729 cachePosition: function(iPageX, iPageY) {
22731 this.lastPageX = iPageX;
22732 this.lastPageY = iPageY;
22734 var aCoord = Roo.lib.Dom.getXY(this.getEl());
22735 this.lastPageX = aCoord[0];
22736 this.lastPageY = aCoord[1];
22741 * Auto-scroll the window if the dragged object has been moved beyond the
22742 * visible window boundary.
22743 * @method autoScroll
22744 * @param {int} x the drag element's x position
22745 * @param {int} y the drag element's y position
22746 * @param {int} h the height of the drag element
22747 * @param {int} w the width of the drag element
22750 autoScroll: function(x, y, h, w) {
22753 // The client height
22754 var clientH = Roo.lib.Dom.getViewWidth();
22756 // The client width
22757 var clientW = Roo.lib.Dom.getViewHeight();
22759 // The amt scrolled down
22760 var st = this.DDM.getScrollTop();
22762 // The amt scrolled right
22763 var sl = this.DDM.getScrollLeft();
22765 // Location of the bottom of the element
22768 // Location of the right of the element
22771 // The distance from the cursor to the bottom of the visible area,
22772 // adjusted so that we don't scroll if the cursor is beyond the
22773 // element drag constraints
22774 var toBot = (clientH + st - y - this.deltaY);
22776 // The distance from the cursor to the right of the visible area
22777 var toRight = (clientW + sl - x - this.deltaX);
22780 // How close to the edge the cursor must be before we scroll
22781 // var thresh = (document.all) ? 100 : 40;
22784 // How many pixels to scroll per autoscroll op. This helps to reduce
22785 // clunky scrolling. IE is more sensitive about this ... it needs this
22786 // value to be higher.
22787 var scrAmt = (document.all) ? 80 : 30;
22789 // Scroll down if we are near the bottom of the visible page and the
22790 // obj extends below the crease
22791 if ( bot > clientH && toBot < thresh ) {
22792 window.scrollTo(sl, st + scrAmt);
22795 // Scroll up if the window is scrolled down and the top of the object
22796 // goes above the top border
22797 if ( y < st && st > 0 && y - st < thresh ) {
22798 window.scrollTo(sl, st - scrAmt);
22801 // Scroll right if the obj is beyond the right border and the cursor is
22802 // near the border.
22803 if ( right > clientW && toRight < thresh ) {
22804 window.scrollTo(sl + scrAmt, st);
22807 // Scroll left if the window has been scrolled to the right and the obj
22808 // extends past the left border
22809 if ( x < sl && sl > 0 && x - sl < thresh ) {
22810 window.scrollTo(sl - scrAmt, st);
22816 * Finds the location the element should be placed if we want to move
22817 * it to where the mouse location less the click offset would place us.
22818 * @method getTargetCoord
22819 * @param {int} iPageX the X coordinate of the click
22820 * @param {int} iPageY the Y coordinate of the click
22821 * @return an object that contains the coordinates (Object.x and Object.y)
22824 getTargetCoord: function(iPageX, iPageY) {
22827 var x = iPageX - this.deltaX;
22828 var y = iPageY - this.deltaY;
22830 if (this.constrainX) {
22831 if (x < this.minX) { x = this.minX; }
22832 if (x > this.maxX) { x = this.maxX; }
22835 if (this.constrainY) {
22836 if (y < this.minY) { y = this.minY; }
22837 if (y > this.maxY) { y = this.maxY; }
22840 x = this.getTick(x, this.xTicks);
22841 y = this.getTick(y, this.yTicks);
22848 * Sets up config options specific to this class. Overrides
22849 * Roo.dd.DragDrop, but all versions of this method through the
22850 * inheritance chain are called
22852 applyConfig: function() {
22853 Roo.dd.DD.superclass.applyConfig.call(this);
22854 this.scroll = (this.config.scroll !== false);
22858 * Event that fires prior to the onMouseDown event. Overrides
22861 b4MouseDown: function(e) {
22862 // this.resetConstraints();
22863 this.autoOffset(e.getPageX(),
22868 * Event that fires prior to the onDrag event. Overrides
22871 b4Drag: function(e) {
22872 this.setDragElPos(e.getPageX(),
22876 toString: function() {
22877 return ("DD " + this.id);
22880 //////////////////////////////////////////////////////////////////////////
22881 // Debugging ygDragDrop events that can be overridden
22882 //////////////////////////////////////////////////////////////////////////
22884 startDrag: function(x, y) {
22887 onDrag: function(e) {
22890 onDragEnter: function(e, id) {
22893 onDragOver: function(e, id) {
22896 onDragOut: function(e, id) {
22899 onDragDrop: function(e, id) {
22902 endDrag: function(e) {
22909 * Ext JS Library 1.1.1
22910 * Copyright(c) 2006-2007, Ext JS, LLC.
22912 * Originally Released Under LGPL - original licence link has changed is not relivant.
22915 * <script type="text/javascript">
22919 * @class Roo.dd.DDProxy
22920 * A DragDrop implementation that inserts an empty, bordered div into
22921 * the document that follows the cursor during drag operations. At the time of
22922 * the click, the frame div is resized to the dimensions of the linked html
22923 * element, and moved to the exact location of the linked element.
22925 * References to the "frame" element refer to the single proxy element that
22926 * was created to be dragged in place of all DDProxy elements on the
22929 * @extends Roo.dd.DD
22931 * @param {String} id the id of the linked html element
22932 * @param {String} sGroup the group of related DragDrop objects
22933 * @param {object} config an object containing configurable attributes
22934 * Valid properties for DDProxy in addition to those in DragDrop:
22935 * resizeFrame, centerFrame, dragElId
22937 Roo.dd.DDProxy = function(id, sGroup, config) {
22939 this.init(id, sGroup, config);
22945 * The default drag frame div id
22946 * @property Roo.dd.DDProxy.dragElId
22950 Roo.dd.DDProxy.dragElId = "ygddfdiv";
22952 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
22955 * By default we resize the drag frame to be the same size as the element
22956 * we want to drag (this is to get the frame effect). We can turn it off
22957 * if we want a different behavior.
22958 * @property resizeFrame
22964 * By default the frame is positioned exactly where the drag element is, so
22965 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
22966 * you do not have constraints on the obj is to have the drag frame centered
22967 * around the cursor. Set centerFrame to true for this effect.
22968 * @property centerFrame
22971 centerFrame: false,
22974 * Creates the proxy element if it does not yet exist
22975 * @method createFrame
22977 createFrame: function() {
22979 var body = document.body;
22981 if (!body || !body.firstChild) {
22982 setTimeout( function() { self.createFrame(); }, 50 );
22986 var div = this.getDragEl();
22989 div = document.createElement("div");
22990 div.id = this.dragElId;
22993 s.position = "absolute";
22994 s.visibility = "hidden";
22996 s.border = "2px solid #aaa";
22999 // appendChild can blow up IE if invoked prior to the window load event
23000 // while rendering a table. It is possible there are other scenarios
23001 // that would cause this to happen as well.
23002 body.insertBefore(div, body.firstChild);
23007 * Initialization for the drag frame element. Must be called in the
23008 * constructor of all subclasses
23009 * @method initFrame
23011 initFrame: function() {
23012 this.createFrame();
23015 applyConfig: function() {
23016 Roo.dd.DDProxy.superclass.applyConfig.call(this);
23018 this.resizeFrame = (this.config.resizeFrame !== false);
23019 this.centerFrame = (this.config.centerFrame);
23020 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
23024 * Resizes the drag frame to the dimensions of the clicked object, positions
23025 * it over the object, and finally displays it
23026 * @method showFrame
23027 * @param {int} iPageX X click position
23028 * @param {int} iPageY Y click position
23031 showFrame: function(iPageX, iPageY) {
23032 var el = this.getEl();
23033 var dragEl = this.getDragEl();
23034 var s = dragEl.style;
23036 this._resizeProxy();
23038 if (this.centerFrame) {
23039 this.setDelta( Math.round(parseInt(s.width, 10)/2),
23040 Math.round(parseInt(s.height, 10)/2) );
23043 this.setDragElPos(iPageX, iPageY);
23045 Roo.fly(dragEl).show();
23049 * The proxy is automatically resized to the dimensions of the linked
23050 * element when a drag is initiated, unless resizeFrame is set to false
23051 * @method _resizeProxy
23054 _resizeProxy: function() {
23055 if (this.resizeFrame) {
23056 var el = this.getEl();
23057 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
23061 // overrides Roo.dd.DragDrop
23062 b4MouseDown: function(e) {
23063 var x = e.getPageX();
23064 var y = e.getPageY();
23065 this.autoOffset(x, y);
23066 this.setDragElPos(x, y);
23069 // overrides Roo.dd.DragDrop
23070 b4StartDrag: function(x, y) {
23071 // show the drag frame
23072 this.showFrame(x, y);
23075 // overrides Roo.dd.DragDrop
23076 b4EndDrag: function(e) {
23077 Roo.fly(this.getDragEl()).hide();
23080 // overrides Roo.dd.DragDrop
23081 // By default we try to move the element to the last location of the frame.
23082 // This is so that the default behavior mirrors that of Roo.dd.DD.
23083 endDrag: function(e) {
23085 var lel = this.getEl();
23086 var del = this.getDragEl();
23088 // Show the drag frame briefly so we can get its position
23089 del.style.visibility = "";
23092 // Hide the linked element before the move to get around a Safari
23094 lel.style.visibility = "hidden";
23095 Roo.dd.DDM.moveToEl(lel, del);
23096 del.style.visibility = "hidden";
23097 lel.style.visibility = "";
23102 beforeMove : function(){
23106 afterDrag : function(){
23110 toString: function() {
23111 return ("DDProxy " + this.id);
23117 * Ext JS Library 1.1.1
23118 * Copyright(c) 2006-2007, Ext JS, LLC.
23120 * Originally Released Under LGPL - original licence link has changed is not relivant.
23123 * <script type="text/javascript">
23127 * @class Roo.dd.DDTarget
23128 * A DragDrop implementation that does not move, but can be a drop
23129 * target. You would get the same result by simply omitting implementation
23130 * for the event callbacks, but this way we reduce the processing cost of the
23131 * event listener and the callbacks.
23132 * @extends Roo.dd.DragDrop
23134 * @param {String} id the id of the element that is a drop target
23135 * @param {String} sGroup the group of related DragDrop objects
23136 * @param {object} config an object containing configurable attributes
23137 * Valid properties for DDTarget in addition to those in
23141 Roo.dd.DDTarget = function(id, sGroup, config) {
23143 this.initTarget(id, sGroup, config);
23145 if (config && (config.listeners || config.events)) {
23146 Roo.dd.DragDrop.superclass.constructor.call(this, {
23147 listeners : config.listeners || {},
23148 events : config.events || {}
23153 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
23154 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
23155 toString: function() {
23156 return ("DDTarget " + this.id);
23161 * Ext JS Library 1.1.1
23162 * Copyright(c) 2006-2007, Ext JS, LLC.
23164 * Originally Released Under LGPL - original licence link has changed is not relivant.
23167 * <script type="text/javascript">
23172 * @class Roo.dd.ScrollManager
23173 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
23174 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
23177 Roo.dd.ScrollManager = function(){
23178 var ddm = Roo.dd.DragDropMgr;
23185 var onStop = function(e){
23190 var triggerRefresh = function(){
23191 if(ddm.dragCurrent){
23192 ddm.refreshCache(ddm.dragCurrent.groups);
23196 var doScroll = function(){
23197 if(ddm.dragCurrent){
23198 var dds = Roo.dd.ScrollManager;
23200 if(proc.el.scroll(proc.dir, dds.increment)){
23204 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
23209 var clearProc = function(){
23211 clearInterval(proc.id);
23218 var startProc = function(el, dir){
23219 Roo.log('scroll startproc');
23223 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
23226 var onFire = function(e, isDrop){
23228 if(isDrop || !ddm.dragCurrent){ return; }
23229 var dds = Roo.dd.ScrollManager;
23230 if(!dragEl || dragEl != ddm.dragCurrent){
23231 dragEl = ddm.dragCurrent;
23232 // refresh regions on drag start
23233 dds.refreshCache();
23236 var xy = Roo.lib.Event.getXY(e);
23237 var pt = new Roo.lib.Point(xy[0], xy[1]);
23238 for(var id in els){
23239 var el = els[id], r = el._region;
23240 if(r && r.contains(pt) && el.isScrollable()){
23241 if(r.bottom - pt.y <= dds.thresh){
23243 startProc(el, "down");
23246 }else if(r.right - pt.x <= dds.thresh){
23248 startProc(el, "left");
23251 }else if(pt.y - r.top <= dds.thresh){
23253 startProc(el, "up");
23256 }else if(pt.x - r.left <= dds.thresh){
23258 startProc(el, "right");
23267 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
23268 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
23272 * Registers new overflow element(s) to auto scroll
23273 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
23275 register : function(el){
23276 if(el instanceof Array){
23277 for(var i = 0, len = el.length; i < len; i++) {
23278 this.register(el[i]);
23284 Roo.dd.ScrollManager.els = els;
23288 * Unregisters overflow element(s) so they are no longer scrolled
23289 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
23291 unregister : function(el){
23292 if(el instanceof Array){
23293 for(var i = 0, len = el.length; i < len; i++) {
23294 this.unregister(el[i]);
23303 * The number of pixels from the edge of a container the pointer needs to be to
23304 * trigger scrolling (defaults to 25)
23310 * The number of pixels to scroll in each scroll increment (defaults to 50)
23316 * The frequency of scrolls in milliseconds (defaults to 500)
23322 * True to animate the scroll (defaults to true)
23328 * The animation duration in seconds -
23329 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
23335 * Manually trigger a cache refresh.
23337 refreshCache : function(){
23338 for(var id in els){
23339 if(typeof els[id] == 'object'){ // for people extending the object prototype
23340 els[id]._region = els[id].getRegion();
23347 * Ext JS Library 1.1.1
23348 * Copyright(c) 2006-2007, Ext JS, LLC.
23350 * Originally Released Under LGPL - original licence link has changed is not relivant.
23353 * <script type="text/javascript">
23358 * @class Roo.dd.Registry
23359 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
23360 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
23363 Roo.dd.Registry = function(){
23366 var autoIdSeed = 0;
23368 var getId = function(el, autogen){
23369 if(typeof el == "string"){
23373 if(!id && autogen !== false){
23374 id = "roodd-" + (++autoIdSeed);
23382 * Register a drag drop element
23383 * @param {String|HTMLElement} element The id or DOM node to register
23384 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
23385 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
23386 * knows how to interpret, plus there are some specific properties known to the Registry that should be
23387 * populated in the data object (if applicable):
23389 Value Description<br />
23390 --------- ------------------------------------------<br />
23391 handles Array of DOM nodes that trigger dragging<br />
23392 for the element being registered<br />
23393 isHandle True if the element passed in triggers<br />
23394 dragging itself, else false
23397 register : function(el, data){
23399 if(typeof el == "string"){
23400 el = document.getElementById(el);
23403 elements[getId(el)] = data;
23404 if(data.isHandle !== false){
23405 handles[data.ddel.id] = data;
23408 var hs = data.handles;
23409 for(var i = 0, len = hs.length; i < len; i++){
23410 handles[getId(hs[i])] = data;
23416 * Unregister a drag drop element
23417 * @param {String|HTMLElement} element The id or DOM node to unregister
23419 unregister : function(el){
23420 var id = getId(el, false);
23421 var data = elements[id];
23423 delete elements[id];
23425 var hs = data.handles;
23426 for(var i = 0, len = hs.length; i < len; i++){
23427 delete handles[getId(hs[i], false)];
23434 * Returns the handle registered for a DOM Node by id
23435 * @param {String|HTMLElement} id The DOM node or id to look up
23436 * @return {Object} handle The custom handle data
23438 getHandle : function(id){
23439 if(typeof id != "string"){ // must be element?
23442 return handles[id];
23446 * Returns the handle that is registered for the DOM node that is the target of the event
23447 * @param {Event} e The event
23448 * @return {Object} handle The custom handle data
23450 getHandleFromEvent : function(e){
23451 var t = Roo.lib.Event.getTarget(e);
23452 return t ? handles[t.id] : null;
23456 * Returns a custom data object that is registered for a DOM node by id
23457 * @param {String|HTMLElement} id The DOM node or id to look up
23458 * @return {Object} data The custom data
23460 getTarget : function(id){
23461 if(typeof id != "string"){ // must be element?
23464 return elements[id];
23468 * Returns a custom data object that is registered for the DOM node that is the target of the event
23469 * @param {Event} e The event
23470 * @return {Object} data The custom data
23472 getTargetFromEvent : function(e){
23473 var t = Roo.lib.Event.getTarget(e);
23474 return t ? elements[t.id] || handles[t.id] : null;
23479 * Ext JS Library 1.1.1
23480 * Copyright(c) 2006-2007, Ext JS, LLC.
23482 * Originally Released Under LGPL - original licence link has changed is not relivant.
23485 * <script type="text/javascript">
23490 * @class Roo.dd.StatusProxy
23491 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
23492 * default drag proxy used by all Roo.dd components.
23494 * @param {Object} config
23496 Roo.dd.StatusProxy = function(config){
23497 Roo.apply(this, config);
23498 this.id = this.id || Roo.id();
23499 this.el = new Roo.Layer({
23501 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
23502 {tag: "div", cls: "x-dd-drop-icon"},
23503 {tag: "div", cls: "x-dd-drag-ghost"}
23506 shadow: !config || config.shadow !== false
23508 this.ghost = Roo.get(this.el.dom.childNodes[1]);
23509 this.dropStatus = this.dropNotAllowed;
23512 Roo.dd.StatusProxy.prototype = {
23514 * @cfg {String} dropAllowed
23515 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
23517 dropAllowed : "x-dd-drop-ok",
23519 * @cfg {String} dropNotAllowed
23520 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
23522 dropNotAllowed : "x-dd-drop-nodrop",
23525 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
23526 * over the current target element.
23527 * @param {String} cssClass The css class for the new drop status indicator image
23529 setStatus : function(cssClass){
23530 cssClass = cssClass || this.dropNotAllowed;
23531 if(this.dropStatus != cssClass){
23532 this.el.replaceClass(this.dropStatus, cssClass);
23533 this.dropStatus = cssClass;
23538 * Resets the status indicator to the default dropNotAllowed value
23539 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
23541 reset : function(clearGhost){
23542 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
23543 this.dropStatus = this.dropNotAllowed;
23545 this.ghost.update("");
23550 * Updates the contents of the ghost element
23551 * @param {String} html The html that will replace the current innerHTML of the ghost element
23553 update : function(html){
23554 if(typeof html == "string"){
23555 this.ghost.update(html);
23557 this.ghost.update("");
23558 html.style.margin = "0";
23559 this.ghost.dom.appendChild(html);
23561 // ensure float = none set?? cant remember why though.
23562 var el = this.ghost.dom.firstChild;
23564 Roo.fly(el).setStyle('float', 'none');
23569 * Returns the underlying proxy {@link Roo.Layer}
23570 * @return {Roo.Layer} el
23572 getEl : function(){
23577 * Returns the ghost element
23578 * @return {Roo.Element} el
23580 getGhost : function(){
23586 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
23588 hide : function(clear){
23596 * Stops the repair animation if it's currently running
23599 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
23605 * Displays this proxy
23612 * Force the Layer to sync its shadow and shim positions to the element
23619 * Causes the proxy to return to its position of origin via an animation. Should be called after an
23620 * invalid drop operation by the item being dragged.
23621 * @param {Array} xy The XY position of the element ([x, y])
23622 * @param {Function} callback The function to call after the repair is complete
23623 * @param {Object} scope The scope in which to execute the callback
23625 repair : function(xy, callback, scope){
23626 this.callback = callback;
23627 this.scope = scope;
23628 if(xy && this.animRepair !== false){
23629 this.el.addClass("x-dd-drag-repair");
23630 this.el.hideUnders(true);
23631 this.anim = this.el.shift({
23632 duration: this.repairDuration || .5,
23636 callback: this.afterRepair,
23640 this.afterRepair();
23645 afterRepair : function(){
23647 if(typeof this.callback == "function"){
23648 this.callback.call(this.scope || this);
23650 this.callback = null;
23655 * Ext JS Library 1.1.1
23656 * Copyright(c) 2006-2007, Ext JS, LLC.
23658 * Originally Released Under LGPL - original licence link has changed is not relivant.
23661 * <script type="text/javascript">
23665 * @class Roo.dd.DragSource
23666 * @extends Roo.dd.DDProxy
23667 * A simple class that provides the basic implementation needed to make any element draggable.
23669 * @param {String/HTMLElement/Element} el The container element
23670 * @param {Object} config
23672 Roo.dd.DragSource = function(el, config){
23673 this.el = Roo.get(el);
23674 this.dragData = {};
23676 Roo.apply(this, config);
23679 this.proxy = new Roo.dd.StatusProxy();
23682 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
23683 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
23685 this.dragging = false;
23688 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
23690 * @cfg {String} dropAllowed
23691 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23693 dropAllowed : "x-dd-drop-ok",
23695 * @cfg {String} dropNotAllowed
23696 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23698 dropNotAllowed : "x-dd-drop-nodrop",
23701 * Returns the data object associated with this drag source
23702 * @return {Object} data An object containing arbitrary data
23704 getDragData : function(e){
23705 return this.dragData;
23709 onDragEnter : function(e, id){
23710 var target = Roo.dd.DragDropMgr.getDDById(id);
23711 this.cachedTarget = target;
23712 if(this.beforeDragEnter(target, e, id) !== false){
23713 if(target.isNotifyTarget){
23714 var status = target.notifyEnter(this, e, this.dragData);
23715 this.proxy.setStatus(status);
23717 this.proxy.setStatus(this.dropAllowed);
23720 if(this.afterDragEnter){
23722 * An empty function by default, but provided so that you can perform a custom action
23723 * when the dragged item enters the drop target by providing an implementation.
23724 * @param {Roo.dd.DragDrop} target The drop target
23725 * @param {Event} e The event object
23726 * @param {String} id The id of the dragged element
23727 * @method afterDragEnter
23729 this.afterDragEnter(target, e, id);
23735 * An empty function by default, but provided so that you can perform a custom action
23736 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
23737 * @param {Roo.dd.DragDrop} target The drop target
23738 * @param {Event} e The event object
23739 * @param {String} id The id of the dragged element
23740 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23742 beforeDragEnter : function(target, e, id){
23747 alignElWithMouse: function() {
23748 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
23753 onDragOver : function(e, id){
23754 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23755 if(this.beforeDragOver(target, e, id) !== false){
23756 if(target.isNotifyTarget){
23757 var status = target.notifyOver(this, e, this.dragData);
23758 this.proxy.setStatus(status);
23761 if(this.afterDragOver){
23763 * An empty function by default, but provided so that you can perform a custom action
23764 * while the dragged item is over the drop target by providing an implementation.
23765 * @param {Roo.dd.DragDrop} target The drop target
23766 * @param {Event} e The event object
23767 * @param {String} id The id of the dragged element
23768 * @method afterDragOver
23770 this.afterDragOver(target, e, id);
23776 * An empty function by default, but provided so that you can perform a custom action
23777 * while the dragged item is over the drop target and optionally cancel the onDragOver.
23778 * @param {Roo.dd.DragDrop} target The drop target
23779 * @param {Event} e The event object
23780 * @param {String} id The id of the dragged element
23781 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23783 beforeDragOver : function(target, e, id){
23788 onDragOut : function(e, id){
23789 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23790 if(this.beforeDragOut(target, e, id) !== false){
23791 if(target.isNotifyTarget){
23792 target.notifyOut(this, e, this.dragData);
23794 this.proxy.reset();
23795 if(this.afterDragOut){
23797 * An empty function by default, but provided so that you can perform a custom action
23798 * after the dragged item is dragged out of the target without dropping.
23799 * @param {Roo.dd.DragDrop} target The drop target
23800 * @param {Event} e The event object
23801 * @param {String} id The id of the dragged element
23802 * @method afterDragOut
23804 this.afterDragOut(target, e, id);
23807 this.cachedTarget = null;
23811 * An empty function by default, but provided so that you can perform a custom action before the dragged
23812 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
23813 * @param {Roo.dd.DragDrop} target The drop target
23814 * @param {Event} e The event object
23815 * @param {String} id The id of the dragged element
23816 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23818 beforeDragOut : function(target, e, id){
23823 onDragDrop : function(e, id){
23824 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23825 if(this.beforeDragDrop(target, e, id) !== false){
23826 if(target.isNotifyTarget){
23827 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
23828 this.onValidDrop(target, e, id);
23830 this.onInvalidDrop(target, e, id);
23833 this.onValidDrop(target, e, id);
23836 if(this.afterDragDrop){
23838 * An empty function by default, but provided so that you can perform a custom action
23839 * after a valid drag drop has occurred by providing an implementation.
23840 * @param {Roo.dd.DragDrop} target The drop target
23841 * @param {Event} e The event object
23842 * @param {String} id The id of the dropped element
23843 * @method afterDragDrop
23845 this.afterDragDrop(target, e, id);
23848 delete this.cachedTarget;
23852 * An empty function by default, but provided so that you can perform a custom action before the dragged
23853 * item is dropped onto the target and optionally cancel the onDragDrop.
23854 * @param {Roo.dd.DragDrop} target The drop target
23855 * @param {Event} e The event object
23856 * @param {String} id The id of the dragged element
23857 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
23859 beforeDragDrop : function(target, e, id){
23864 onValidDrop : function(target, e, id){
23866 if(this.afterValidDrop){
23868 * An empty function by default, but provided so that you can perform a custom action
23869 * after a valid drop has occurred by providing an implementation.
23870 * @param {Object} target The target DD
23871 * @param {Event} e The event object
23872 * @param {String} id The id of the dropped element
23873 * @method afterInvalidDrop
23875 this.afterValidDrop(target, e, id);
23880 getRepairXY : function(e, data){
23881 return this.el.getXY();
23885 onInvalidDrop : function(target, e, id){
23886 this.beforeInvalidDrop(target, e, id);
23887 if(this.cachedTarget){
23888 if(this.cachedTarget.isNotifyTarget){
23889 this.cachedTarget.notifyOut(this, e, this.dragData);
23891 this.cacheTarget = null;
23893 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
23895 if(this.afterInvalidDrop){
23897 * An empty function by default, but provided so that you can perform a custom action
23898 * after an invalid drop has occurred by providing an implementation.
23899 * @param {Event} e The event object
23900 * @param {String} id The id of the dropped element
23901 * @method afterInvalidDrop
23903 this.afterInvalidDrop(e, id);
23908 afterRepair : function(){
23910 this.el.highlight(this.hlColor || "c3daf9");
23912 this.dragging = false;
23916 * An empty function by default, but provided so that you can perform a custom action after an invalid
23917 * drop has occurred.
23918 * @param {Roo.dd.DragDrop} target The drop target
23919 * @param {Event} e The event object
23920 * @param {String} id The id of the dragged element
23921 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
23923 beforeInvalidDrop : function(target, e, id){
23928 handleMouseDown : function(e){
23929 if(this.dragging) {
23932 var data = this.getDragData(e);
23933 if(data && this.onBeforeDrag(data, e) !== false){
23934 this.dragData = data;
23936 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
23941 * An empty function by default, but provided so that you can perform a custom action before the initial
23942 * drag event begins and optionally cancel it.
23943 * @param {Object} data An object containing arbitrary data to be shared with drop targets
23944 * @param {Event} e The event object
23945 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23947 onBeforeDrag : function(data, e){
23952 * An empty function by default, but provided so that you can perform a custom action once the initial
23953 * drag event has begun. The drag cannot be canceled from this function.
23954 * @param {Number} x The x position of the click on the dragged object
23955 * @param {Number} y The y position of the click on the dragged object
23957 onStartDrag : Roo.emptyFn,
23959 // private - YUI override
23960 startDrag : function(x, y){
23961 this.proxy.reset();
23962 this.dragging = true;
23963 this.proxy.update("");
23964 this.onInitDrag(x, y);
23969 onInitDrag : function(x, y){
23970 var clone = this.el.dom.cloneNode(true);
23971 clone.id = Roo.id(); // prevent duplicate ids
23972 this.proxy.update(clone);
23973 this.onStartDrag(x, y);
23978 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
23979 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
23981 getProxy : function(){
23986 * Hides the drag source's {@link Roo.dd.StatusProxy}
23988 hideProxy : function(){
23990 this.proxy.reset(true);
23991 this.dragging = false;
23995 triggerCacheRefresh : function(){
23996 Roo.dd.DDM.refreshCache(this.groups);
23999 // private - override to prevent hiding
24000 b4EndDrag: function(e) {
24003 // private - override to prevent moving
24004 endDrag : function(e){
24005 this.onEndDrag(this.dragData, e);
24009 onEndDrag : function(data, e){
24012 // private - pin to cursor
24013 autoOffset : function(x, y) {
24014 this.setDelta(-12, -20);
24018 * Ext JS Library 1.1.1
24019 * Copyright(c) 2006-2007, Ext JS, LLC.
24021 * Originally Released Under LGPL - original licence link has changed is not relivant.
24024 * <script type="text/javascript">
24029 * @class Roo.dd.DropTarget
24030 * @extends Roo.dd.DDTarget
24031 * A simple class that provides the basic implementation needed to make any element a drop target that can have
24032 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
24034 * @param {String/HTMLElement/Element} el The container element
24035 * @param {Object} config
24037 Roo.dd.DropTarget = function(el, config){
24038 this.el = Roo.get(el);
24040 var listeners = false; ;
24041 if (config && config.listeners) {
24042 listeners= config.listeners;
24043 delete config.listeners;
24045 Roo.apply(this, config);
24047 if(this.containerScroll){
24048 Roo.dd.ScrollManager.register(this.el);
24052 * @scope Roo.dd.DropTarget
24057 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
24058 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
24059 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
24061 * IMPORTANT : it should set this.valid to true|false
24063 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24064 * @param {Event} e The event
24065 * @param {Object} data An object containing arbitrary data supplied by the drag source
24071 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
24072 * This method will be called on every mouse movement while the drag source is over the drop target.
24073 * This default implementation simply returns the dropAllowed config value.
24075 * IMPORTANT : it should set this.valid to true|false
24077 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24078 * @param {Event} e The event
24079 * @param {Object} data An object containing arbitrary data supplied by the drag source
24085 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
24086 * out of the target without dropping. This default implementation simply removes the CSS class specified by
24087 * overClass (if any) from the drop element.
24090 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24091 * @param {Event} e The event
24092 * @param {Object} data An object containing arbitrary data supplied by the drag source
24098 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
24099 * been dropped on it. This method has no default implementation and returns false, so you must provide an
24100 * implementation that does something to process the drop event and returns true so that the drag source's
24101 * repair action does not run.
24103 * IMPORTANT : it should set this.success
24105 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24106 * @param {Event} e The event
24107 * @param {Object} data An object containing arbitrary data supplied by the drag source
24113 Roo.dd.DropTarget.superclass.constructor.call( this,
24115 this.ddGroup || this.group,
24118 listeners : listeners || {}
24126 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
24128 * @cfg {String} overClass
24129 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
24132 * @cfg {String} ddGroup
24133 * The drag drop group to handle drop events for
24137 * @cfg {String} dropAllowed
24138 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
24140 dropAllowed : "x-dd-drop-ok",
24142 * @cfg {String} dropNotAllowed
24143 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
24145 dropNotAllowed : "x-dd-drop-nodrop",
24147 * @cfg {boolean} success
24148 * set this after drop listener..
24152 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
24153 * if the drop point is valid for over/enter..
24160 isNotifyTarget : true,
24165 notifyEnter : function(dd, e, data)
24168 this.fireEvent('enter', dd, e, data);
24169 if(this.overClass){
24170 this.el.addClass(this.overClass);
24172 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
24173 this.valid ? this.dropAllowed : this.dropNotAllowed
24180 notifyOver : function(dd, e, data)
24183 this.fireEvent('over', dd, e, data);
24184 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
24185 this.valid ? this.dropAllowed : this.dropNotAllowed
24192 notifyOut : function(dd, e, data)
24194 this.fireEvent('out', dd, e, data);
24195 if(this.overClass){
24196 this.el.removeClass(this.overClass);
24203 notifyDrop : function(dd, e, data)
24205 this.success = false;
24206 this.fireEvent('drop', dd, e, data);
24207 return this.success;
24211 * Ext JS Library 1.1.1
24212 * Copyright(c) 2006-2007, Ext JS, LLC.
24214 * Originally Released Under LGPL - original licence link has changed is not relivant.
24217 * <script type="text/javascript">
24222 * @class Roo.dd.DragZone
24223 * @extends Roo.dd.DragSource
24224 * This class provides a container DD instance that proxies for multiple child node sources.<br />
24225 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
24227 * @param {String/HTMLElement/Element} el The container element
24228 * @param {Object} config
24230 Roo.dd.DragZone = function(el, config){
24231 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
24232 if(this.containerScroll){
24233 Roo.dd.ScrollManager.register(this.el);
24237 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
24239 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
24240 * for auto scrolling during drag operations.
24243 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
24244 * method after a failed drop (defaults to "c3daf9" - light blue)
24248 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
24249 * for a valid target to drag based on the mouse down. Override this method
24250 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
24251 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
24252 * @param {EventObject} e The mouse down event
24253 * @return {Object} The dragData
24255 getDragData : function(e){
24256 return Roo.dd.Registry.getHandleFromEvent(e);
24260 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
24261 * this.dragData.ddel
24262 * @param {Number} x The x position of the click on the dragged object
24263 * @param {Number} y The y position of the click on the dragged object
24264 * @return {Boolean} true to continue the drag, false to cancel
24266 onInitDrag : function(x, y){
24267 this.proxy.update(this.dragData.ddel.cloneNode(true));
24268 this.onStartDrag(x, y);
24273 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
24275 afterRepair : function(){
24277 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
24279 this.dragging = false;
24283 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
24284 * the XY of this.dragData.ddel
24285 * @param {EventObject} e The mouse up event
24286 * @return {Array} The xy location (e.g. [100, 200])
24288 getRepairXY : function(e){
24289 return Roo.Element.fly(this.dragData.ddel).getXY();
24293 * Ext JS Library 1.1.1
24294 * Copyright(c) 2006-2007, Ext JS, LLC.
24296 * Originally Released Under LGPL - original licence link has changed is not relivant.
24299 * <script type="text/javascript">
24302 * @class Roo.dd.DropZone
24303 * @extends Roo.dd.DropTarget
24304 * This class provides a container DD instance that proxies for multiple child node targets.<br />
24305 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
24307 * @param {String/HTMLElement/Element} el The container element
24308 * @param {Object} config
24310 Roo.dd.DropZone = function(el, config){
24311 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
24314 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
24316 * Returns a custom data object associated with the DOM node that is the target of the event. By default
24317 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
24318 * provide your own custom lookup.
24319 * @param {Event} e The event
24320 * @return {Object} data The custom data
24322 getTargetFromEvent : function(e){
24323 return Roo.dd.Registry.getTargetFromEvent(e);
24327 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
24328 * that it has registered. This method has no default implementation and should be overridden to provide
24329 * node-specific processing if necessary.
24330 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24331 * {@link #getTargetFromEvent} for this node)
24332 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24333 * @param {Event} e The event
24334 * @param {Object} data An object containing arbitrary data supplied by the drag source
24336 onNodeEnter : function(n, dd, e, data){
24341 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
24342 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
24343 * overridden to provide the proper feedback.
24344 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24345 * {@link #getTargetFromEvent} for this node)
24346 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24347 * @param {Event} e The event
24348 * @param {Object} data An object containing arbitrary data supplied by the drag source
24349 * @return {String} status The CSS class that communicates the drop status back to the source so that the
24350 * underlying {@link Roo.dd.StatusProxy} can be updated
24352 onNodeOver : function(n, dd, e, data){
24353 return this.dropAllowed;
24357 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
24358 * the drop node without dropping. This method has no default implementation and should be overridden to provide
24359 * node-specific processing if necessary.
24360 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24361 * {@link #getTargetFromEvent} for this node)
24362 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24363 * @param {Event} e The event
24364 * @param {Object} data An object containing arbitrary data supplied by the drag source
24366 onNodeOut : function(n, dd, e, data){
24371 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
24372 * the drop node. The default implementation returns false, so it should be overridden to provide the
24373 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
24374 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24375 * {@link #getTargetFromEvent} for this node)
24376 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24377 * @param {Event} e The event
24378 * @param {Object} data An object containing arbitrary data supplied by the drag source
24379 * @return {Boolean} True if the drop was valid, else false
24381 onNodeDrop : function(n, dd, e, data){
24386 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
24387 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
24388 * it should be overridden to provide the proper feedback if necessary.
24389 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24390 * @param {Event} e The event
24391 * @param {Object} data An object containing arbitrary data supplied by the drag source
24392 * @return {String} status The CSS class that communicates the drop status back to the source so that the
24393 * underlying {@link Roo.dd.StatusProxy} can be updated
24395 onContainerOver : function(dd, e, data){
24396 return this.dropNotAllowed;
24400 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
24401 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
24402 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
24403 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
24404 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24405 * @param {Event} e The event
24406 * @param {Object} data An object containing arbitrary data supplied by the drag source
24407 * @return {Boolean} True if the drop was valid, else false
24409 onContainerDrop : function(dd, e, data){
24414 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
24415 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
24416 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
24417 * you should override this method and provide a custom implementation.
24418 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24419 * @param {Event} e The event
24420 * @param {Object} data An object containing arbitrary data supplied by the drag source
24421 * @return {String} status The CSS class that communicates the drop status back to the source so that the
24422 * underlying {@link Roo.dd.StatusProxy} can be updated
24424 notifyEnter : function(dd, e, data){
24425 return this.dropNotAllowed;
24429 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
24430 * This method will be called on every mouse movement while the drag source is over the drop zone.
24431 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
24432 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
24433 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
24434 * registered node, it will call {@link #onContainerOver}.
24435 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24436 * @param {Event} e The event
24437 * @param {Object} data An object containing arbitrary data supplied by the drag source
24438 * @return {String} status The CSS class that communicates the drop status back to the source so that the
24439 * underlying {@link Roo.dd.StatusProxy} can be updated
24441 notifyOver : function(dd, e, data){
24442 var n = this.getTargetFromEvent(e);
24443 if(!n){ // not over valid drop target
24444 if(this.lastOverNode){
24445 this.onNodeOut(this.lastOverNode, dd, e, data);
24446 this.lastOverNode = null;
24448 return this.onContainerOver(dd, e, data);
24450 if(this.lastOverNode != n){
24451 if(this.lastOverNode){
24452 this.onNodeOut(this.lastOverNode, dd, e, data);
24454 this.onNodeEnter(n, dd, e, data);
24455 this.lastOverNode = n;
24457 return this.onNodeOver(n, dd, e, data);
24461 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
24462 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
24463 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
24464 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24465 * @param {Event} e The event
24466 * @param {Object} data An object containing arbitrary data supplied by the drag zone
24468 notifyOut : function(dd, e, data){
24469 if(this.lastOverNode){
24470 this.onNodeOut(this.lastOverNode, dd, e, data);
24471 this.lastOverNode = null;
24476 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
24477 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
24478 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
24479 * otherwise it will call {@link #onContainerDrop}.
24480 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24481 * @param {Event} e The event
24482 * @param {Object} data An object containing arbitrary data supplied by the drag source
24483 * @return {Boolean} True if the drop was valid, else false
24485 notifyDrop : function(dd, e, data){
24486 if(this.lastOverNode){
24487 this.onNodeOut(this.lastOverNode, dd, e, data);
24488 this.lastOverNode = null;
24490 var n = this.getTargetFromEvent(e);
24492 this.onNodeDrop(n, dd, e, data) :
24493 this.onContainerDrop(dd, e, data);
24497 triggerCacheRefresh : function(){
24498 Roo.dd.DDM.refreshCache(this.groups);