4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isFirefox = ua.indexOf("firefox") > -1,
57 isIE = ua.indexOf("msie") > -1,
58 isIE7 = ua.indexOf("msie 7") > -1,
59 isIE11 = /trident.*rv\:11\./.test(ua),
60 isEdge = ua.indexOf("edge") > -1,
61 isGecko = !isSafari && ua.indexOf("gecko") > -1,
62 isBorderBox = isIE && !isStrict,
63 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
64 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
65 isLinux = (ua.indexOf("linux") != -1),
66 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
67 isIOS = /iphone|ipad/.test(ua),
68 isAndroid = /android/.test(ua),
69 isTouch = (function() {
71 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
72 window.addEventListener('touchstart', function __set_has_touch__ () {
74 window.removeEventListener('touchstart', __set_has_touch__);
76 return false; // no touch on chrome!?
78 document.createEvent("TouchEvent");
85 // remove css image flicker
88 document.execCommand("BackgroundImageCache", false, true);
94 * True if the browser is in strict mode
99 * True if the page is running over SSL
104 * True when the document is fully initialized and ready for action
109 * Turn on debugging output (currently only the factory uses this)
116 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
119 enableGarbageCollector : true,
122 * True to automatically purge event listeners after uncaching an element (defaults to false).
123 * Note: this only happens if enableGarbageCollector is true.
126 enableListenerCollection:false,
129 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
130 * the IE insecure content warning (defaults to javascript:false).
133 SSL_SECURE_URL : "javascript:false",
136 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
137 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
140 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
142 emptyFn : function(){},
145 * Copies all the properties of config to obj if they don't already exist.
146 * @param {Object} obj The receiver of the properties
147 * @param {Object} config The source of the properties
148 * @return {Object} returns obj
150 applyIf : function(o, c){
153 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
160 * Applies event listeners to elements by selectors when the document is ready.
161 * The event name is specified with an @ suffix.
164 // add a listener for click on all anchors in element with id foo
165 '#foo a@click' : function(e, t){
169 // add the same listener to multiple selectors (separated by comma BEFORE the @)
170 '#foo a, #bar span.some-class@mouseover' : function(){
175 * @param {Object} obj The list of behaviors to apply
177 addBehaviors : function(o){
179 Roo.onReady(function(){
184 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
186 var parts = b.split('@');
187 if(parts[1]){ // for Object prototype breakers
190 cache[s] = Roo.select(s);
192 cache[s].on(parts[1], o[b]);
199 * Generates unique ids. If the element already has an id, it is unchanged
200 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
201 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
202 * @return {String} The generated Id.
204 id : function(el, prefix){
205 prefix = prefix || "roo-gen";
207 var id = prefix + (++idSeed);
208 return el ? (el.id ? el.id : (el.id = id)) : id;
213 * Extends one class with another class and optionally overrides members with the passed literal. This class
214 * also adds the function "override()" to the class that can be used to override
215 * members on an instance.
216 * @param {Object} subclass The class inheriting the functionality
217 * @param {Object} superclass The class being extended
218 * @param {Object} overrides (optional) A literal with members
223 var io = function(o){
228 return function(sb, sp, overrides){
229 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
232 sb = function(){sp.apply(this, arguments);};
234 var F = function(){}, sbp, spp = sp.prototype;
236 sbp = sb.prototype = new F();
240 if(spp.constructor == Object.prototype.constructor){
245 sb.override = function(o){
249 Roo.override(sb, overrides);
255 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
257 Roo.override(MyClass, {
258 newMethod1: function(){
261 newMethod2: function(foo){
266 * @param {Object} origclass The class to override
267 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
268 * containing one or more methods.
271 override : function(origclass, overrides){
273 var p = origclass.prototype;
274 for(var method in overrides){
275 p[method] = overrides[method];
280 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
282 Roo.namespace('Company', 'Company.data');
283 Company.Widget = function() { ... }
284 Company.data.CustomStore = function(config) { ... }
286 * @param {String} namespace1
287 * @param {String} namespace2
288 * @param {String} etc
291 namespace : function(){
292 var a=arguments, o=null, i, j, d, rt;
293 for (i=0; i<a.length; ++i) {
297 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
298 for (j=1; j<d.length; ++j) {
299 o[d[j]]=o[d[j]] || {};
305 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
307 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
308 Roo.factory(conf, Roo.data);
310 * @param {String} classname
311 * @param {String} namespace (optional)
315 factory : function(c, ns)
317 // no xtype, no ns or c.xns - or forced off by c.xns
318 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
321 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
322 if (c.constructor == ns[c.xtype]) {// already created...
326 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
327 var ret = new ns[c.xtype](c);
331 c.xns = false; // prevent recursion..
335 * Logs to console if it can.
337 * @param {String|Object} string
342 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
349 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
353 urlEncode : function(o){
359 var ov = o[key], k = Roo.encodeURIComponent(key);
360 var type = typeof ov;
361 if(type == 'undefined'){
363 }else if(type != "function" && type != "object"){
364 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
365 }else if(ov instanceof Array){
367 for(var i = 0, len = ov.length; i < len; i++) {
368 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
379 * Safe version of encodeURIComponent
380 * @param {String} data
384 encodeURIComponent : function (data)
387 return encodeURIComponent(data);
388 } catch(e) {} // should be an uri encode error.
390 if (data == '' || data == null){
393 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
394 function nibble_to_hex(nibble){
395 var chars = '0123456789ABCDEF';
396 return chars.charAt(nibble);
398 data = data.toString();
400 for(var i=0; i<data.length; i++){
401 var c = data.charCodeAt(i);
402 var bs = new Array();
405 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
406 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
407 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
408 bs[3] = 0x80 | (c & 0x3F);
409 }else if (c > 0x800){
411 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
412 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
413 bs[2] = 0x80 | (c & 0x3F);
416 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
417 bs[1] = 0x80 | (c & 0x3F);
422 for(var j=0; j<bs.length; j++){
424 var hex = nibble_to_hex((b & 0xF0) >>> 4)
425 + nibble_to_hex(b &0x0F);
434 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
435 * @param {String} string
436 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
437 * @return {Object} A literal with members
439 urlDecode : function(string, overwrite){
440 if(!string || !string.length){
444 var pairs = string.split('&');
445 var pair, name, value;
446 for(var i = 0, len = pairs.length; i < len; i++){
447 pair = pairs[i].split('=');
448 name = decodeURIComponent(pair[0]);
449 value = decodeURIComponent(pair[1]);
450 if(overwrite !== true){
451 if(typeof obj[name] == "undefined"){
453 }else if(typeof obj[name] == "string"){
454 obj[name] = [obj[name]];
455 obj[name].push(value);
457 obj[name].push(value);
467 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
468 * passed array is not really an array, your function is called once with it.
469 * The supplied function is called with (Object item, Number index, Array allItems).
470 * @param {Array/NodeList/Mixed} array
471 * @param {Function} fn
472 * @param {Object} scope
474 each : function(array, fn, scope){
475 if(typeof array.length == "undefined" || typeof array == "string"){
478 for(var i = 0, len = array.length; i < len; i++){
479 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
484 combine : function(){
485 var as = arguments, l = as.length, r = [];
486 for(var i = 0; i < l; i++){
488 if(a instanceof Array){
490 }else if(a.length !== undefined && !a.substr){
491 r = r.concat(Array.prototype.slice.call(a, 0));
500 * Escapes the passed string for use in a regular expression
501 * @param {String} str
504 escapeRe : function(s) {
505 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
509 callback : function(cb, scope, args, delay){
510 if(typeof cb == "function"){
512 cb.defer(delay, scope, args || []);
514 cb.apply(scope, args || []);
520 * Return the dom node for the passed string (id), dom node, or Roo.Element
521 * @param {String/HTMLElement/Roo.Element} el
522 * @return HTMLElement
524 getDom : function(el){
528 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
532 * Shorthand for {@link Roo.ComponentMgr#get}
534 * @return Roo.Component
536 getCmp : function(id){
537 return Roo.ComponentMgr.get(id);
540 num : function(v, defaultValue){
541 if(typeof v != 'number'){
547 destroy : function(){
548 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
552 as.removeAllListeners();
556 if(typeof as.purgeListeners == 'function'){
559 if(typeof as.destroy == 'function'){
566 // inpired by a similar function in mootools library
568 * Returns the type of object that is passed in. If the object passed in is null or undefined it
569 * return false otherwise it returns one of the following values:<ul>
570 * <li><b>string</b>: If the object passed is a string</li>
571 * <li><b>number</b>: If the object passed is a number</li>
572 * <li><b>boolean</b>: If the object passed is a boolean value</li>
573 * <li><b>function</b>: If the object passed is a function reference</li>
574 * <li><b>object</b>: If the object passed is an object</li>
575 * <li><b>array</b>: If the object passed is an array</li>
576 * <li><b>regexp</b>: If the object passed is a regular expression</li>
577 * <li><b>element</b>: If the object passed is a DOM Element</li>
578 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
579 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
580 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
581 * @param {Mixed} object
585 if(o === undefined || o === null){
592 if(t == 'object' && o.nodeName) {
594 case 1: return 'element';
595 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
598 if(t == 'object' || t == 'function') {
599 switch(o.constructor) {
600 case Array: return 'array';
601 case RegExp: return 'regexp';
603 if(typeof o.length == 'number' && typeof o.item == 'function') {
611 * Returns true if the passed value is null, undefined or an empty string (optional).
612 * @param {Mixed} value The value to test
613 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
616 isEmpty : function(v, allowBlank){
617 return v === null || v === undefined || (!allowBlank ? v === '' : false);
625 isFirefox : isFirefox,
637 isBorderBox : isBorderBox,
639 isWindows : isWindows,
647 isAndroid : isAndroid,
652 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
653 * you may want to set this to true.
656 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
661 * Selects a single element as a Roo Element
662 * This is about as close as you can get to jQuery's $('do crazy stuff')
663 * @param {String} selector The selector/xpath query
664 * @param {Node} root (optional) The start of the query (defaults to document).
665 * @return {Roo.Element}
667 selectNode : function(selector, root)
669 var node = Roo.DomQuery.selectNode(selector,root);
670 return node ? Roo.get(node) : new Roo.Element(false);
673 * Find the current bootstrap width Grid size
674 * Note xs is the default for smaller.. - this is currently used by grids to render correct columns
675 * @returns {String} (xs|sm|md|lg|xl)
678 getGridSize : function()
680 var w = Roo.lib.Dom.getViewWidth();
701 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
702 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
707 * Ext JS Library 1.1.1
708 * Copyright(c) 2006-2007, Ext JS, LLC.
710 * Originally Released Under LGPL - original licence link has changed is not relivant.
713 * <script type="text/javascript">
717 // wrappedn so fnCleanup is not in global scope...
719 function fnCleanUp() {
720 var p = Function.prototype;
721 delete p.createSequence;
723 delete p.createDelegate;
724 delete p.createCallback;
725 delete p.createInterceptor;
727 window.detachEvent("onunload", fnCleanUp);
729 window.attachEvent("onunload", fnCleanUp);
736 * These functions are available on every Function object (any JavaScript function).
738 Roo.apply(Function.prototype, {
740 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
741 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
742 * Will create a function that is bound to those 2 args.
743 * @return {Function} The new function
745 createCallback : function(/*args...*/){
746 // make args available, in function below
747 var args = arguments;
750 return method.apply(window, args);
755 * Creates a delegate (callback) that sets the scope to obj.
756 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
757 * Will create a function that is automatically scoped to this.
758 * @param {Object} obj (optional) The object for which the scope is set
759 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
760 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
761 * if a number the args are inserted at the specified position
762 * @return {Function} The new function
764 createDelegate : function(obj, args, appendArgs){
767 var callArgs = args || arguments;
768 if(appendArgs === true){
769 callArgs = Array.prototype.slice.call(arguments, 0);
770 callArgs = callArgs.concat(args);
771 }else if(typeof appendArgs == "number"){
772 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
773 var applyArgs = [appendArgs, 0].concat(args); // create method call params
774 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
776 return method.apply(obj || window, callArgs);
781 * Calls this function after the number of millseconds specified.
782 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
783 * @param {Object} obj (optional) The object for which the scope is set
784 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
785 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
786 * if a number the args are inserted at the specified position
787 * @return {Number} The timeout id that can be used with clearTimeout
789 defer : function(millis, obj, args, appendArgs){
790 var fn = this.createDelegate(obj, args, appendArgs);
792 return setTimeout(fn, millis);
798 * Create a combined function call sequence of the original function + the passed function.
799 * The resulting function returns the results of the original function.
800 * The passed fcn is called with the parameters of the original function
801 * @param {Function} fcn The function to sequence
802 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
803 * @return {Function} The new function
805 createSequence : function(fcn, scope){
806 if(typeof fcn != "function"){
811 var retval = method.apply(this || window, arguments);
812 fcn.apply(scope || this || window, arguments);
818 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
819 * The resulting function returns the results of the original function.
820 * The passed fcn is called with the parameters of the original function.
822 * @param {Function} fcn The function to call before the original
823 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
824 * @return {Function} The new function
826 createInterceptor : function(fcn, scope){
827 if(typeof fcn != "function"){
834 if(fcn.apply(scope || this || window, arguments) === false){
837 return method.apply(this || window, arguments);
843 * Ext JS Library 1.1.1
844 * Copyright(c) 2006-2007, Ext JS, LLC.
846 * Originally Released Under LGPL - original licence link has changed is not relivant.
849 * <script type="text/javascript">
852 Roo.applyIf(String, {
857 * Escapes the passed string for ' and \
858 * @param {String} string The string to escape
859 * @return {String} The escaped string
862 escape : function(string) {
863 return string.replace(/('|\\)/g, "\\$1");
867 * Pads the left side of a string with a specified character. This is especially useful
868 * for normalizing number and date strings. Example usage:
870 var s = String.leftPad('123', 5, '0');
871 // s now contains the string: '00123'
873 * @param {String} string The original string
874 * @param {Number} size The total length of the output string
875 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
876 * @return {String} The padded string
879 leftPad : function (val, size, ch) {
880 var result = new String(val);
881 if(ch === null || ch === undefined || ch === '') {
884 while (result.length < size) {
885 result = ch + result;
891 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
892 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
894 var cls = 'my-class', text = 'Some text';
895 var s = String.format('<div class="{0}">{1}</div>', cls, text);
896 // s now contains the string: '<div class="my-class">Some text</div>'
898 * @param {String} string The tokenized string to be formatted
899 * @param {String} value1 The value to replace token {0}
900 * @param {String} value2 Etc...
901 * @return {String} The formatted string
904 format : function(format){
905 var args = Array.prototype.slice.call(arguments, 1);
906 return format.replace(/\{(\d+)\}/g, function(m, i){
907 return Roo.util.Format.htmlEncode(args[i]);
915 * Utility function that allows you to easily switch a string between two alternating values. The passed value
916 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
917 * they are already different, the first value passed in is returned. Note that this method returns the new value
918 * but does not change the current string.
920 // alternate sort directions
921 sort = sort.toggle('ASC', 'DESC');
923 // instead of conditional logic:
924 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
926 * @param {String} value The value to compare to the current string
927 * @param {String} other The new value to use if the string already equals the first value passed in
928 * @return {String} The new value
931 String.prototype.toggle = function(value, other){
932 return this == value ? other : value;
937 * Remove invalid unicode characters from a string
939 * @return {String} The clean string
941 String.prototype.unicodeClean = function () {
942 return this.replace(/[\s\S]/g,
943 function(character) {
944 if (character.charCodeAt()< 256) {
948 encodeURIComponent(character);
959 * Ext JS Library 1.1.1
960 * Copyright(c) 2006-2007, Ext JS, LLC.
962 * Originally Released Under LGPL - original licence link has changed is not relivant.
965 * <script type="text/javascript">
971 Roo.applyIf(Number.prototype, {
973 * Checks whether or not the current number is within a desired range. If the number is already within the
974 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
975 * exceeded. Note that this method returns the constrained value but does not change the current number.
976 * @param {Number} min The minimum number in the range
977 * @param {Number} max The maximum number in the range
978 * @return {Number} The constrained value if outside the range, otherwise the current value
980 constrain : function(min, max){
981 return Math.min(Math.max(this, min), max);
985 * Ext JS Library 1.1.1
986 * Copyright(c) 2006-2007, Ext JS, LLC.
988 * Originally Released Under LGPL - original licence link has changed is not relivant.
991 * <script type="text/javascript">
996 Roo.applyIf(Array.prototype, {
999 * Checks whether or not the specified object exists in the array.
1000 * @param {Object} o The object to check for
1001 * @return {Number} The index of o in the array (or -1 if it is not found)
1003 indexOf : function(o){
1004 for (var i = 0, len = this.length; i < len; i++){
1005 if(this[i] == o) { return i; }
1011 * Removes the specified object from the array. If the object is not found nothing happens.
1012 * @param {Object} o The object to remove
1014 remove : function(o){
1015 var index = this.indexOf(o);
1017 this.splice(index, 1);
1021 * Map (JS 1.6 compatibility)
1022 * @param {Function} function to call
1024 map : function(fun )
1026 var len = this.length >>> 0;
1027 if (typeof fun != "function") {
1028 throw new TypeError();
1030 var res = new Array(len);
1031 var thisp = arguments[1];
1032 for (var i = 0; i < len; i++)
1035 res[i] = fun.call(thisp, this[i], i, this);
1043 * @param {Array} o The array to compare to
1044 * @returns {Boolean} true if the same
1046 equals : function(b)
1048 // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
1055 if (this.length !== b.length) {
1059 // sort?? a.sort().equals(b.sort());
1061 for (var i = 0; i < this.length; ++i) {
1062 if (this[i] !== b[i]) {
1074 Roo.applyIf(Array, {
1078 * @param {Array} o Or Array like object (eg. nodelist)
1085 for (var i =0; i < o.length; i++) {
1094 * Ext JS Library 1.1.1
1095 * Copyright(c) 2006-2007, Ext JS, LLC.
1097 * Originally Released Under LGPL - original licence link has changed is not relivant.
1100 * <script type="text/javascript">
1106 * The date parsing and format syntax is a subset of
1107 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1108 * supported will provide results equivalent to their PHP versions.
1110 * Following is the list of all currently supported formats:
1113 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1115 Format Output Description
1116 ------ ---------- --------------------------------------------------------------
1117 d 10 Day of the month, 2 digits with leading zeros
1118 D Wed A textual representation of a day, three letters
1119 j 10 Day of the month without leading zeros
1120 l Wednesday A full textual representation of the day of the week
1121 S th English ordinal day of month suffix, 2 chars (use with j)
1122 w 3 Numeric representation of the day of the week
1123 z 9 The julian date, or day of the year (0-365)
1124 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1125 F January A full textual representation of the month
1126 m 01 Numeric representation of a month, with leading zeros
1127 M Jan Month name abbreviation, three letters
1128 n 1 Numeric representation of a month, without leading zeros
1129 t 31 Number of days in the given month
1130 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1131 Y 2007 A full numeric representation of a year, 4 digits
1132 y 07 A two digit representation of a year
1133 a pm Lowercase Ante meridiem and Post meridiem
1134 A PM Uppercase Ante meridiem and Post meridiem
1135 g 3 12-hour format of an hour without leading zeros
1136 G 15 24-hour format of an hour without leading zeros
1137 h 03 12-hour format of an hour with leading zeros
1138 H 15 24-hour format of an hour with leading zeros
1139 i 05 Minutes with leading zeros
1140 s 01 Seconds, with leading zeros
1141 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1142 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1143 T CST Timezone setting of the machine running the code
1144 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1147 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1149 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1150 document.write(dt.format('Y-m-d')); //2007-01-10
1151 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1152 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1155 * Here are some standard date/time patterns that you might find helpful. They
1156 * are not part of the source of Date.js, but to use them you can simply copy this
1157 * block of code into any script that is included after Date.js and they will also become
1158 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1161 ISO8601Long:"Y-m-d H:i:s",
1162 ISO8601Short:"Y-m-d",
1164 LongDate: "l, F d, Y",
1165 FullDateTime: "l, F d, Y g:i:s A",
1168 LongTime: "g:i:s A",
1169 SortableDateTime: "Y-m-d\\TH:i:s",
1170 UniversalSortableDateTime: "Y-m-d H:i:sO",
1177 var dt = new Date();
1178 document.write(dt.format(Date.patterns.ShortDate));
1183 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1184 * They generate precompiled functions from date formats instead of parsing and
1185 * processing the pattern every time you format a date. These functions are available
1186 * on every Date object (any javascript function).
1188 * The original article and download are here:
1189 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1196 Returns the number of milliseconds between this date and date
1197 @param {Date} date (optional) Defaults to now
1198 @return {Number} The diff in milliseconds
1199 @member Date getElapsed
1201 Date.prototype.getElapsed = function(date) {
1202 return Math.abs((date || new Date()).getTime()-this.getTime());
1204 // was in date file..
1208 Date.parseFunctions = {count:0};
1210 Date.parseRegexes = [];
1212 Date.formatFunctions = {count:0};
1215 Date.prototype.dateFormat = function(format) {
1216 if (Date.formatFunctions[format] == null) {
1217 Date.createNewFormat(format);
1219 var func = Date.formatFunctions[format];
1220 return this[func]();
1225 * Formats a date given the supplied format string
1226 * @param {String} format The format string
1227 * @return {String} The formatted date
1230 Date.prototype.format = Date.prototype.dateFormat;
1233 Date.createNewFormat = function(format) {
1234 var funcName = "format" + Date.formatFunctions.count++;
1235 Date.formatFunctions[format] = funcName;
1236 var code = "Date.prototype." + funcName + " = function(){return ";
1237 var special = false;
1239 for (var i = 0; i < format.length; ++i) {
1240 ch = format.charAt(i);
1241 if (!special && ch == "\\") {
1246 code += "'" + String.escape(ch) + "' + ";
1249 code += Date.getFormatCode(ch);
1252 /** eval:var:zzzzzzzzzzzzz */
1253 eval(code.substring(0, code.length - 3) + ";}");
1257 Date.getFormatCode = function(character) {
1258 switch (character) {
1260 return "String.leftPad(this.getDate(), 2, '0') + ";
1262 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1264 return "this.getDate() + ";
1266 return "Date.dayNames[this.getDay()] + ";
1268 return "this.getSuffix() + ";
1270 return "this.getDay() + ";
1272 return "this.getDayOfYear() + ";
1274 return "this.getWeekOfYear() + ";
1276 return "Date.monthNames[this.getMonth()] + ";
1278 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1280 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1282 return "(this.getMonth() + 1) + ";
1284 return "this.getDaysInMonth() + ";
1286 return "(this.isLeapYear() ? 1 : 0) + ";
1288 return "this.getFullYear() + ";
1290 return "('' + this.getFullYear()).substring(2, 4) + ";
1292 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1294 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1296 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1298 return "this.getHours() + ";
1300 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1302 return "String.leftPad(this.getHours(), 2, '0') + ";
1304 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1306 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1308 return "this.getGMTOffset() + ";
1310 return "this.getGMTColonOffset() + ";
1312 return "this.getTimezone() + ";
1314 return "(this.getTimezoneOffset() * -60) + ";
1316 return "'" + String.escape(character) + "' + ";
1321 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1322 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1323 * the date format that is not specified will default to the current date value for that part. Time parts can also
1324 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1325 * string or the parse operation will fail.
1328 //dt = Fri May 25 2007 (current date)
1329 var dt = new Date();
1331 //dt = Thu May 25 2006 (today's month/day in 2006)
1332 dt = Date.parseDate("2006", "Y");
1334 //dt = Sun Jan 15 2006 (all date parts specified)
1335 dt = Date.parseDate("2006-1-15", "Y-m-d");
1337 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1338 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1340 * @param {String} input The unparsed date as a string
1341 * @param {String} format The format the date is in
1342 * @return {Date} The parsed date
1345 Date.parseDate = function(input, format) {
1346 if (Date.parseFunctions[format] == null) {
1347 Date.createParser(format);
1349 var func = Date.parseFunctions[format];
1350 return Date[func](input);
1356 Date.createParser = function(format) {
1357 var funcName = "parse" + Date.parseFunctions.count++;
1358 var regexNum = Date.parseRegexes.length;
1359 var currentGroup = 1;
1360 Date.parseFunctions[format] = funcName;
1362 var code = "Date." + funcName + " = function(input){\n"
1363 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1364 + "var d = new Date();\n"
1365 + "y = d.getFullYear();\n"
1366 + "m = d.getMonth();\n"
1367 + "d = d.getDate();\n"
1368 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1369 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1370 + "if (results && results.length > 0) {";
1373 var special = false;
1375 for (var i = 0; i < format.length; ++i) {
1376 ch = format.charAt(i);
1377 if (!special && ch == "\\") {
1382 regex += String.escape(ch);
1385 var obj = Date.formatCodeToRegex(ch, currentGroup);
1386 currentGroup += obj.g;
1388 if (obj.g && obj.c) {
1394 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1395 + "{v = new Date(y, m, d, h, i, s); v.setFullYear(y);}\n"
1396 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1397 + "{v = new Date(y, m, d, h, i); v.setFullYear(y);}\n"
1398 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1399 + "{v = new Date(y, m, d, h); v.setFullYear(y);}\n"
1400 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1401 + "{v = new Date(y, m, d); v.setFullYear(y);}\n"
1402 + "else if (y >= 0 && m >= 0)\n"
1403 + "{v = new Date(y, m); v.setFullYear(y);}\n"
1404 + "else if (y >= 0)\n"
1405 + "{v = new Date(y); v.setFullYear(y);}\n"
1406 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1407 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1408 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1411 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1412 /** eval:var:zzzzzzzzzzzzz */
1417 Date.formatCodeToRegex = function(character, currentGroup) {
1418 switch (character) {
1422 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1425 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1426 s:"(\\d{1,2})"}; // day of month without leading zeroes
1429 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1430 s:"(\\d{2})"}; // day of month with leading zeroes
1434 s:"(?:" + Date.dayNames.join("|") + ")"};
1438 s:"(?:st|nd|rd|th)"};
1453 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1454 s:"(" + Date.monthNames.join("|") + ")"};
1457 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1458 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1461 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1462 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1465 c:"m = Math.max(0,parseInt(results[" + currentGroup + "], 10) - 1);\n",
1466 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1477 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1481 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1482 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1486 c:"if (results[" + currentGroup + "] == 'am') {\n"
1487 + "if (h == 12) { h = 0; }\n"
1488 + "} else { if (h < 12) { h += 12; }}",
1492 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1493 + "if (h == 12) { h = 0; }\n"
1494 + "} else { if (h < 12) { h += 12; }}",
1499 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1500 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1504 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1505 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1508 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1512 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1517 "o = results[", currentGroup, "];\n",
1518 "var sn = o.substring(0,1);\n", // get + / - sign
1519 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1520 "var mn = o.substring(3,5) % 60;\n", // get minutes
1521 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1522 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1524 s:"([+\-]\\d{2,4})"};
1530 "o = results[", currentGroup, "];\n",
1531 "var sn = o.substring(0,1);\n",
1532 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1533 "var mn = o.substring(4,6) % 60;\n",
1534 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1535 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1541 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1544 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1545 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1546 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1550 s:String.escape(character)};
1555 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1556 * @return {String} The abbreviated timezone name (e.g. 'CST')
1558 Date.prototype.getTimezone = function() {
1559 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1563 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1564 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1566 Date.prototype.getGMTOffset = function() {
1567 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1568 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1569 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1573 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1574 * @return {String} 2-characters representing hours and 2-characters representing minutes
1575 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1577 Date.prototype.getGMTColonOffset = function() {
1578 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1579 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1581 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1585 * Get the numeric day number of the year, adjusted for leap year.
1586 * @return {Number} 0 through 364 (365 in leap years)
1588 Date.prototype.getDayOfYear = function() {
1590 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1591 for (var i = 0; i < this.getMonth(); ++i) {
1592 num += Date.daysInMonth[i];
1594 return num + this.getDate() - 1;
1598 * Get the string representation of the numeric week number of the year
1599 * (equivalent to the format specifier 'W').
1600 * @return {String} '00' through '52'
1602 Date.prototype.getWeekOfYear = function() {
1603 // Skip to Thursday of this week
1604 var now = this.getDayOfYear() + (4 - this.getDay());
1605 // Find the first Thursday of the year
1606 var jan1 = new Date(this.getFullYear(), 0, 1);
1607 var then = (7 - jan1.getDay() + 4);
1608 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1612 * Whether or not the current date is in a leap year.
1613 * @return {Boolean} True if the current date is in a leap year, else false
1615 Date.prototype.isLeapYear = function() {
1616 var year = this.getFullYear();
1617 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1621 * Get the first day of the current month, adjusted for leap year. The returned value
1622 * is the numeric day index within the week (0-6) which can be used in conjunction with
1623 * the {@link #monthNames} array to retrieve the textual day name.
1626 var dt = new Date('1/10/2007');
1627 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1629 * @return {Number} The day number (0-6)
1631 Date.prototype.getFirstDayOfMonth = function() {
1632 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1633 return (day < 0) ? (day + 7) : day;
1637 * Get the last day of the current month, adjusted for leap year. The returned value
1638 * is the numeric day index within the week (0-6) which can be used in conjunction with
1639 * the {@link #monthNames} array to retrieve the textual day name.
1642 var dt = new Date('1/10/2007');
1643 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1645 * @return {Number} The day number (0-6)
1647 Date.prototype.getLastDayOfMonth = function() {
1648 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1649 return (day < 0) ? (day + 7) : day;
1654 * Get the first date of this date's month
1657 Date.prototype.getFirstDateOfMonth = function() {
1658 return new Date(this.getFullYear(), this.getMonth(), 1);
1662 * Get the last date of this date's month
1665 Date.prototype.getLastDateOfMonth = function() {
1666 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1669 * Get the number of days in the current month, adjusted for leap year.
1670 * @return {Number} The number of days in the month
1672 Date.prototype.getDaysInMonth = function() {
1673 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1674 return Date.daysInMonth[this.getMonth()];
1678 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1679 * @return {String} 'st, 'nd', 'rd' or 'th'
1681 Date.prototype.getSuffix = function() {
1682 switch (this.getDate()) {
1699 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1702 * An array of textual month names.
1703 * Override these values for international dates, for example...
1704 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1723 * An array of textual day names.
1724 * Override these values for international dates, for example...
1725 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1741 Date.monthNumbers = {
1756 * Creates and returns a new Date instance with the exact same date value as the called instance.
1757 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1758 * variable will also be changed. When the intention is to create a new variable that will not
1759 * modify the original instance, you should create a clone.
1761 * Example of correctly cloning a date:
1764 var orig = new Date('10/1/2006');
1767 document.write(orig); //returns 'Thu Oct 05 2006'!
1770 var orig = new Date('10/1/2006');
1771 var copy = orig.clone();
1773 document.write(orig); //returns 'Thu Oct 01 2006'
1775 * @return {Date} The new Date instance
1777 Date.prototype.clone = function() {
1778 return new Date(this.getTime());
1782 * Clears any time information from this date
1783 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1784 @return {Date} this or the clone
1786 Date.prototype.clearTime = function(clone){
1788 return this.clone().clearTime();
1793 this.setMilliseconds(0);
1798 // safari setMonth is broken -- check that this is only donw once...
1799 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1800 Date.brokenSetMonth = Date.prototype.setMonth;
1801 Date.prototype.setMonth = function(num){
1803 var n = Math.ceil(-num);
1804 var back_year = Math.ceil(n/12);
1805 var month = (n % 12) ? 12 - n % 12 : 0 ;
1806 this.setFullYear(this.getFullYear() - back_year);
1807 return Date.brokenSetMonth.call(this, month);
1809 return Date.brokenSetMonth.apply(this, arguments);
1814 /** Date interval constant
1818 /** Date interval constant
1822 /** Date interval constant
1826 /** Date interval constant
1830 /** Date interval constant
1834 /** Date interval constant
1838 /** Date interval constant
1844 * Provides a convenient method of performing basic date arithmetic. This method
1845 * does not modify the Date instance being called - it creates and returns
1846 * a new Date instance containing the resulting date value.
1851 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1852 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1854 //Negative values will subtract correctly:
1855 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1856 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1858 //You can even chain several calls together in one line!
1859 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1860 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1863 * @param {String} interval A valid date interval enum value
1864 * @param {Number} value The amount to add to the current date
1865 * @return {Date} The new Date instance
1867 Date.prototype.add = function(interval, value){
1868 var d = this.clone();
1869 if (!interval || value === 0) { return d; }
1870 switch(interval.toLowerCase()){
1872 d.setMilliseconds(this.getMilliseconds() + value);
1875 d.setSeconds(this.getSeconds() + value);
1878 d.setMinutes(this.getMinutes() + value);
1881 d.setHours(this.getHours() + value);
1884 d.setDate(this.getDate() + value);
1887 var day = this.getDate();
1889 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1892 d.setMonth(this.getMonth() + value);
1895 d.setFullYear(this.getFullYear() + value);
1901 * @class Roo.lib.Dom
1905 * Dom utils (from YIU afaik)
1911 * Get the view width
1912 * @param {Boolean} full True will get the full document, otherwise it's the view width
1913 * @return {Number} The width
1916 getViewWidth : function(full) {
1917 return full ? this.getDocumentWidth() : this.getViewportWidth();
1920 * Get the view height
1921 * @param {Boolean} full True will get the full document, otherwise it's the view height
1922 * @return {Number} The height
1924 getViewHeight : function(full) {
1925 return full ? this.getDocumentHeight() : this.getViewportHeight();
1928 * Get the Full Document height
1929 * @return {Number} The height
1931 getDocumentHeight: function() {
1932 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1933 return Math.max(scrollHeight, this.getViewportHeight());
1936 * Get the Full Document width
1937 * @return {Number} The width
1939 getDocumentWidth: function() {
1940 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1941 return Math.max(scrollWidth, this.getViewportWidth());
1944 * Get the Window Viewport height
1945 * @return {Number} The height
1947 getViewportHeight: function() {
1948 var height = self.innerHeight;
1949 var mode = document.compatMode;
1951 if ((mode || Roo.isIE) && !Roo.isOpera) {
1952 height = (mode == "CSS1Compat") ?
1953 document.documentElement.clientHeight :
1954 document.body.clientHeight;
1960 * Get the Window Viewport width
1961 * @return {Number} The width
1963 getViewportWidth: function() {
1964 var width = self.innerWidth;
1965 var mode = document.compatMode;
1967 if (mode || Roo.isIE) {
1968 width = (mode == "CSS1Compat") ?
1969 document.documentElement.clientWidth :
1970 document.body.clientWidth;
1975 isAncestor : function(p, c) {
1982 if (p.contains && !Roo.isSafari) {
1983 return p.contains(c);
1984 } else if (p.compareDocumentPosition) {
1985 return !!(p.compareDocumentPosition(c) & 16);
1987 var parent = c.parentNode;
1992 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1995 parent = parent.parentNode;
2001 getRegion : function(el) {
2002 return Roo.lib.Region.getRegion(el);
2005 getY : function(el) {
2006 return this.getXY(el)[1];
2009 getX : function(el) {
2010 return this.getXY(el)[0];
2013 getXY : function(el) {
2014 var p, pe, b, scroll, bd = document.body;
2015 el = Roo.getDom(el);
2016 var fly = Roo.lib.AnimBase.fly;
2017 if (el.getBoundingClientRect) {
2018 b = el.getBoundingClientRect();
2019 scroll = fly(document).getScroll();
2020 return [b.left + scroll.left, b.top + scroll.top];
2026 var hasAbsolute = fly(el).getStyle("position") == "absolute";
2033 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
2040 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
2041 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2048 if (p != el && pe.getStyle('overflow') != 'visible') {
2056 if (Roo.isSafari && hasAbsolute) {
2061 if (Roo.isGecko && !hasAbsolute) {
2063 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2064 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2068 while (p && p != bd) {
2069 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2081 setXY : function(el, xy) {
2082 el = Roo.fly(el, '_setXY');
2084 var pts = el.translatePoints(xy);
2085 if (xy[0] !== false) {
2086 el.dom.style.left = pts.left + "px";
2088 if (xy[1] !== false) {
2089 el.dom.style.top = pts.top + "px";
2093 setX : function(el, x) {
2094 this.setXY(el, [x, false]);
2097 setY : function(el, y) {
2098 this.setXY(el, [false, y]);
2102 * Portions of this file are based on pieces of Yahoo User Interface Library
2103 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2104 * YUI licensed under the BSD License:
2105 * http://developer.yahoo.net/yui/license.txt
2106 * <script type="text/javascript">
2110 Roo.lib.Event = function() {
2111 var loadComplete = false;
2113 var unloadListeners = [];
2115 var onAvailStack = [];
2117 var lastError = null;
2130 startInterval: function() {
2131 if (!this._interval) {
2133 var callback = function() {
2134 self._tryPreloadAttach();
2136 this._interval = setInterval(callback, this.POLL_INTERVAL);
2141 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2142 onAvailStack.push({ id: p_id,
2145 override: p_override,
2146 checkReady: false });
2148 retryCount = this.POLL_RETRYS;
2149 this.startInterval();
2153 addListener: function(el, eventName, fn) {
2154 el = Roo.getDom(el);
2159 if ("unload" == eventName) {
2160 unloadListeners[unloadListeners.length] =
2161 [el, eventName, fn];
2165 var wrappedFn = function(e) {
2166 return fn(Roo.lib.Event.getEvent(e));
2169 var li = [el, eventName, fn, wrappedFn];
2171 var index = listeners.length;
2172 listeners[index] = li;
2174 this.doAdd(el, eventName, wrappedFn, false);
2180 removeListener: function(el, eventName, fn) {
2183 el = Roo.getDom(el);
2186 return this.purgeElement(el, false, eventName);
2190 if ("unload" == eventName) {
2192 for (i = 0,len = unloadListeners.length; i < len; i++) {
2193 var li = unloadListeners[i];
2196 li[1] == eventName &&
2198 unloadListeners.splice(i, 1);
2206 var cacheItem = null;
2209 var index = arguments[3];
2211 if ("undefined" == typeof index) {
2212 index = this._getCacheIndex(el, eventName, fn);
2216 cacheItem = listeners[index];
2219 if (!el || !cacheItem) {
2223 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2225 delete listeners[index][this.WFN];
2226 delete listeners[index][this.FN];
2227 listeners.splice(index, 1);
2234 getTarget: function(ev, resolveTextNode) {
2235 ev = ev.browserEvent || ev;
2236 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2237 var t = ev.target || ev.srcElement;
2238 return this.resolveTextNode(t);
2242 resolveTextNode: function(node) {
2243 if (Roo.isSafari && node && 3 == node.nodeType) {
2244 return node.parentNode;
2251 getPageX: function(ev) {
2252 ev = ev.browserEvent || ev;
2253 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2255 if (!x && 0 !== x) {
2256 x = ev.clientX || 0;
2259 x += this.getScroll()[1];
2267 getPageY: function(ev) {
2268 ev = ev.browserEvent || ev;
2269 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2271 if (!y && 0 !== y) {
2272 y = ev.clientY || 0;
2275 y += this.getScroll()[0];
2284 getXY: function(ev) {
2285 ev = ev.browserEvent || ev;
2286 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2287 return [this.getPageX(ev), this.getPageY(ev)];
2291 getRelatedTarget: function(ev) {
2292 ev = ev.browserEvent || ev;
2293 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2294 var t = ev.relatedTarget;
2296 if (ev.type == "mouseout") {
2298 } else if (ev.type == "mouseover") {
2303 return this.resolveTextNode(t);
2307 getTime: function(ev) {
2308 ev = ev.browserEvent || ev;
2309 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2311 var t = new Date().getTime();
2315 this.lastError = ex;
2324 stopEvent: function(ev) {
2325 this.stopPropagation(ev);
2326 this.preventDefault(ev);
2330 stopPropagation: function(ev) {
2331 ev = ev.browserEvent || ev;
2332 if (ev.stopPropagation) {
2333 ev.stopPropagation();
2335 ev.cancelBubble = true;
2340 preventDefault: function(ev) {
2341 ev = ev.browserEvent || ev;
2342 if(ev.preventDefault) {
2343 ev.preventDefault();
2345 ev.returnValue = false;
2350 getEvent: function(e) {
2351 var ev = e || window.event;
2353 var c = this.getEvent.caller;
2355 ev = c.arguments[0];
2356 if (ev && Event == ev.constructor) {
2366 getCharCode: function(ev) {
2367 ev = ev.browserEvent || ev;
2368 return ev.charCode || ev.keyCode || 0;
2372 _getCacheIndex: function(el, eventName, fn) {
2373 for (var i = 0,len = listeners.length; i < len; ++i) {
2374 var li = listeners[i];
2376 li[this.FN] == fn &&
2377 li[this.EL] == el &&
2378 li[this.TYPE] == eventName) {
2390 getEl: function(id) {
2391 return document.getElementById(id);
2395 clearCache: function() {
2399 _load: function(e) {
2400 loadComplete = true;
2401 var EU = Roo.lib.Event;
2405 EU.doRemove(window, "load", EU._load);
2410 _tryPreloadAttach: function() {
2419 var tryAgain = !loadComplete;
2421 tryAgain = (retryCount > 0);
2426 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2427 var item = onAvailStack[i];
2429 var el = this.getEl(item.id);
2432 if (!item.checkReady ||
2435 (document && document.body)) {
2438 if (item.override) {
2439 if (item.override === true) {
2442 scope = item.override;
2445 item.fn.call(scope, item.obj);
2446 onAvailStack[i] = null;
2449 notAvail.push(item);
2454 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2458 this.startInterval();
2460 clearInterval(this._interval);
2461 this._interval = null;
2464 this.locked = false;
2471 purgeElement: function(el, recurse, eventName) {
2472 var elListeners = this.getListeners(el, eventName);
2474 for (var i = 0,len = elListeners.length; i < len; ++i) {
2475 var l = elListeners[i];
2476 this.removeListener(el, l.type, l.fn);
2480 if (recurse && el && el.childNodes) {
2481 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2482 this.purgeElement(el.childNodes[i], recurse, eventName);
2488 getListeners: function(el, eventName) {
2489 var results = [], searchLists;
2491 searchLists = [listeners, unloadListeners];
2492 } else if (eventName == "unload") {
2493 searchLists = [unloadListeners];
2495 searchLists = [listeners];
2498 for (var j = 0; j < searchLists.length; ++j) {
2499 var searchList = searchLists[j];
2500 if (searchList && searchList.length > 0) {
2501 for (var i = 0,len = searchList.length; i < len; ++i) {
2502 var l = searchList[i];
2503 if (l && l[this.EL] === el &&
2504 (!eventName || eventName === l[this.TYPE])) {
2509 adjust: l[this.ADJ_SCOPE],
2517 return (results.length) ? results : null;
2521 _unload: function(e) {
2523 var EU = Roo.lib.Event, i, j, l, len, index;
2525 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2526 l = unloadListeners[i];
2529 if (l[EU.ADJ_SCOPE]) {
2530 if (l[EU.ADJ_SCOPE] === true) {
2533 scope = l[EU.ADJ_SCOPE];
2536 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2537 unloadListeners[i] = null;
2543 unloadListeners = null;
2545 if (listeners && listeners.length > 0) {
2546 j = listeners.length;
2549 l = listeners[index];
2551 EU.removeListener(l[EU.EL], l[EU.TYPE],
2561 EU.doRemove(window, "unload", EU._unload);
2566 getScroll: function() {
2567 var dd = document.documentElement, db = document.body;
2568 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2569 return [dd.scrollTop, dd.scrollLeft];
2571 return [db.scrollTop, db.scrollLeft];
2578 doAdd: function () {
2579 if (window.addEventListener) {
2580 return function(el, eventName, fn, capture) {
2581 el.addEventListener(eventName, fn, (capture));
2583 } else if (window.attachEvent) {
2584 return function(el, eventName, fn, capture) {
2585 el.attachEvent("on" + eventName, fn);
2594 doRemove: function() {
2595 if (window.removeEventListener) {
2596 return function (el, eventName, fn, capture) {
2597 el.removeEventListener(eventName, fn, (capture));
2599 } else if (window.detachEvent) {
2600 return function (el, eventName, fn) {
2601 el.detachEvent("on" + eventName, fn);
2613 var E = Roo.lib.Event;
2614 E.on = E.addListener;
2615 E.un = E.removeListener;
2617 if (document && document.body) {
2620 E.doAdd(window, "load", E._load);
2622 E.doAdd(window, "unload", E._unload);
2623 E._tryPreloadAttach();
2630 * @class Roo.lib.Ajax
2632 * provide a simple Ajax request utility functions
2634 * Portions of this file are based on pieces of Yahoo User Interface Library
2635 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2636 * YUI licensed under the BSD License:
2637 * http://developer.yahoo.net/yui/license.txt
2638 * <script type="text/javascript">
2646 request : function(method, uri, cb, data, options) {
2648 var hs = options.headers;
2651 if(hs.hasOwnProperty(h)){
2652 this.initHeader(h, hs[h], false);
2656 if(options.xmlData){
2657 this.initHeader('Content-Type', 'text/xml', false);
2659 data = options.xmlData;
2663 return this.asyncRequest(method, uri, cb, data);
2669 * @param {DomForm} form element
2670 * @return {String} urlencode form output.
2672 serializeForm : function(form) {
2673 if(typeof form == 'string') {
2674 form = (document.getElementById(form) || document.forms[form]);
2677 var el, name, val, disabled, data = '', hasSubmit = false;
2678 for (var i = 0; i < form.elements.length; i++) {
2679 el = form.elements[i];
2680 disabled = form.elements[i].disabled;
2681 name = form.elements[i].name;
2682 val = form.elements[i].value;
2684 if (!disabled && name){
2688 case 'select-multiple':
2689 for (var j = 0; j < el.options.length; j++) {
2690 if (el.options[j].selected) {
2692 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2695 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2703 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2716 if(hasSubmit == false) {
2717 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2722 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2727 data = data.substr(0, data.length - 1);
2735 useDefaultHeader:true,
2737 defaultPostHeader:'application/x-www-form-urlencoded',
2739 useDefaultXhrHeader:true,
2741 defaultXhrHeader:'XMLHttpRequest',
2743 hasDefaultHeaders:true,
2755 setProgId:function(id)
2757 this.activeX.unshift(id);
2760 setDefaultPostHeader:function(b)
2762 this.useDefaultHeader = b;
2765 setDefaultXhrHeader:function(b)
2767 this.useDefaultXhrHeader = b;
2770 setPollingInterval:function(i)
2772 if (typeof i == 'number' && isFinite(i)) {
2773 this.pollInterval = i;
2777 createXhrObject:function(transactionId)
2783 http = new XMLHttpRequest();
2785 obj = { conn:http, tId:transactionId };
2789 for (var i = 0; i < this.activeX.length; ++i) {
2793 http = new ActiveXObject(this.activeX[i]);
2795 obj = { conn:http, tId:transactionId };
2808 getConnectionObject:function()
2811 var tId = this.transactionId;
2815 o = this.createXhrObject(tId);
2817 this.transactionId++;
2828 asyncRequest:function(method, uri, callback, postData)
2830 var o = this.getConnectionObject();
2836 o.conn.open(method, uri, true);
2838 if (this.useDefaultXhrHeader) {
2839 if (!this.defaultHeaders['X-Requested-With']) {
2840 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2844 if(postData && this.useDefaultHeader){
2845 this.initHeader('Content-Type', this.defaultPostHeader);
2848 if (this.hasDefaultHeaders || this.hasHeaders) {
2852 this.handleReadyState(o, callback);
2853 o.conn.send(postData || null);
2859 handleReadyState:function(o, callback)
2863 if (callback && callback.timeout) {
2865 this.timeout[o.tId] = window.setTimeout(function() {
2866 oConn.abort(o, callback, true);
2867 }, callback.timeout);
2870 this.poll[o.tId] = window.setInterval(
2872 if (o.conn && o.conn.readyState == 4) {
2873 window.clearInterval(oConn.poll[o.tId]);
2874 delete oConn.poll[o.tId];
2876 if(callback && callback.timeout) {
2877 window.clearTimeout(oConn.timeout[o.tId]);
2878 delete oConn.timeout[o.tId];
2881 oConn.handleTransactionResponse(o, callback);
2884 , this.pollInterval);
2887 handleTransactionResponse:function(o, callback, isAbort)
2891 this.releaseObject(o);
2895 var httpStatus, responseObject;
2899 if (o.conn.status !== undefined && o.conn.status != 0) {
2900 httpStatus = o.conn.status;
2912 if (httpStatus >= 200 && httpStatus < 300) {
2913 responseObject = this.createResponseObject(o, callback.argument);
2914 if (callback.success) {
2915 if (!callback.scope) {
2916 callback.success(responseObject);
2921 callback.success.apply(callback.scope, [responseObject]);
2926 switch (httpStatus) {
2934 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2935 if (callback.failure) {
2936 if (!callback.scope) {
2937 callback.failure(responseObject);
2940 callback.failure.apply(callback.scope, [responseObject]);
2945 responseObject = this.createResponseObject(o, callback.argument);
2946 if (callback.failure) {
2947 if (!callback.scope) {
2948 callback.failure(responseObject);
2951 callback.failure.apply(callback.scope, [responseObject]);
2957 this.releaseObject(o);
2958 responseObject = null;
2961 createResponseObject:function(o, callbackArg)
2968 var headerStr = o.conn.getAllResponseHeaders();
2969 var header = headerStr.split('\n');
2970 for (var i = 0; i < header.length; i++) {
2971 var delimitPos = header[i].indexOf(':');
2972 if (delimitPos != -1) {
2973 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2981 obj.status = o.conn.status;
2982 obj.statusText = o.conn.statusText;
2983 obj.getResponseHeader = headerObj;
2984 obj.getAllResponseHeaders = headerStr;
2985 obj.responseText = o.conn.responseText;
2986 obj.responseXML = o.conn.responseXML;
2988 if (typeof callbackArg !== undefined) {
2989 obj.argument = callbackArg;
2995 createExceptionObject:function(tId, callbackArg, isAbort)
2998 var COMM_ERROR = 'communication failure';
2999 var ABORT_CODE = -1;
3000 var ABORT_ERROR = 'transaction aborted';
3006 obj.status = ABORT_CODE;
3007 obj.statusText = ABORT_ERROR;
3010 obj.status = COMM_CODE;
3011 obj.statusText = COMM_ERROR;
3015 obj.argument = callbackArg;
3021 initHeader:function(label, value, isDefault)
3023 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
3025 if (headerObj[label] === undefined) {
3026 headerObj[label] = value;
3031 headerObj[label] = value + "," + headerObj[label];
3035 this.hasDefaultHeaders = true;
3038 this.hasHeaders = true;
3043 setHeader:function(o)
3045 if (this.hasDefaultHeaders) {
3046 for (var prop in this.defaultHeaders) {
3047 if (this.defaultHeaders.hasOwnProperty(prop)) {
3048 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3053 if (this.hasHeaders) {
3054 for (var prop in this.headers) {
3055 if (this.headers.hasOwnProperty(prop)) {
3056 o.conn.setRequestHeader(prop, this.headers[prop]);
3060 this.hasHeaders = false;
3064 resetDefaultHeaders:function() {
3065 delete this.defaultHeaders;
3066 this.defaultHeaders = {};
3067 this.hasDefaultHeaders = false;
3070 abort:function(o, callback, isTimeout)
3072 if(this.isCallInProgress(o)) {
3074 window.clearInterval(this.poll[o.tId]);
3075 delete this.poll[o.tId];
3077 delete this.timeout[o.tId];
3080 this.handleTransactionResponse(o, callback, true);
3090 isCallInProgress:function(o)
3093 return o.conn.readyState != 4 && o.conn.readyState != 0;
3102 releaseObject:function(o)
3111 'MSXML2.XMLHTTP.3.0',
3119 * Portions of this file are based on pieces of Yahoo User Interface Library
3120 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3121 * YUI licensed under the BSD License:
3122 * http://developer.yahoo.net/yui/license.txt
3123 * <script type="text/javascript">
3127 Roo.lib.Region = function(t, r, b, l) {
3137 Roo.lib.Region.prototype = {
3138 contains : function(region) {
3139 return ( region.left >= this.left &&
3140 region.right <= this.right &&
3141 region.top >= this.top &&
3142 region.bottom <= this.bottom );
3146 getArea : function() {
3147 return ( (this.bottom - this.top) * (this.right - this.left) );
3150 intersect : function(region) {
3151 var t = Math.max(this.top, region.top);
3152 var r = Math.min(this.right, region.right);
3153 var b = Math.min(this.bottom, region.bottom);
3154 var l = Math.max(this.left, region.left);
3156 if (b >= t && r >= l) {
3157 return new Roo.lib.Region(t, r, b, l);
3162 union : function(region) {
3163 var t = Math.min(this.top, region.top);
3164 var r = Math.max(this.right, region.right);
3165 var b = Math.max(this.bottom, region.bottom);
3166 var l = Math.min(this.left, region.left);
3168 return new Roo.lib.Region(t, r, b, l);
3171 adjust : function(t, l, b, r) {
3180 Roo.lib.Region.getRegion = function(el) {
3181 var p = Roo.lib.Dom.getXY(el);
3184 var r = p[0] + el.offsetWidth;
3185 var b = p[1] + el.offsetHeight;
3188 return new Roo.lib.Region(t, r, b, l);
3191 * Portions of this file are based on pieces of Yahoo User Interface Library
3192 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3193 * YUI licensed under the BSD License:
3194 * http://developer.yahoo.net/yui/license.txt
3195 * <script type="text/javascript">
3198 //@@dep Roo.lib.Region
3201 Roo.lib.Point = function(x, y) {
3202 if (x instanceof Array) {
3206 this.x = this.right = this.left = this[0] = x;
3207 this.y = this.top = this.bottom = this[1] = y;
3210 Roo.lib.Point.prototype = new Roo.lib.Region();
3212 * Portions of this file are based on pieces of Yahoo User Interface Library
3213 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3214 * YUI licensed under the BSD License:
3215 * http://developer.yahoo.net/yui/license.txt
3216 * <script type="text/javascript">
3223 scroll : function(el, args, duration, easing, cb, scope) {
3224 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3227 motion : function(el, args, duration, easing, cb, scope) {
3228 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3231 color : function(el, args, duration, easing, cb, scope) {
3232 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3235 run : function(el, args, duration, easing, cb, scope, type) {
3236 type = type || Roo.lib.AnimBase;
3237 if (typeof easing == "string") {
3238 easing = Roo.lib.Easing[easing];
3240 var anim = new type(el, args, duration, easing);
3241 anim.animateX(function() {
3242 Roo.callback(cb, scope);
3248 * Portions of this file are based on pieces of Yahoo User Interface Library
3249 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3250 * YUI licensed under the BSD License:
3251 * http://developer.yahoo.net/yui/license.txt
3252 * <script type="text/javascript">
3260 if (!libFlyweight) {
3261 libFlyweight = new Roo.Element.Flyweight();
3263 libFlyweight.dom = el;
3264 return libFlyweight;
3267 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3271 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3273 this.init(el, attributes, duration, method);
3277 Roo.lib.AnimBase.fly = fly;
3281 Roo.lib.AnimBase.prototype = {
3283 toString: function() {
3284 var el = this.getEl();
3285 var id = el.id || el.tagName;
3286 return ("Anim " + id);
3290 noNegatives: /width|height|opacity|padding/i,
3291 offsetAttribute: /^((width|height)|(top|left))$/,
3292 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3293 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3297 doMethod: function(attr, start, end) {
3298 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3302 setAttribute: function(attr, val, unit) {
3303 if (this.patterns.noNegatives.test(attr)) {
3304 val = (val > 0) ? val : 0;
3307 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3311 getAttribute: function(attr) {
3312 var el = this.getEl();
3313 var val = fly(el).getStyle(attr);
3315 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3316 return parseFloat(val);
3319 var a = this.patterns.offsetAttribute.exec(attr) || [];
3320 var pos = !!( a[3] );
3321 var box = !!( a[2] );
3324 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3325 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3334 getDefaultUnit: function(attr) {
3335 if (this.patterns.defaultUnit.test(attr)) {
3342 animateX : function(callback, scope) {
3343 var f = function() {
3344 this.onComplete.removeListener(f);
3345 if (typeof callback == "function") {
3346 callback.call(scope || this, this);
3349 this.onComplete.addListener(f, this);
3354 setRuntimeAttribute: function(attr) {
3357 var attributes = this.attributes;
3359 this.runtimeAttributes[attr] = {};
3361 var isset = function(prop) {
3362 return (typeof prop !== 'undefined');
3365 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3369 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3372 if (isset(attributes[attr]['to'])) {
3373 end = attributes[attr]['to'];
3374 } else if (isset(attributes[attr]['by'])) {
3375 if (start.constructor == Array) {
3377 for (var i = 0, len = start.length; i < len; ++i) {
3378 end[i] = start[i] + attributes[attr]['by'][i];
3381 end = start + attributes[attr]['by'];
3385 this.runtimeAttributes[attr].start = start;
3386 this.runtimeAttributes[attr].end = end;
3389 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3393 init: function(el, attributes, duration, method) {
3395 var isAnimated = false;
3398 var startTime = null;
3401 var actualFrames = 0;
3404 el = Roo.getDom(el);
3407 this.attributes = attributes || {};
3410 this.duration = duration || 1;
3413 this.method = method || Roo.lib.Easing.easeNone;
3416 this.useSeconds = true;
3419 this.currentFrame = 0;
3422 this.totalFrames = Roo.lib.AnimMgr.fps;
3425 this.getEl = function() {
3430 this.isAnimated = function() {
3435 this.getStartTime = function() {
3439 this.runtimeAttributes = {};
3442 this.animate = function() {
3443 if (this.isAnimated()) {
3447 this.currentFrame = 0;
3449 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3451 Roo.lib.AnimMgr.registerElement(this);
3455 this.stop = function(finish) {
3457 this.currentFrame = this.totalFrames;
3458 this._onTween.fire();
3460 Roo.lib.AnimMgr.stop(this);
3463 var onStart = function() {
3464 this.onStart.fire();
3466 this.runtimeAttributes = {};
3467 for (var attr in this.attributes) {
3468 this.setRuntimeAttribute(attr);
3473 startTime = new Date();
3477 var onTween = function() {
3479 duration: new Date() - this.getStartTime(),
3480 currentFrame: this.currentFrame
3483 data.toString = function() {
3485 'duration: ' + data.duration +
3486 ', currentFrame: ' + data.currentFrame
3490 this.onTween.fire(data);
3492 var runtimeAttributes = this.runtimeAttributes;
3494 for (var attr in runtimeAttributes) {
3495 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3501 var onComplete = function() {
3502 var actual_duration = (new Date() - startTime) / 1000 ;
3505 duration: actual_duration,
3506 frames: actualFrames,
3507 fps: actualFrames / actual_duration
3510 data.toString = function() {
3512 'duration: ' + data.duration +
3513 ', frames: ' + data.frames +
3514 ', fps: ' + data.fps
3520 this.onComplete.fire(data);
3524 this._onStart = new Roo.util.Event(this);
3525 this.onStart = new Roo.util.Event(this);
3526 this.onTween = new Roo.util.Event(this);
3527 this._onTween = new Roo.util.Event(this);
3528 this.onComplete = new Roo.util.Event(this);
3529 this._onComplete = new Roo.util.Event(this);
3530 this._onStart.addListener(onStart);
3531 this._onTween.addListener(onTween);
3532 this._onComplete.addListener(onComplete);
3537 * Portions of this file are based on pieces of Yahoo User Interface Library
3538 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3539 * YUI licensed under the BSD License:
3540 * http://developer.yahoo.net/yui/license.txt
3541 * <script type="text/javascript">
3545 Roo.lib.AnimMgr = new function() {
3562 this.registerElement = function(tween) {
3563 queue[queue.length] = tween;
3565 tween._onStart.fire();
3570 this.unRegister = function(tween, index) {
3571 tween._onComplete.fire();
3572 index = index || getIndex(tween);
3574 queue.splice(index, 1);
3578 if (tweenCount <= 0) {
3584 this.start = function() {
3585 if (thread === null) {
3586 thread = setInterval(this.run, this.delay);
3591 this.stop = function(tween) {
3593 clearInterval(thread);
3595 for (var i = 0, len = queue.length; i < len; ++i) {
3596 if (queue[0].isAnimated()) {
3597 this.unRegister(queue[0], 0);
3606 this.unRegister(tween);
3611 this.run = function() {
3612 for (var i = 0, len = queue.length; i < len; ++i) {
3613 var tween = queue[i];
3614 if (!tween || !tween.isAnimated()) {
3618 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3620 tween.currentFrame += 1;
3622 if (tween.useSeconds) {
3623 correctFrame(tween);
3625 tween._onTween.fire();
3628 Roo.lib.AnimMgr.stop(tween, i);
3633 var getIndex = function(anim) {
3634 for (var i = 0, len = queue.length; i < len; ++i) {
3635 if (queue[i] == anim) {
3643 var correctFrame = function(tween) {
3644 var frames = tween.totalFrames;
3645 var frame = tween.currentFrame;
3646 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3647 var elapsed = (new Date() - tween.getStartTime());
3650 if (elapsed < tween.duration * 1000) {
3651 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3653 tweak = frames - (frame + 1);
3655 if (tweak > 0 && isFinite(tweak)) {
3656 if (tween.currentFrame + tweak >= frames) {
3657 tweak = frames - (frame + 1);
3660 tween.currentFrame += tweak;
3666 * Portions of this file are based on pieces of Yahoo User Interface Library
3667 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3668 * YUI licensed under the BSD License:
3669 * http://developer.yahoo.net/yui/license.txt
3670 * <script type="text/javascript">
3673 Roo.lib.Bezier = new function() {
3675 this.getPosition = function(points, t) {
3676 var n = points.length;
3679 for (var i = 0; i < n; ++i) {
3680 tmp[i] = [points[i][0], points[i][1]];
3683 for (var j = 1; j < n; ++j) {
3684 for (i = 0; i < n - j; ++i) {
3685 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3686 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3690 return [ tmp[0][0], tmp[0][1] ];
3696 * @class Roo.lib.Color
3698 * An abstract Color implementation. Concrete Color implementations should use
3699 * an instance of this function as their prototype, and implement the getRGB and
3700 * getHSL functions. getRGB should return an object representing the RGB
3701 * components of this Color, with the red, green, and blue components in the
3702 * range [0,255] and the alpha component in the range [0,100]. getHSL should
3703 * return an object representing the HSL components of this Color, with the hue
3704 * component in the range [0,360), the saturation and lightness components in
3705 * the range [0,100], and the alpha component in the range [0,1].
3710 * Functions for Color handling and processing.
3712 * http://www.safalra.com/web-design/javascript/Color-handling-and-processing/
3714 * The author of this program, Safalra (Stephen Morley), irrevocably releases all
3715 * rights to this program, with the intention of it becoming part of the public
3716 * domain. Because this program is released into the public domain, it comes with
3717 * no warranty either expressed or implied, to the extent permitted by law.
3719 * For more free and public domain JavaScript code by the same author, visit:
3720 * http://www.safalra.com/web-design/javascript/
3723 Roo.lib.Color = function() { }
3726 Roo.apply(Roo.lib.Color.prototype, {
3734 * @return {Object} an object representing the RGBA components of this Color. The red,
3735 * green, and blue components are converted to integers in the range [0,255].
3736 * The alpha is a value in the range [0,1].
3738 getIntegerRGB : function(){
3740 // get the RGB components of this Color
3741 var rgb = this.getRGB();
3743 // return the integer components
3745 'r' : Math.round(rgb.r),
3746 'g' : Math.round(rgb.g),
3747 'b' : Math.round(rgb.b),
3755 * @return {Object} an object representing the RGBA components of this Color. The red,
3756 * green, and blue components are converted to numbers in the range [0,100].
3757 * The alpha is a value in the range [0,1].
3759 getPercentageRGB : function(){
3761 // get the RGB components of this Color
3762 var rgb = this.getRGB();
3764 // return the percentage components
3766 'r' : 100 * rgb.r / 255,
3767 'g' : 100 * rgb.g / 255,
3768 'b' : 100 * rgb.b / 255,
3775 * getCSSHexadecimalRGB
3776 * @return {String} a string representing this Color as a CSS hexadecimal RGB Color
3777 * value - that is, a string of the form #RRGGBB where each of RR, GG, and BB
3778 * are two-digit hexadecimal numbers.
3780 getCSSHexadecimalRGB : function()
3783 // get the integer RGB components
3784 var rgb = this.getIntegerRGB();
3786 // determine the hexadecimal equivalents
3787 var r16 = rgb.r.toString(16);
3788 var g16 = rgb.g.toString(16);
3789 var b16 = rgb.b.toString(16);
3791 // return the CSS RGB Color value
3793 + (r16.length == 2 ? r16 : '0' + r16)
3794 + (g16.length == 2 ? g16 : '0' + g16)
3795 + (b16.length == 2 ? b16 : '0' + b16);
3801 * @return {String} a string representing this Color as a CSS integer RGB Color
3802 * value - that is, a string of the form rgb(r,g,b) where each of r, g, and b
3803 * are integers in the range [0,255].
3805 getCSSIntegerRGB : function(){
3807 // get the integer RGB components
3808 var rgb = this.getIntegerRGB();
3810 // return the CSS RGB Color value
3811 return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')';
3817 * @return {String} Returns a string representing this Color as a CSS integer RGBA Color
3818 * value - that is, a string of the form rgba(r,g,b,a) where each of r, g, and
3819 * b are integers in the range [0,255] and a is in the range [0,1].
3821 getCSSIntegerRGBA : function(){
3823 // get the integer RGB components
3824 var rgb = this.getIntegerRGB();
3826 // return the CSS integer RGBA Color value
3827 return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + rgb.a + ')';
3832 * getCSSPercentageRGB
3833 * @return {String} a string representing this Color as a CSS percentage RGB Color
3834 * value - that is, a string of the form rgb(r%,g%,b%) where each of r, g, and
3835 * b are in the range [0,100].
3837 getCSSPercentageRGB : function(){
3839 // get the percentage RGB components
3840 var rgb = this.getPercentageRGB();
3842 // return the CSS RGB Color value
3843 return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%)';
3848 * getCSSPercentageRGBA
3849 * @return {String} a string representing this Color as a CSS percentage RGBA Color
3850 * value - that is, a string of the form rgba(r%,g%,b%,a) where each of r, g,
3851 * and b are in the range [0,100] and a is in the range [0,1].
3853 getCSSPercentageRGBA : function(){
3855 // get the percentage RGB components
3856 var rgb = this.getPercentageRGB();
3858 // return the CSS percentage RGBA Color value
3859 return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%,' + rgb.a + ')';
3865 * @return {String} a string representing this Color as a CSS HSL Color value - that
3866 * is, a string of the form hsl(h,s%,l%) where h is in the range [0,100] and
3867 * s and l are in the range [0,100].
3869 getCSSHSL : function(){
3871 // get the HSL components
3872 var hsl = this.getHSL();
3874 // return the CSS HSL Color value
3875 return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%)';
3881 * @return {String} a string representing this Color as a CSS HSLA Color value - that
3882 * is, a string of the form hsla(h,s%,l%,a) where h is in the range [0,100],
3883 * s and l are in the range [0,100], and a is in the range [0,1].
3885 getCSSHSLA : function(){
3887 // get the HSL components
3888 var hsl = this.getHSL();
3890 // return the CSS HSL Color value
3891 return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%,' + hsl.a + ')';
3896 * Sets the Color of the specified node to this Color. This functions sets
3897 * the CSS 'color' property for the node. The parameter is:
3899 * @param {DomElement} node - the node whose Color should be set
3901 setNodeColor : function(node){
3903 // set the Color of the node
3904 node.style.color = this.getCSSHexadecimalRGB();
3909 * Sets the background Color of the specified node to this Color. This
3910 * functions sets the CSS 'background-color' property for the node. The
3913 * @param {DomElement} node - the node whose background Color should be set
3915 setNodeBackgroundColor : function(node){
3917 // set the background Color of the node
3918 node.style.backgroundColor = this.getCSSHexadecimalRGB();
3921 // convert between formats..
3924 var r = this.getIntegerRGB();
3925 return new Roo.lib.RGBColor(r.r,r.g,r.b,r.a);
3930 var hsl = this.getHSL();
3931 // return the CSS HSL Color value
3932 return new Roo.lib.HSLColor(hsl.h, hsl.s, hsl.l , hsl.a );
3938 var rgb = this.toRGB();
3939 var hsv = rgb.getHSV();
3940 // return the CSS HSL Color value
3941 return new Roo.lib.HSVColor(hsv.h, hsv.s, hsv.v , hsv.a );
3945 // modify v = 0 ... 1 (eg. 0.5)
3946 saturate : function(v)
3948 var rgb = this.toRGB();
3949 var hsv = rgb.getHSV();
3950 return new Roo.lib.HSVColor(hsv.h, hsv.s * v, hsv.v , hsv.a );
3958 * @return {Object} the RGB and alpha components of this Color as an object with r,
3959 * g, b, and a properties. r, g, and b are in the range [0,255] and a is in
3964 // return the RGB components
3976 * @return {Object} the HSV and alpha components of this Color as an object with h,
3977 * s, v, and a properties. h is in the range [0,360), s and v are in the range
3978 * [0,100], and a is in the range [0,1].
3983 // calculate the HSV components if necessary
3984 if (this.hsv == null) {
3985 this.calculateHSV();
3988 // return the HSV components
4000 * @return {Object} the HSL and alpha components of this Color as an object with h,
4001 * s, l, and a properties. h is in the range [0,360), s and l are in the range
4002 * [0,100], and a is in the range [0,1].
4004 getHSL : function(){
4007 // calculate the HSV components if necessary
4008 if (this.hsl == null) { this.calculateHSL(); }
4010 // return the HSL components
4025 * @class Roo.lib.RGBColor
4026 * @extends Roo.lib.Color
4027 * Creates a Color specified in the RGB Color space, with an optional alpha
4028 * component. The parameters are:
4032 * @param {Number} r - the red component, clipped to the range [0,255]
4033 * @param {Number} g - the green component, clipped to the range [0,255]
4034 * @param {Number} b - the blue component, clipped to the range [0,255]
4035 * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4036 * optional and defaults to 1
4038 Roo.lib.RGBColor = function (r, g, b, a){
4040 // store the alpha component after clipping it if necessary
4041 this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4043 // store the RGB components after clipping them if necessary
4046 'r' : Math.max(0, Math.min(255, r)),
4047 'g' : Math.max(0, Math.min(255, g)),
4048 'b' : Math.max(0, Math.min(255, b))
4051 // initialise the HSV and HSL components to null
4055 * //private returns the HSV or HSL hue component of this RGBColor. The hue is in the
4056 * range [0,360). The parameters are:
4058 * maximum - the maximum of the RGB component values
4059 * range - the range of the RGB component values
4064 // this does an 'exteds'
4065 Roo.extend(Roo.lib.RGBColor, Roo.lib.Color, {
4068 getHue : function(maximum, range)
4072 // check whether the range is zero
4075 // set the hue to zero (any hue is acceptable as the Color is grey)
4080 // determine which of the components has the highest value and set the hue
4083 // red has the highest value
4085 var hue = (rgb.g - rgb.b) / range * 60;
4086 if (hue < 0) { hue += 360; }
4089 // green has the highest value
4091 var hue = (rgb.b - rgb.r) / range * 60 + 120;
4094 // blue has the highest value
4096 var hue = (rgb.r - rgb.g) / range * 60 + 240;
4108 /* //private Calculates and stores the HSV components of this RGBColor so that they can
4109 * be returned be the getHSV function.
4111 calculateHSV : function(){
4113 // get the maximum and range of the RGB component values
4114 var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4115 var range = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4117 // store the HSV components
4120 'h' : this.getHue(maximum, range),
4121 's' : (maximum == 0 ? 0 : 100 * range / maximum),
4122 'v' : maximum / 2.55
4127 /* //private Calculates and stores the HSL components of this RGBColor so that they can
4128 * be returned be the getHSL function.
4130 calculateHSL : function(){
4132 // get the maximum and range of the RGB component values
4133 var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4134 var range = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4136 // determine the lightness in the range [0,1]
4137 var l = maximum / 255 - range / 510;
4139 // store the HSL components
4142 'h' : this.getHue(maximum, range),
4143 's' : (range == 0 ? 0 : range / 2.55 / (l < 0.5 ? l * 2 : 2 - l * 2)),
4152 * @class Roo.lib.HSVColor
4153 * @extends Roo.lib.Color
4154 * Creates a Color specified in the HSV Color space, with an optional alpha
4155 * component. The parameters are:
4158 * @param {Number} h - the hue component, wrapped to the range [0,360)
4159 * @param {Number} s - the saturation component, clipped to the range [0,100]
4160 * @param {Number} v - the value component, clipped to the range [0,100]
4161 * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4162 * optional and defaults to 1
4164 Roo.lib.HSVColor = function (h, s, v, a){
4166 // store the alpha component after clipping it if necessary
4167 this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4169 // store the HSV components after clipping or wrapping them if necessary
4172 'h' : (h % 360 + 360) % 360,
4173 's' : Math.max(0, Math.min(100, s)),
4174 'v' : Math.max(0, Math.min(100, v))
4177 // initialise the RGB and HSL components to null
4182 Roo.extend(Roo.lib.HSVColor, Roo.lib.Color, {
4183 /* Calculates and stores the RGB components of this HSVColor so that they can
4184 * be returned be the getRGB function.
4186 calculateRGB: function ()
4189 // check whether the saturation is zero
4192 // set the Color to the appropriate shade of grey
4199 // set some temporary values
4200 var f = hsv.h / 60 - Math.floor(hsv.h / 60);
4201 var p = hsv.v * (1 - hsv.s / 100);
4202 var q = hsv.v * (1 - hsv.s / 100 * f);
4203 var t = hsv.v * (1 - hsv.s / 100 * (1 - f));
4205 // set the RGB Color components to their temporary values
4206 switch (Math.floor(hsv.h / 60)){
4207 case 0: var r = hsv.v; var g = t; var b = p; break;
4208 case 1: var r = q; var g = hsv.v; var b = p; break;
4209 case 2: var r = p; var g = hsv.v; var b = t; break;
4210 case 3: var r = p; var g = q; var b = hsv.v; break;
4211 case 4: var r = t; var g = p; var b = hsv.v; break;
4212 case 5: var r = hsv.v; var g = p; var b = q; break;
4217 // store the RGB components
4227 /* Calculates and stores the HSL components of this HSVColor so that they can
4228 * be returned be the getHSL function.
4230 calculateHSL : function (){
4233 // determine the lightness in the range [0,100]
4234 var l = (2 - hsv.s / 100) * hsv.v / 2;
4236 // store the HSL components
4240 's' : hsv.s * hsv.v / (l < 50 ? l * 2 : 200 - l * 2),
4244 // correct a division-by-zero error
4245 if (isNaN(hsl.s)) { hsl.s = 0; }
4254 * @class Roo.lib.HSLColor
4255 * @extends Roo.lib.Color
4258 * Creates a Color specified in the HSL Color space, with an optional alpha
4259 * component. The parameters are:
4261 * @param {Number} h - the hue component, wrapped to the range [0,360)
4262 * @param {Number} s - the saturation component, clipped to the range [0,100]
4263 * @param {Number} l - the lightness component, clipped to the range [0,100]
4264 * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4265 * optional and defaults to 1
4268 Roo.lib.HSLColor = function(h, s, l, a){
4270 // store the alpha component after clipping it if necessary
4271 this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4273 // store the HSL components after clipping or wrapping them if necessary
4276 'h' : (h % 360 + 360) % 360,
4277 's' : Math.max(0, Math.min(100, s)),
4278 'l' : Math.max(0, Math.min(100, l))
4281 // initialise the RGB and HSV components to null
4284 Roo.extend(Roo.lib.HSLColor, Roo.lib.Color, {
4286 /* Calculates and stores the RGB components of this HSLColor so that they can
4287 * be returned be the getRGB function.
4289 calculateRGB: function (){
4291 // check whether the saturation is zero
4292 if (this.hsl.s == 0){
4294 // store the RGB components representing the appropriate shade of grey
4297 'r' : this.hsl.l * 2.55,
4298 'g' : this.hsl.l * 2.55,
4299 'b' : this.hsl.l * 2.55
4304 // set some temporary values
4305 var p = this.hsl.l < 50
4306 ? this.hsl.l * (1 + hsl.s / 100)
4307 : this.hsl.l + hsl.s - hsl.l * hsl.s / 100;
4308 var q = 2 * hsl.l - p;
4310 // initialise the RGB components
4313 'r' : (h + 120) / 60 % 6,
4315 'b' : (h + 240) / 60 % 6
4318 // loop over the RGB components
4319 for (var key in this.rgb){
4321 // ensure that the property is not inherited from the root object
4322 if (this.rgb.hasOwnProperty(key)){
4324 // set the component to its value in the range [0,100]
4325 if (this.rgb[key] < 1){
4326 this.rgb[key] = q + (p - q) * this.rgb[key];
4327 }else if (this.rgb[key] < 3){
4329 }else if (this.rgb[key] < 4){
4330 this.rgb[key] = q + (p - q) * (4 - this.rgb[key]);
4335 // set the component to its value in the range [0,255]
4336 this.rgb[key] *= 2.55;
4346 /* Calculates and stores the HSV components of this HSLColor so that they can
4347 * be returned be the getHSL function.
4349 calculateHSV : function(){
4351 // set a temporary value
4352 var t = this.hsl.s * (this.hsl.l < 50 ? this.hsl.l : 100 - this.hsl.l) / 100;
4354 // store the HSV components
4358 's' : 200 * t / (this.hsl.l + t),
4359 'v' : t + this.hsl.l
4362 // correct a division-by-zero error
4363 if (isNaN(this.hsv.s)) { this.hsv.s = 0; }
4370 * Portions of this file are based on pieces of Yahoo User Interface Library
4371 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4372 * YUI licensed under the BSD License:
4373 * http://developer.yahoo.net/yui/license.txt
4374 * <script type="text/javascript">
4379 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
4380 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
4383 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
4385 var fly = Roo.lib.AnimBase.fly;
4387 var superclass = Y.ColorAnim.superclass;
4388 var proto = Y.ColorAnim.prototype;
4390 proto.toString = function() {
4391 var el = this.getEl();
4392 var id = el.id || el.tagName;
4393 return ("ColorAnim " + id);
4396 proto.patterns.color = /color$/i;
4397 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
4398 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
4399 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
4400 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
4403 proto.parseColor = function(s) {
4404 if (s.length == 3) {
4408 var c = this.patterns.hex.exec(s);
4409 if (c && c.length == 4) {
4410 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
4413 c = this.patterns.rgb.exec(s);
4414 if (c && c.length == 4) {
4415 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
4418 c = this.patterns.hex3.exec(s);
4419 if (c && c.length == 4) {
4420 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
4425 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
4426 proto.getAttribute = function(attr) {
4427 var el = this.getEl();
4428 if (this.patterns.color.test(attr)) {
4429 var val = fly(el).getStyle(attr);
4431 if (this.patterns.transparent.test(val)) {
4432 var parent = el.parentNode;
4433 val = fly(parent).getStyle(attr);
4435 while (parent && this.patterns.transparent.test(val)) {
4436 parent = parent.parentNode;
4437 val = fly(parent).getStyle(attr);
4438 if (parent.tagName.toUpperCase() == 'HTML') {
4444 val = superclass.getAttribute.call(this, attr);
4449 proto.getAttribute = function(attr) {
4450 var el = this.getEl();
4451 if (this.patterns.color.test(attr)) {
4452 var val = fly(el).getStyle(attr);
4454 if (this.patterns.transparent.test(val)) {
4455 var parent = el.parentNode;
4456 val = fly(parent).getStyle(attr);
4458 while (parent && this.patterns.transparent.test(val)) {
4459 parent = parent.parentNode;
4460 val = fly(parent).getStyle(attr);
4461 if (parent.tagName.toUpperCase() == 'HTML') {
4467 val = superclass.getAttribute.call(this, attr);
4473 proto.doMethod = function(attr, start, end) {
4476 if (this.patterns.color.test(attr)) {
4478 for (var i = 0, len = start.length; i < len; ++i) {
4479 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
4482 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
4485 val = superclass.doMethod.call(this, attr, start, end);
4491 proto.setRuntimeAttribute = function(attr) {
4492 superclass.setRuntimeAttribute.call(this, attr);
4494 if (this.patterns.color.test(attr)) {
4495 var attributes = this.attributes;
4496 var start = this.parseColor(this.runtimeAttributes[attr].start);
4497 var end = this.parseColor(this.runtimeAttributes[attr].end);
4499 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
4500 end = this.parseColor(attributes[attr].by);
4502 for (var i = 0, len = start.length; i < len; ++i) {
4503 end[i] = start[i] + end[i];
4507 this.runtimeAttributes[attr].start = start;
4508 this.runtimeAttributes[attr].end = end;
4514 * Portions of this file are based on pieces of Yahoo User Interface Library
4515 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4516 * YUI licensed under the BSD License:
4517 * http://developer.yahoo.net/yui/license.txt
4518 * <script type="text/javascript">
4524 easeNone: function (t, b, c, d) {
4525 return c * t / d + b;
4529 easeIn: function (t, b, c, d) {
4530 return c * (t /= d) * t + b;
4534 easeOut: function (t, b, c, d) {
4535 return -c * (t /= d) * (t - 2) + b;
4539 easeBoth: function (t, b, c, d) {
4540 if ((t /= d / 2) < 1) {
4541 return c / 2 * t * t + b;
4544 return -c / 2 * ((--t) * (t - 2) - 1) + b;
4548 easeInStrong: function (t, b, c, d) {
4549 return c * (t /= d) * t * t * t + b;
4553 easeOutStrong: function (t, b, c, d) {
4554 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
4558 easeBothStrong: function (t, b, c, d) {
4559 if ((t /= d / 2) < 1) {
4560 return c / 2 * t * t * t * t + b;
4563 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
4568 elasticIn: function (t, b, c, d, a, p) {
4572 if ((t /= d) == 1) {
4579 if (!a || a < Math.abs(c)) {
4584 var s = p / (2 * Math.PI) * Math.asin(c / a);
4587 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4591 elasticOut: function (t, b, c, d, a, p) {
4595 if ((t /= d) == 1) {
4602 if (!a || a < Math.abs(c)) {
4607 var s = p / (2 * Math.PI) * Math.asin(c / a);
4610 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
4614 elasticBoth: function (t, b, c, d, a, p) {
4619 if ((t /= d / 2) == 2) {
4627 if (!a || a < Math.abs(c)) {
4632 var s = p / (2 * Math.PI) * Math.asin(c / a);
4636 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
4637 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4639 return a * Math.pow(2, -10 * (t -= 1)) *
4640 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
4645 backIn: function (t, b, c, d, s) {
4646 if (typeof s == 'undefined') {
4649 return c * (t /= d) * t * ((s + 1) * t - s) + b;
4653 backOut: function (t, b, c, d, s) {
4654 if (typeof s == 'undefined') {
4657 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
4661 backBoth: function (t, b, c, d, s) {
4662 if (typeof s == 'undefined') {
4666 if ((t /= d / 2 ) < 1) {
4667 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
4669 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
4673 bounceIn: function (t, b, c, d) {
4674 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
4678 bounceOut: function (t, b, c, d) {
4679 if ((t /= d) < (1 / 2.75)) {
4680 return c * (7.5625 * t * t) + b;
4681 } else if (t < (2 / 2.75)) {
4682 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
4683 } else if (t < (2.5 / 2.75)) {
4684 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
4686 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
4690 bounceBoth: function (t, b, c, d) {
4692 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
4694 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
4697 * Portions of this file are based on pieces of Yahoo User Interface Library
4698 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4699 * YUI licensed under the BSD License:
4700 * http://developer.yahoo.net/yui/license.txt
4701 * <script type="text/javascript">
4705 Roo.lib.Motion = function(el, attributes, duration, method) {
4707 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
4711 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
4715 var superclass = Y.Motion.superclass;
4716 var proto = Y.Motion.prototype;
4718 proto.toString = function() {
4719 var el = this.getEl();
4720 var id = el.id || el.tagName;
4721 return ("Motion " + id);
4724 proto.patterns.points = /^points$/i;
4726 proto.setAttribute = function(attr, val, unit) {
4727 if (this.patterns.points.test(attr)) {
4728 unit = unit || 'px';
4729 superclass.setAttribute.call(this, 'left', val[0], unit);
4730 superclass.setAttribute.call(this, 'top', val[1], unit);
4732 superclass.setAttribute.call(this, attr, val, unit);
4736 proto.getAttribute = function(attr) {
4737 if (this.patterns.points.test(attr)) {
4739 superclass.getAttribute.call(this, 'left'),
4740 superclass.getAttribute.call(this, 'top')
4743 val = superclass.getAttribute.call(this, attr);
4749 proto.doMethod = function(attr, start, end) {
4752 if (this.patterns.points.test(attr)) {
4753 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4754 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4756 val = superclass.doMethod.call(this, attr, start, end);
4761 proto.setRuntimeAttribute = function(attr) {
4762 if (this.patterns.points.test(attr)) {
4763 var el = this.getEl();
4764 var attributes = this.attributes;
4766 var control = attributes['points']['control'] || [];
4770 if (control.length > 0 && !(control[0] instanceof Array)) {
4771 control = [control];
4774 for (i = 0,len = control.length; i < len; ++i) {
4775 tmp[i] = control[i];
4780 Roo.fly(el).position();
4782 if (isset(attributes['points']['from'])) {
4783 Roo.lib.Dom.setXY(el, attributes['points']['from']);
4786 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4789 start = this.getAttribute('points');
4792 if (isset(attributes['points']['to'])) {
4793 end = translateValues.call(this, attributes['points']['to'], start);
4795 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4796 for (i = 0,len = control.length; i < len; ++i) {
4797 control[i] = translateValues.call(this, control[i], start);
4801 } else if (isset(attributes['points']['by'])) {
4802 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4804 for (i = 0,len = control.length; i < len; ++i) {
4805 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4809 this.runtimeAttributes[attr] = [start];
4811 if (control.length > 0) {
4812 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4815 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4818 superclass.setRuntimeAttribute.call(this, attr);
4822 var translateValues = function(val, start) {
4823 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4824 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4829 var isset = function(prop) {
4830 return (typeof prop !== 'undefined');
4834 * Portions of this file are based on pieces of Yahoo User Interface Library
4835 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4836 * YUI licensed under the BSD License:
4837 * http://developer.yahoo.net/yui/license.txt
4838 * <script type="text/javascript">
4842 Roo.lib.Scroll = function(el, attributes, duration, method) {
4844 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4848 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4852 var superclass = Y.Scroll.superclass;
4853 var proto = Y.Scroll.prototype;
4855 proto.toString = function() {
4856 var el = this.getEl();
4857 var id = el.id || el.tagName;
4858 return ("Scroll " + id);
4861 proto.doMethod = function(attr, start, end) {
4864 if (attr == 'scroll') {
4866 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4867 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4871 val = superclass.doMethod.call(this, attr, start, end);
4876 proto.getAttribute = function(attr) {
4878 var el = this.getEl();
4880 if (attr == 'scroll') {
4881 val = [ el.scrollLeft, el.scrollTop ];
4883 val = superclass.getAttribute.call(this, attr);
4889 proto.setAttribute = function(attr, val, unit) {
4890 var el = this.getEl();
4892 if (attr == 'scroll') {
4893 el.scrollLeft = val[0];
4894 el.scrollTop = val[1];
4896 superclass.setAttribute.call(this, attr, val, unit);
4901 * Originally based of this code... - refactored for Roo...
4902 * https://github.com/aaalsaleh/undo-manager
4905 * @author Abdulrahman Alsaleh
4906 * @copyright 2015 Abdulrahman Alsaleh
4907 * @license MIT License (c)
4909 * Hackily modifyed by alan@roojs.com
4913 * document.undoManager = new UndoManager(limit, document)
4916 * TOTALLY UNTESTED...
4918 * Documentation to be done....
4924 * @class Roo.lib.UndoManager
4925 * An undo manager implementation in JavaScript. It follows the W3C UndoManager and DOM Transaction
4926 * Draft and the undocumented and disabled Mozilla Firefox's UndoManager implementation.
4930 document.undoManager = new UndoManager(limit, document)
4933 * For more information see this blog post with examples:
4934 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4935 - Create Elements using DOM, HTML fragments and Templates</a>.
4937 * @param {Number} limit how far back to go ... use 1000?
4938 * @param {Object} scope usually use document..
4941 Roo.lib.UndoManager = function (limit, undoScopeHost)
4944 this.fireEvent = typeof CustomEvent != 'undefined' && undoScopeHost && undoScopeHost.dispatchEvent;
4948 Roo.lib.UndoManager.prototype = {
4959 * To push and execute a transaction, the method undoManager.transact
4960 * must be called by passing a transaction object as the first argument, and a merge
4961 * flag as the second argument. A transaction object has the following properties:
4965 undoManager.transact({
4967 execute: function() { ... },
4968 undo: function() { ... },
4969 // redo same as execute
4970 redo: function() { this.execute(); }
4973 // merge transaction
4974 undoManager.transact({
4976 execute: function() { ... }, // this will be run...
4977 undo: function() { ... }, // what to do when undo is run.
4978 // redo same as execute
4979 redo: function() { this.execute(); }
4984 * @param {Object} transaction The transaction to add to the stack.
4985 * @return {String} The HTML fragment
4989 transact : function (transaction, merge)
4991 if (arguments.length < 2) {
4992 throw new TypeError('Not enough arguments to UndoManager.transact.');
4995 transaction.execute();
4997 this.stack.splice(0, this.position);
4998 if (merge && this.length) {
4999 this.stack[0].push(transaction);
5001 this.stack.unshift([transaction]);
5006 if (limit && this.stack.length > limit) {
5007 this.length = this.stack.length = limit;
5009 this.length = this.stack.length;
5012 if (this.fireEvent) {
5013 undoScopeHost.dispatchEvent(
5014 new CustomEvent('DOMTransaction', {
5016 transactions: this.stack[0].slice()
5027 if (this.position < this.length) {
5028 for (var i = this.stack[this.position].length - 1; i >= 0; i--) {
5029 this.stack[this.position][i].undo();
5033 if (this.fireEvent) {
5034 undoScopeHost.dispatchEvent(
5035 new CustomEvent('undo', {
5037 transactions: this.stack[this.position - 1].slice()
5049 if (this.position > 0) {
5050 for (var i = 0, n = this.stack[this.position - 1].length; i < n; i++) {
5051 this.stack[this.position - 1][i].redo();
5055 if (this.fireEvent) {
5056 undoScopeHost.dispatchEvent(
5057 new CustomEvent('redo', {
5059 transactions: this.stack[this.position].slice()
5069 item : function (index)
5071 if (index >= 0 && index < this.length) {
5072 return this.stack[index].slice();
5077 clearUndo : function () {
5078 this.stack.length = this.length = this.position;
5081 clearRedo : function () {
5082 this.stack.splice(0, this.position);
5084 this.length = stack.length;
5089 * Ext JS Library 1.1.1
5090 * Copyright(c) 2006-2007, Ext JS, LLC.
5092 * Originally Released Under LGPL - original licence link has changed is not relivant.
5095 * <script type="text/javascript">
5099 // nasty IE9 hack - what a pile of crap that is..
5101 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
5102 Range.prototype.createContextualFragment = function (html) {
5103 var doc = window.document;
5104 var container = doc.createElement("div");
5105 container.innerHTML = html;
5106 var frag = doc.createDocumentFragment(), n;
5107 while ((n = container.firstChild)) {
5108 frag.appendChild(n);
5115 * @class Roo.DomHelper
5116 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
5117 * 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>.
5120 Roo.DomHelper = function(){
5121 var tempTableEl = null;
5122 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
5123 var tableRe = /^table|tbody|tr|td$/i;
5125 // build as innerHTML where available
5127 var createHtml = function(o){
5128 if(typeof o == 'string'){
5137 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
5138 if(attr == "style"){
5140 if(typeof s == "function"){
5143 if(typeof s == "string"){
5144 b += ' style="' + s + '"';
5145 }else if(typeof s == "object"){
5148 if(typeof s[key] != "function"){
5149 b += key + ":" + s[key] + ";";
5156 b += ' class="' + o["cls"] + '"';
5157 }else if(attr == "htmlFor"){
5158 b += ' for="' + o["htmlFor"] + '"';
5160 b += " " + attr + '="' + o[attr] + '"';
5164 if(emptyTags.test(o.tag)){
5168 var cn = o.children || o.cn;
5170 //http://bugs.kde.org/show_bug.cgi?id=71506
5171 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5172 for(var i = 0, len = cn.length; i < len; i++) {
5173 b += createHtml(cn[i], b);
5176 b += createHtml(cn, b);
5182 b += "</" + o.tag + ">";
5189 var createDom = function(o, parentNode){
5191 // defininition craeted..
5193 if (o.ns && o.ns != 'html') {
5195 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
5196 xmlns[o.ns] = o.xmlns;
5199 if (typeof(xmlns[o.ns]) == 'undefined') {
5200 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
5206 if (typeof(o) == 'string') {
5207 return parentNode.appendChild(document.createTextNode(o));
5209 o.tag = o.tag || div;
5210 if (o.ns && Roo.isIE) {
5212 o.tag = o.ns + ':' + o.tag;
5215 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
5216 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
5219 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
5220 attr == "style" || typeof o[attr] == "function") { continue; }
5222 if(attr=="cls" && Roo.isIE){
5223 el.className = o["cls"];
5225 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
5231 Roo.DomHelper.applyStyles(el, o.style);
5232 var cn = o.children || o.cn;
5234 //http://bugs.kde.org/show_bug.cgi?id=71506
5235 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5236 for(var i = 0, len = cn.length; i < len; i++) {
5237 createDom(cn[i], el);
5244 el.innerHTML = o.html;
5247 parentNode.appendChild(el);
5252 var ieTable = function(depth, s, h, e){
5253 tempTableEl.innerHTML = [s, h, e].join('');
5254 var i = -1, el = tempTableEl;
5255 while(++i < depth && el.firstChild){
5261 // kill repeat to save bytes
5265 tbe = '</tbody>'+te,
5271 * Nasty code for IE's broken table implementation
5273 var insertIntoTable = function(tag, where, el, html){
5275 tempTableEl = document.createElement('div');
5280 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
5283 if(where == 'beforebegin'){
5287 before = el.nextSibling;
5290 node = ieTable(4, trs, html, tre);
5292 else if(tag == 'tr'){
5293 if(where == 'beforebegin'){
5296 node = ieTable(3, tbs, html, tbe);
5297 } else if(where == 'afterend'){
5298 before = el.nextSibling;
5300 node = ieTable(3, tbs, html, tbe);
5301 } else{ // INTO a TR
5302 if(where == 'afterbegin'){
5303 before = el.firstChild;
5305 node = ieTable(4, trs, html, tre);
5307 } else if(tag == 'tbody'){
5308 if(where == 'beforebegin'){
5311 node = ieTable(2, ts, html, te);
5312 } else if(where == 'afterend'){
5313 before = el.nextSibling;
5315 node = ieTable(2, ts, html, te);
5317 if(where == 'afterbegin'){
5318 before = el.firstChild;
5320 node = ieTable(3, tbs, html, tbe);
5323 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
5326 if(where == 'afterbegin'){
5327 before = el.firstChild;
5329 node = ieTable(2, ts, html, te);
5331 el.insertBefore(node, before);
5335 // this is a bit like the react update code...
5338 var updateNode = function(from, to)
5340 // should we handle non-standard elements?
5341 Roo.log(["UpdateNode" , from, to]);
5342 if (from.nodeType != to.nodeType) {
5343 Roo.log(["ReplaceChild - mismatch notType" , to, from ]);
5344 from.parentNode.replaceChild(to, from);
5347 if (from.nodeType == 3) {
5348 // assume it's text?!
5349 if (from.data == to.data) {
5352 from.data = to.data;
5356 // assume 'to' doesnt have '1/3 nodetypes!
5357 if (from.nodeType !=1 || from.tagName != to.tagName) {
5358 Roo.log(["ReplaceChild" , from, to ]);
5359 from.parentNode.replaceChild(to, from);
5362 // compare attributes
5363 var ar = Array.from(from.attributes);
5364 for(var i = 0; i< ar.length;i++) {
5365 if (to.hasAttribute(ar[i].name)) {
5368 if (ar[i].name == 'id') { // always keep ids?
5371 from.removeAttribute(ar[i].name);
5374 for(var i = 0; i< ar.length;i++) {
5375 if (from.getAttribute(ar[i].name) == to.getAttribute(ar[i].name)) {
5378 from.setAttribute(ar[i].name, to.getAttribute(ar[i].name));
5381 var far = Array.from(from.childNodes);
5382 var tar = Array.from(to.childNodes);
5383 // if the lengths are different.. then it's probably a editable content change, rather than
5384 // a change of the block definition..
5386 // this did notwork , as our rebuilt nodes did not include ID's so did not match at all.
5387 /*if (from.innerHTML == to.innerHTML) {
5390 if (far.length != tar.length) {
5391 from.innerHTML = to.innerHTML;
5396 for(var i = 0; i < Math.max(tar.length, far.length); i++) {
5397 if (i >= far.length) {
5398 from.appendChild(tar[i]);
5399 Roo.log(["add", tar[i]]);
5401 } else if ( i >= tar.length) {
5402 from.removeChild(far[i]);
5403 Roo.log(["remove", far[i]]);
5406 updateNode(far[i], tar[i]);
5418 /** True to force the use of DOM instead of html fragments @type Boolean */
5422 * Returns the markup for the passed Element(s) config
5423 * @param {Object} o The Dom object spec (and children)
5426 markup : function(o){
5427 return createHtml(o);
5431 * Applies a style specification to an element
5432 * @param {String/HTMLElement} el The element to apply styles to
5433 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
5434 * a function which returns such a specification.
5436 applyStyles : function(el, styles){
5439 if(typeof styles == "string"){
5440 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
5442 while ((matches = re.exec(styles)) != null){
5443 el.setStyle(matches[1], matches[2]);
5445 }else if (typeof styles == "object"){
5446 for (var style in styles){
5447 el.setStyle(style, styles[style]);
5449 }else if (typeof styles == "function"){
5450 Roo.DomHelper.applyStyles(el, styles.call());
5456 * Inserts an HTML fragment into the Dom
5457 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
5458 * @param {HTMLElement} el The context element
5459 * @param {String} html The HTML fragmenet
5460 * @return {HTMLElement} The new node
5462 insertHtml : function(where, el, html){
5463 where = where.toLowerCase();
5464 if(el.insertAdjacentHTML){
5465 if(tableRe.test(el.tagName)){
5467 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
5473 el.insertAdjacentHTML('BeforeBegin', html);
5474 return el.previousSibling;
5476 el.insertAdjacentHTML('AfterBegin', html);
5477 return el.firstChild;
5479 el.insertAdjacentHTML('BeforeEnd', html);
5480 return el.lastChild;
5482 el.insertAdjacentHTML('AfterEnd', html);
5483 return el.nextSibling;
5485 throw 'Illegal insertion point -> "' + where + '"';
5487 var range = el.ownerDocument.createRange();
5491 range.setStartBefore(el);
5492 frag = range.createContextualFragment(html);
5493 el.parentNode.insertBefore(frag, el);
5494 return el.previousSibling;
5497 range.setStartBefore(el.firstChild);
5498 frag = range.createContextualFragment(html);
5499 el.insertBefore(frag, el.firstChild);
5500 return el.firstChild;
5502 el.innerHTML = html;
5503 return el.firstChild;
5507 range.setStartAfter(el.lastChild);
5508 frag = range.createContextualFragment(html);
5509 el.appendChild(frag);
5510 return el.lastChild;
5512 el.innerHTML = html;
5513 return el.lastChild;
5516 range.setStartAfter(el);
5517 frag = range.createContextualFragment(html);
5518 el.parentNode.insertBefore(frag, el.nextSibling);
5519 return el.nextSibling;
5521 throw 'Illegal insertion point -> "' + where + '"';
5525 * Creates new Dom element(s) and inserts them before el
5526 * @param {String/HTMLElement/Element} el The context element
5527 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5528 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5529 * @return {HTMLElement/Roo.Element} The new node
5531 insertBefore : function(el, o, returnElement){
5532 return this.doInsert(el, o, returnElement, "beforeBegin");
5536 * Creates new Dom element(s) and inserts them after el
5537 * @param {String/HTMLElement/Element} el The context element
5538 * @param {Object} o The Dom object spec (and children)
5539 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5540 * @return {HTMLElement/Roo.Element} The new node
5542 insertAfter : function(el, o, returnElement){
5543 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
5547 * Creates new Dom element(s) and inserts them as the first child of el
5548 * @param {String/HTMLElement/Element} el The context element
5549 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5550 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5551 * @return {HTMLElement/Roo.Element} The new node
5553 insertFirst : function(el, o, returnElement){
5554 return this.doInsert(el, o, returnElement, "afterBegin");
5558 doInsert : function(el, o, returnElement, pos, sibling){
5559 el = Roo.getDom(el);
5561 if(this.useDom || o.ns){
5562 newNode = createDom(o, null);
5563 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
5565 var html = createHtml(o);
5566 newNode = this.insertHtml(pos, el, html);
5568 return returnElement ? Roo.get(newNode, true) : newNode;
5572 * Creates new Dom element(s) and appends them to el
5573 * @param {String/HTMLElement/Element} el The context element
5574 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5575 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5576 * @return {HTMLElement/Roo.Element} The new node
5578 append : function(el, o, returnElement){
5579 el = Roo.getDom(el);
5581 if(this.useDom || o.ns){
5582 newNode = createDom(o, null);
5583 el.appendChild(newNode);
5585 var html = createHtml(o);
5586 newNode = this.insertHtml("beforeEnd", el, html);
5588 return returnElement ? Roo.get(newNode, true) : newNode;
5592 * Creates new Dom element(s) and overwrites the contents of el with them
5593 * @param {String/HTMLElement/Element} el The context element
5594 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5595 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5596 * @return {HTMLElement/Roo.Element} The new node
5598 overwrite : function(el, o, returnElement)
5600 el = Roo.getDom(el);
5603 while (el.childNodes.length) {
5604 el.removeChild(el.firstChild);
5608 el.innerHTML = createHtml(o);
5611 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5615 * Creates a new Roo.DomHelper.Template from the Dom object spec
5616 * @param {Object} o The Dom object spec (and children)
5617 * @return {Roo.DomHelper.Template} The new template
5619 createTemplate : function(o){
5620 var html = createHtml(o);
5621 return new Roo.Template(html);
5624 * Updates the first element with the spec from the o (replacing if necessary)
5625 * This iterates through the children, and updates attributes / children etc..
5626 * @param {String/HTMLElement/Element} el The context element
5627 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5630 update : function(el, o)
5632 updateNode(Roo.getDom(el), createDom(o));
5641 * Ext JS Library 1.1.1
5642 * Copyright(c) 2006-2007, Ext JS, LLC.
5644 * Originally Released Under LGPL - original licence link has changed is not relivant.
5647 * <script type="text/javascript">
5651 * @class Roo.Template
5652 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
5653 * For a list of available format functions, see {@link Roo.util.Format}.<br />
5656 var t = new Roo.Template({
5657 html : '<div name="{id}">' +
5658 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
5660 myformat: function (value, allValues) {
5661 return 'XX' + value;
5664 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
5666 * For more information see this blog post with examples:
5667 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
5668 - Create Elements using DOM, HTML fragments and Templates</a>.
5670 * @param {Object} cfg - Configuration object.
5672 Roo.Template = function(cfg){
5674 if(cfg instanceof Array){
5676 }else if(arguments.length > 1){
5677 cfg = Array.prototype.join.call(arguments, "");
5681 if (typeof(cfg) == 'object') {
5692 Roo.Template.prototype = {
5695 * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
5701 * @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..
5702 * it should be fixed so that template is observable...
5706 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
5714 * Returns an HTML fragment of this template with the specified values applied.
5715 * @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'})
5716 * @return {String} The HTML fragment
5721 applyTemplate : function(values){
5722 //Roo.log(["applyTemplate", values]);
5726 return this.compiled(values);
5728 var useF = this.disableFormats !== true;
5729 var fm = Roo.util.Format, tpl = this;
5730 var fn = function(m, name, format, args){
5732 if(format.substr(0, 5) == "this."){
5733 return tpl.call(format.substr(5), values[name], values);
5736 // quoted values are required for strings in compiled templates,
5737 // but for non compiled we need to strip them
5738 // quoted reversed for jsmin
5739 var re = /^\s*['"](.*)["']\s*$/;
5740 args = args.split(',');
5741 for(var i = 0, len = args.length; i < len; i++){
5742 args[i] = args[i].replace(re, "$1");
5744 args = [values[name]].concat(args);
5746 args = [values[name]];
5748 return fm[format].apply(fm, args);
5751 return values[name] !== undefined ? values[name] : "";
5754 return this.html.replace(this.re, fn);
5772 this.loading = true;
5773 this.compiled = false;
5775 var cx = new Roo.data.Connection();
5779 success : function (response) {
5783 _t.set(response.responseText,true);
5789 failure : function(response) {
5790 Roo.log("Template failed to load from " + _t.url);
5797 * Sets the HTML used as the template and optionally compiles it.
5798 * @param {String} html
5799 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
5800 * @return {Roo.Template} this
5802 set : function(html, compile){
5804 this.compiled = false;
5812 * True to disable format functions (defaults to false)
5815 disableFormats : false,
5818 * The regular expression used to match template variables
5822 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
5825 * Compiles the template into an internal function, eliminating the RegEx overhead.
5826 * @return {Roo.Template} this
5828 compile : function(){
5829 var fm = Roo.util.Format;
5830 var useF = this.disableFormats !== true;
5831 var sep = Roo.isGecko ? "+" : ",";
5832 var fn = function(m, name, format, args){
5834 args = args ? ',' + args : "";
5835 if(format.substr(0, 5) != "this."){
5836 format = "fm." + format + '(';
5838 format = 'this.call("'+ format.substr(5) + '", ';
5842 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
5844 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
5847 // branched to use + in gecko and [].join() in others
5849 body = "this.compiled = function(values){ return '" +
5850 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
5853 body = ["this.compiled = function(values){ return ['"];
5854 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
5855 body.push("'].join('');};");
5856 body = body.join('');
5866 // private function used to call members
5867 call : function(fnName, value, allValues){
5868 return this[fnName](value, allValues);
5872 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
5873 * @param {String/HTMLElement/Roo.Element} el The context element
5874 * @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'})
5875 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5876 * @return {HTMLElement/Roo.Element} The new node or Element
5878 insertFirst: function(el, values, returnElement){
5879 return this.doInsert('afterBegin', el, values, returnElement);
5883 * Applies the supplied values to the template and inserts the new node(s) before el.
5884 * @param {String/HTMLElement/Roo.Element} el The context element
5885 * @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'})
5886 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5887 * @return {HTMLElement/Roo.Element} The new node or Element
5889 insertBefore: function(el, values, returnElement){
5890 return this.doInsert('beforeBegin', el, values, returnElement);
5894 * Applies the supplied values to the template and inserts the new node(s) after el.
5895 * @param {String/HTMLElement/Roo.Element} el The context element
5896 * @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'})
5897 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5898 * @return {HTMLElement/Roo.Element} The new node or Element
5900 insertAfter : function(el, values, returnElement){
5901 return this.doInsert('afterEnd', el, values, returnElement);
5905 * Applies the supplied values to the template and appends the new node(s) to el.
5906 * @param {String/HTMLElement/Roo.Element} el The context element
5907 * @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'})
5908 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5909 * @return {HTMLElement/Roo.Element} The new node or Element
5911 append : function(el, values, returnElement){
5912 return this.doInsert('beforeEnd', el, values, returnElement);
5915 doInsert : function(where, el, values, returnEl){
5916 el = Roo.getDom(el);
5917 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
5918 return returnEl ? Roo.get(newNode, true) : newNode;
5922 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
5923 * @param {String/HTMLElement/Roo.Element} el The context element
5924 * @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'})
5925 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5926 * @return {HTMLElement/Roo.Element} The new node or Element
5928 overwrite : function(el, values, returnElement){
5929 el = Roo.getDom(el);
5930 el.innerHTML = this.applyTemplate(values);
5931 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5935 * Alias for {@link #applyTemplate}
5938 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
5941 Roo.DomHelper.Template = Roo.Template;
5944 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
5945 * @param {String/HTMLElement} el A DOM element or its id
5946 * @returns {Roo.Template} The created template
5949 Roo.Template.from = function(el){
5950 el = Roo.getDom(el);
5951 return new Roo.Template(el.value || el.innerHTML);
5954 * Ext JS Library 1.1.1
5955 * Copyright(c) 2006-2007, Ext JS, LLC.
5957 * Originally Released Under LGPL - original licence link has changed is not relivant.
5960 * <script type="text/javascript">
5965 * This is code is also distributed under MIT license for use
5966 * with jQuery and prototype JavaScript libraries.
5969 * @class Roo.DomQuery
5970 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).
5972 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>
5975 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.
5977 <h4>Element Selectors:</h4>
5979 <li> <b>*</b> any element</li>
5980 <li> <b>E</b> an element with the tag E</li>
5981 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
5982 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
5983 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
5984 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
5986 <h4>Attribute Selectors:</h4>
5987 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
5989 <li> <b>E[foo]</b> has an attribute "foo"</li>
5990 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
5991 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
5992 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
5993 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
5994 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
5995 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
5997 <h4>Pseudo Classes:</h4>
5999 <li> <b>E:first-child</b> E is the first child of its parent</li>
6000 <li> <b>E:last-child</b> E is the last child of its parent</li>
6001 <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>
6002 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
6003 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
6004 <li> <b>E:only-child</b> E is the only child of its parent</li>
6005 <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>
6006 <li> <b>E:first</b> the first E in the resultset</li>
6007 <li> <b>E:last</b> the last E in the resultset</li>
6008 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
6009 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
6010 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
6011 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
6012 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
6013 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
6014 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
6015 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
6016 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
6018 <h4>CSS Value Selectors:</h4>
6020 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
6021 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
6022 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
6023 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
6024 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
6025 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
6029 Roo.DomQuery = function(){
6030 var cache = {}, simpleCache = {}, valueCache = {};
6031 var nonSpace = /\S/;
6032 var trimRe = /^\s+|\s+$/g;
6033 var tplRe = /\{(\d+)\}/g;
6034 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
6035 var tagTokenRe = /^(#)?([\w-\*]+)/;
6036 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
6038 function child(p, index){
6040 var n = p.firstChild;
6042 if(n.nodeType == 1){
6053 while((n = n.nextSibling) && n.nodeType != 1);
6058 while((n = n.previousSibling) && n.nodeType != 1);
6062 function children(d){
6063 var n = d.firstChild, ni = -1;
6065 var nx = n.nextSibling;
6066 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
6076 function byClassName(c, a, v){
6080 var r = [], ri = -1, cn;
6081 for(var i = 0, ci; ci = c[i]; i++){
6085 ( (ci instanceof SVGElement) ? ci.className.baseVal : ci.className)
6086 +' ').indexOf(v) != -1){
6093 function attrValue(n, attr){
6094 if(!n.tagName && typeof n.length != "undefined"){
6103 if(attr == "class" || attr == "className"){
6104 return (n instanceof SVGElement) ? n.className.baseVal : n.className;
6106 return n.getAttribute(attr) || n[attr];
6110 function getNodes(ns, mode, tagName){
6111 var result = [], ri = -1, cs;
6115 tagName = tagName || "*";
6116 if(typeof ns.getElementsByTagName != "undefined"){
6120 for(var i = 0, ni; ni = ns[i]; i++){
6121 cs = ni.getElementsByTagName(tagName);
6122 for(var j = 0, ci; ci = cs[j]; j++){
6126 }else if(mode == "/" || mode == ">"){
6127 var utag = tagName.toUpperCase();
6128 for(var i = 0, ni, cn; ni = ns[i]; i++){
6129 cn = ni.children || ni.childNodes;
6130 for(var j = 0, cj; cj = cn[j]; j++){
6131 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
6136 }else if(mode == "+"){
6137 var utag = tagName.toUpperCase();
6138 for(var i = 0, n; n = ns[i]; i++){
6139 while((n = n.nextSibling) && n.nodeType != 1);
6140 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
6144 }else if(mode == "~"){
6145 for(var i = 0, n; n = ns[i]; i++){
6146 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
6155 function concat(a, b){
6159 for(var i = 0, l = b.length; i < l; i++){
6165 function byTag(cs, tagName){
6166 if(cs.tagName || cs == document){
6172 var r = [], ri = -1;
6173 tagName = tagName.toLowerCase();
6174 for(var i = 0, ci; ci = cs[i]; i++){
6175 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
6182 function byId(cs, attr, id){
6183 if(cs.tagName || cs == document){
6189 var r = [], ri = -1;
6190 for(var i = 0,ci; ci = cs[i]; i++){
6191 if(ci && ci.id == id){
6199 function byAttribute(cs, attr, value, op, custom){
6200 var r = [], ri = -1, st = custom=="{";
6201 var f = Roo.DomQuery.operators[op];
6202 for(var i = 0, ci; ci = cs[i]; i++){
6205 a = Roo.DomQuery.getStyle(ci, attr);
6207 else if(attr == "class" || attr == "className"){
6208 a = (ci instanceof SVGElement) ? ci.className.baseVal : ci.className;
6209 }else if(attr == "for"){
6211 }else if(attr == "href"){
6212 a = ci.getAttribute("href", 2);
6214 a = ci.getAttribute(attr);
6216 if((f && f(a, value)) || (!f && a)){
6223 function byPseudo(cs, name, value){
6224 return Roo.DomQuery.pseudos[name](cs, value);
6227 // This is for IE MSXML which does not support expandos.
6228 // IE runs the same speed using setAttribute, however FF slows way down
6229 // and Safari completely fails so they need to continue to use expandos.
6230 var isIE = window.ActiveXObject ? true : false;
6232 // this eval is stop the compressor from
6233 // renaming the variable to something shorter
6235 /** eval:var:batch */
6240 function nodupIEXml(cs){
6242 cs[0].setAttribute("_nodup", d);
6244 for(var i = 1, len = cs.length; i < len; i++){
6246 if(!c.getAttribute("_nodup") != d){
6247 c.setAttribute("_nodup", d);
6251 for(var i = 0, len = cs.length; i < len; i++){
6252 cs[i].removeAttribute("_nodup");
6261 var len = cs.length, c, i, r = cs, cj, ri = -1;
6262 if(!len || typeof cs.nodeType != "undefined" || len == 1){
6265 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
6266 return nodupIEXml(cs);
6270 for(i = 1; c = cs[i]; i++){
6275 for(var j = 0; j < i; j++){
6278 for(j = i+1; cj = cs[j]; j++){
6290 function quickDiffIEXml(c1, c2){
6292 for(var i = 0, len = c1.length; i < len; i++){
6293 c1[i].setAttribute("_qdiff", d);
6296 for(var i = 0, len = c2.length; i < len; i++){
6297 if(c2[i].getAttribute("_qdiff") != d){
6298 r[r.length] = c2[i];
6301 for(var i = 0, len = c1.length; i < len; i++){
6302 c1[i].removeAttribute("_qdiff");
6307 function quickDiff(c1, c2){
6308 var len1 = c1.length;
6312 if(isIE && c1[0].selectSingleNode){
6313 return quickDiffIEXml(c1, c2);
6316 for(var i = 0; i < len1; i++){
6320 for(var i = 0, len = c2.length; i < len; i++){
6321 if(c2[i]._qdiff != d){
6322 r[r.length] = c2[i];
6328 function quickId(ns, mode, root, id){
6330 var d = root.ownerDocument || root;
6331 return d.getElementById(id);
6333 ns = getNodes(ns, mode, "*");
6334 return byId(ns, null, id);
6338 getStyle : function(el, name){
6339 return Roo.fly(el).getStyle(name);
6342 * Compiles a selector/xpath query into a reusable function. The returned function
6343 * takes one parameter "root" (optional), which is the context node from where the query should start.
6344 * @param {String} selector The selector/xpath query
6345 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
6346 * @return {Function}
6348 compile : function(path, type){
6349 type = type || "select";
6351 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
6352 var q = path, mode, lq;
6353 var tk = Roo.DomQuery.matchers;
6354 var tklen = tk.length;
6357 // accept leading mode switch
6358 var lmode = q.match(modeRe);
6359 if(lmode && lmode[1]){
6360 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
6361 q = q.replace(lmode[1], "");
6363 // strip leading slashes
6364 while(path.substr(0, 1)=="/"){
6365 path = path.substr(1);
6368 while(q && lq != q){
6370 var tm = q.match(tagTokenRe);
6371 if(type == "select"){
6374 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
6376 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
6378 q = q.replace(tm[0], "");
6379 }else if(q.substr(0, 1) != '@'){
6380 fn[fn.length] = 'n = getNodes(n, mode, "*");';
6385 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
6387 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
6389 q = q.replace(tm[0], "");
6392 while(!(mm = q.match(modeRe))){
6393 var matched = false;
6394 for(var j = 0; j < tklen; j++){
6396 var m = q.match(t.re);
6398 fn[fn.length] = t.select.replace(tplRe, function(x, i){
6401 q = q.replace(m[0], "");
6406 // prevent infinite loop on bad selector
6408 throw 'Error parsing selector, parsing failed at "' + q + '"';
6412 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
6413 q = q.replace(mm[1], "");
6416 fn[fn.length] = "return nodup(n);\n}";
6419 * list of variables that need from compression as they are used by eval.
6429 * eval:var:byClassName
6431 * eval:var:byAttribute
6432 * eval:var:attrValue
6440 * Selects a group of elements.
6441 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
6442 * @param {Node} root (optional) The start of the query (defaults to document).
6445 select : function(path, root, type){
6446 if(!root || root == document){
6449 if(typeof root == "string"){
6450 root = document.getElementById(root);
6452 var paths = path.split(",");
6454 for(var i = 0, len = paths.length; i < len; i++){
6455 var p = paths[i].replace(trimRe, "");
6457 cache[p] = Roo.DomQuery.compile(p);
6459 throw p + " is not a valid selector";
6462 var result = cache[p](root);
6463 if(result && result != document){
6464 results = results.concat(result);
6467 if(paths.length > 1){
6468 return nodup(results);
6474 * Selects a single element.
6475 * @param {String} selector The selector/xpath query
6476 * @param {Node} root (optional) The start of the query (defaults to document).
6479 selectNode : function(path, root){
6480 return Roo.DomQuery.select(path, root)[0];
6484 * Selects the value of a node, optionally replacing null with the defaultValue.
6485 * @param {String} selector The selector/xpath query
6486 * @param {Node} root (optional) The start of the query (defaults to document).
6487 * @param {String} defaultValue
6489 selectValue : function(path, root, defaultValue){
6490 path = path.replace(trimRe, "");
6491 if(!valueCache[path]){
6492 valueCache[path] = Roo.DomQuery.compile(path, "select");
6494 var n = valueCache[path](root);
6495 n = n[0] ? n[0] : n;
6496 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
6497 return ((v === null||v === undefined||v==='') ? defaultValue : v);
6501 * Selects the value of a node, parsing integers and floats.
6502 * @param {String} selector The selector/xpath query
6503 * @param {Node} root (optional) The start of the query (defaults to document).
6504 * @param {Number} defaultValue
6507 selectNumber : function(path, root, defaultValue){
6508 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
6509 return parseFloat(v);
6513 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
6514 * @param {String/HTMLElement/Array} el An element id, element or array of elements
6515 * @param {String} selector The simple selector to test
6518 is : function(el, ss){
6519 if(typeof el == "string"){
6520 el = document.getElementById(el);
6522 var isArray = (el instanceof Array);
6523 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
6524 return isArray ? (result.length == el.length) : (result.length > 0);
6528 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
6529 * @param {Array} el An array of elements to filter
6530 * @param {String} selector The simple selector to test
6531 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
6532 * the selector instead of the ones that match
6535 filter : function(els, ss, nonMatches){
6536 ss = ss.replace(trimRe, "");
6537 if(!simpleCache[ss]){
6538 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
6540 var result = simpleCache[ss](els);
6541 return nonMatches ? quickDiff(result, els) : result;
6545 * Collection of matching regular expressions and code snippets.
6549 select: 'n = byClassName(n, null, " {1} ");'
6551 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
6552 select: 'n = byPseudo(n, "{1}", "{2}");'
6554 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
6555 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
6558 select: 'n = byId(n, null, "{1}");'
6561 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
6566 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
6567 * 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, > <.
6570 "=" : function(a, v){
6573 "!=" : function(a, v){
6576 "^=" : function(a, v){
6577 return a && a.substr(0, v.length) == v;
6579 "$=" : function(a, v){
6580 return a && a.substr(a.length-v.length) == v;
6582 "*=" : function(a, v){
6583 return a && a.indexOf(v) !== -1;
6585 "%=" : function(a, v){
6586 return (a % v) == 0;
6588 "|=" : function(a, v){
6589 return a && (a == v || a.substr(0, v.length+1) == v+'-');
6591 "~=" : function(a, v){
6592 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
6597 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
6598 * and the argument (if any) supplied in the selector.
6601 "first-child" : function(c){
6602 var r = [], ri = -1, n;
6603 for(var i = 0, ci; ci = n = c[i]; i++){
6604 while((n = n.previousSibling) && n.nodeType != 1);
6612 "last-child" : function(c){
6613 var r = [], ri = -1, n;
6614 for(var i = 0, ci; ci = n = c[i]; i++){
6615 while((n = n.nextSibling) && n.nodeType != 1);
6623 "nth-child" : function(c, a) {
6624 var r = [], ri = -1;
6625 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
6626 var f = (m[1] || 1) - 0, l = m[2] - 0;
6627 for(var i = 0, n; n = c[i]; i++){
6628 var pn = n.parentNode;
6629 if (batch != pn._batch) {
6631 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
6632 if(cn.nodeType == 1){
6639 if (l == 0 || n.nodeIndex == l){
6642 } else if ((n.nodeIndex + l) % f == 0){
6650 "only-child" : function(c){
6651 var r = [], ri = -1;;
6652 for(var i = 0, ci; ci = c[i]; i++){
6653 if(!prev(ci) && !next(ci)){
6660 "empty" : function(c){
6661 var r = [], ri = -1;
6662 for(var i = 0, ci; ci = c[i]; i++){
6663 var cns = ci.childNodes, j = 0, cn, empty = true;
6666 if(cn.nodeType == 1 || cn.nodeType == 3){
6678 "contains" : function(c, v){
6679 var r = [], ri = -1;
6680 for(var i = 0, ci; ci = c[i]; i++){
6681 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
6688 "nodeValue" : function(c, v){
6689 var r = [], ri = -1;
6690 for(var i = 0, ci; ci = c[i]; i++){
6691 if(ci.firstChild && ci.firstChild.nodeValue == v){
6698 "checked" : function(c){
6699 var r = [], ri = -1;
6700 for(var i = 0, ci; ci = c[i]; i++){
6701 if(ci.checked == true){
6708 "not" : function(c, ss){
6709 return Roo.DomQuery.filter(c, ss, true);
6712 "odd" : function(c){
6713 return this["nth-child"](c, "odd");
6716 "even" : function(c){
6717 return this["nth-child"](c, "even");
6720 "nth" : function(c, a){
6721 return c[a-1] || [];
6724 "first" : function(c){
6728 "last" : function(c){
6729 return c[c.length-1] || [];
6732 "has" : function(c, ss){
6733 var s = Roo.DomQuery.select;
6734 var r = [], ri = -1;
6735 for(var i = 0, ci; ci = c[i]; i++){
6736 if(s(ss, ci).length > 0){
6743 "next" : function(c, ss){
6744 var is = Roo.DomQuery.is;
6745 var r = [], ri = -1;
6746 for(var i = 0, ci; ci = c[i]; i++){
6755 "prev" : function(c, ss){
6756 var is = Roo.DomQuery.is;
6757 var r = [], ri = -1;
6758 for(var i = 0, ci; ci = c[i]; i++){
6771 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
6772 * @param {String} path The selector/xpath query
6773 * @param {Node} root (optional) The start of the query (defaults to document).
6778 Roo.query = Roo.DomQuery.select;
6781 * Ext JS Library 1.1.1
6782 * Copyright(c) 2006-2007, Ext JS, LLC.
6784 * Originally Released Under LGPL - original licence link has changed is not relivant.
6787 * <script type="text/javascript">
6791 * @class Roo.util.Observable
6792 * Base class that provides a common interface for publishing events. Subclasses are expected to
6793 * to have a property "events" with all the events defined.<br>
6796 Employee = function(name){
6803 Roo.extend(Employee, Roo.util.Observable);
6805 * @param {Object} config properties to use (incuding events / listeners)
6808 Roo.util.Observable = function(cfg){
6811 this.addEvents(cfg.events || {});
6813 delete cfg.events; // make sure
6816 Roo.apply(this, cfg);
6819 this.on(this.listeners);
6820 delete this.listeners;
6823 Roo.util.Observable.prototype = {
6825 * @cfg {Object} listeners list of events and functions to call for this object,
6829 'click' : function(e) {
6839 * Fires the specified event with the passed parameters (minus the event name).
6840 * @param {String} eventName
6841 * @param {Object...} args Variable number of parameters are passed to handlers
6842 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
6844 fireEvent : function(){
6845 var ce = this.events[arguments[0].toLowerCase()];
6846 if(typeof ce == "object"){
6847 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
6854 filterOptRe : /^(?:scope|delay|buffer|single)$/,
6857 * Appends an event handler to this component
6858 * @param {String} eventName The type of event to listen for
6859 * @param {Function} handler The method the event invokes
6860 * @param {Object} scope (optional) The scope in which to execute the handler
6861 * function. The handler function's "this" context.
6862 * @param {Object} options (optional) An object containing handler configuration
6863 * properties. This may contain any of the following properties:<ul>
6864 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6865 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6866 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6867 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6868 * by the specified number of milliseconds. If the event fires again within that time, the original
6869 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6872 * <b>Combining Options</b><br>
6873 * Using the options argument, it is possible to combine different types of listeners:<br>
6875 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
6877 el.on('click', this.onClick, this, {
6884 * <b>Attaching multiple handlers in 1 call</b><br>
6885 * The method also allows for a single argument to be passed which is a config object containing properties
6886 * which specify multiple handlers.
6895 fn: this.onMouseOver,
6899 fn: this.onMouseOut,
6905 * Or a shorthand syntax which passes the same scope object to all handlers:
6908 'click': this.onClick,
6909 'mouseover': this.onMouseOver,
6910 'mouseout': this.onMouseOut,
6915 addListener : function(eventName, fn, scope, o){
6916 if(typeof eventName == "object"){
6919 if(this.filterOptRe.test(e)){
6922 if(typeof o[e] == "function"){
6924 this.addListener(e, o[e], o.scope, o);
6926 // individual options
6927 this.addListener(e, o[e].fn, o[e].scope, o[e]);
6932 o = (!o || typeof o == "boolean") ? {} : o;
6933 eventName = eventName.toLowerCase();
6934 var ce = this.events[eventName] || true;
6935 if(typeof ce == "boolean"){
6936 ce = new Roo.util.Event(this, eventName);
6937 this.events[eventName] = ce;
6939 ce.addListener(fn, scope, o);
6943 * Removes a listener
6944 * @param {String} eventName The type of event to listen for
6945 * @param {Function} handler The handler to remove
6946 * @param {Object} scope (optional) The scope (this object) for the handler
6948 removeListener : function(eventName, fn, scope){
6949 var ce = this.events[eventName.toLowerCase()];
6950 if(typeof ce == "object"){
6951 ce.removeListener(fn, scope);
6956 * Removes all listeners for this object
6958 purgeListeners : function(){
6959 for(var evt in this.events){
6960 if(typeof this.events[evt] == "object"){
6961 this.events[evt].clearListeners();
6966 relayEvents : function(o, events){
6967 var createHandler = function(ename){
6970 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
6973 for(var i = 0, len = events.length; i < len; i++){
6974 var ename = events[i];
6975 if(!this.events[ename]){
6976 this.events[ename] = true;
6978 o.on(ename, createHandler(ename), this);
6983 * Used to define events on this Observable
6984 * @param {Object} object The object with the events defined
6986 addEvents : function(o){
6990 Roo.applyIf(this.events, o);
6994 * Checks to see if this object has any listeners for a specified event
6995 * @param {String} eventName The name of the event to check for
6996 * @return {Boolean} True if the event is being listened for, else false
6998 hasListener : function(eventName){
6999 var e = this.events[eventName];
7000 return typeof e == "object" && e.listeners.length > 0;
7004 * Appends an event handler to this element (shorthand for addListener)
7005 * @param {String} eventName The type of event to listen for
7006 * @param {Function} handler The method the event invokes
7007 * @param {Object} scope (optional) The scope in which to execute the handler
7008 * function. The handler function's "this" context.
7009 * @param {Object} options (optional)
7012 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
7014 * Removes a listener (shorthand for removeListener)
7015 * @param {String} eventName The type of event to listen for
7016 * @param {Function} handler The handler to remove
7017 * @param {Object} scope (optional) The scope (this object) for the handler
7020 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
7023 * Starts capture on the specified Observable. All events will be passed
7024 * to the supplied function with the event name + standard signature of the event
7025 * <b>before</b> the event is fired. If the supplied function returns false,
7026 * the event will not fire.
7027 * @param {Observable} o The Observable to capture
7028 * @param {Function} fn The function to call
7029 * @param {Object} scope (optional) The scope (this object) for the fn
7032 Roo.util.Observable.capture = function(o, fn, scope){
7033 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
7037 * Removes <b>all</b> added captures from the Observable.
7038 * @param {Observable} o The Observable to release
7041 Roo.util.Observable.releaseCapture = function(o){
7042 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
7047 var createBuffered = function(h, o, scope){
7048 var task = new Roo.util.DelayedTask();
7050 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
7054 var createSingle = function(h, e, fn, scope){
7056 e.removeListener(fn, scope);
7057 return h.apply(scope, arguments);
7061 var createDelayed = function(h, o, scope){
7063 var args = Array.prototype.slice.call(arguments, 0);
7064 setTimeout(function(){
7065 h.apply(scope, args);
7070 Roo.util.Event = function(obj, name){
7073 this.listeners = [];
7076 Roo.util.Event.prototype = {
7077 addListener : function(fn, scope, options){
7078 var o = options || {};
7079 scope = scope || this.obj;
7080 if(!this.isListening(fn, scope)){
7081 var l = {fn: fn, scope: scope, options: o};
7084 h = createDelayed(h, o, scope);
7087 h = createSingle(h, this, fn, scope);
7090 h = createBuffered(h, o, scope);
7093 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
7094 this.listeners.push(l);
7096 this.listeners = this.listeners.slice(0);
7097 this.listeners.push(l);
7102 findListener : function(fn, scope){
7103 scope = scope || this.obj;
7104 var ls = this.listeners;
7105 for(var i = 0, len = ls.length; i < len; i++){
7107 if(l.fn == fn && l.scope == scope){
7114 isListening : function(fn, scope){
7115 return this.findListener(fn, scope) != -1;
7118 removeListener : function(fn, scope){
7120 if((index = this.findListener(fn, scope)) != -1){
7122 this.listeners.splice(index, 1);
7124 this.listeners = this.listeners.slice(0);
7125 this.listeners.splice(index, 1);
7132 clearListeners : function(){
7133 this.listeners = [];
7137 var ls = this.listeners, scope, len = ls.length;
7140 var args = Array.prototype.slice.call(arguments, 0);
7141 for(var i = 0; i < len; i++){
7143 if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
7144 this.firing = false;
7148 this.firing = false;
7155 * Copyright(c) 2007-2017, Roo J Solutions Ltd
7162 * @class Roo.Document
7163 * @extends Roo.util.Observable
7164 * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
7166 * @param {Object} config the methods and properties of the 'base' class for the application.
7168 * Generic Page handler - implement this to start your app..
7171 * MyProject = new Roo.Document({
7173 'load' : true // your events..
7176 'ready' : function() {
7177 // fired on Roo.onReady()
7182 Roo.Document = function(cfg) {
7187 Roo.util.Observable.call(this,cfg);
7191 Roo.onReady(function() {
7192 _this.fireEvent('ready');
7198 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
7200 * Ext JS Library 1.1.1
7201 * Copyright(c) 2006-2007, Ext JS, LLC.
7203 * Originally Released Under LGPL - original licence link has changed is not relivant.
7206 * <script type="text/javascript">
7210 * @class Roo.EventManager
7211 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
7212 * several useful events directly.
7213 * See {@link Roo.EventObject} for more details on normalized event objects.
7216 Roo.EventManager = function(){
7217 var docReadyEvent, docReadyProcId, docReadyState = false;
7218 var resizeEvent, resizeTask, textEvent, textSize;
7219 var E = Roo.lib.Event;
7220 var D = Roo.lib.Dom;
7225 var fireDocReady = function(){
7227 docReadyState = true;
7230 clearInterval(docReadyProcId);
7232 if(Roo.isGecko || Roo.isOpera) {
7233 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
7236 var defer = document.getElementById("ie-deferred-loader");
7238 defer.onreadystatechange = null;
7239 defer.parentNode.removeChild(defer);
7243 docReadyEvent.fire();
7244 docReadyEvent.clearListeners();
7249 var initDocReady = function(){
7250 docReadyEvent = new Roo.util.Event();
7251 if(Roo.isGecko || Roo.isOpera) {
7252 document.addEventListener("DOMContentLoaded", fireDocReady, false);
7254 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
7255 var defer = document.getElementById("ie-deferred-loader");
7256 defer.onreadystatechange = function(){
7257 if(this.readyState == "complete"){
7261 }else if(Roo.isSafari){
7262 docReadyProcId = setInterval(function(){
7263 var rs = document.readyState;
7264 if(rs == "complete") {
7269 // no matter what, make sure it fires on load
7270 E.on(window, "load", fireDocReady);
7273 var createBuffered = function(h, o){
7274 var task = new Roo.util.DelayedTask(h);
7276 // create new event object impl so new events don't wipe out properties
7277 e = new Roo.EventObjectImpl(e);
7278 task.delay(o.buffer, h, null, [e]);
7282 var createSingle = function(h, el, ename, fn){
7284 Roo.EventManager.removeListener(el, ename, fn);
7289 var createDelayed = function(h, o){
7291 // create new event object impl so new events don't wipe out properties
7292 e = new Roo.EventObjectImpl(e);
7293 setTimeout(function(){
7298 var transitionEndVal = false;
7300 var transitionEnd = function()
7302 if (transitionEndVal) {
7303 return transitionEndVal;
7305 var el = document.createElement('div');
7307 var transEndEventNames = {
7308 WebkitTransition : 'webkitTransitionEnd',
7309 MozTransition : 'transitionend',
7310 OTransition : 'oTransitionEnd otransitionend',
7311 transition : 'transitionend'
7314 for (var name in transEndEventNames) {
7315 if (el.style[name] !== undefined) {
7316 transitionEndVal = transEndEventNames[name];
7317 return transitionEndVal ;
7324 var listen = function(element, ename, opt, fn, scope)
7326 var o = (!opt || typeof opt == "boolean") ? {} : opt;
7327 fn = fn || o.fn; scope = scope || o.scope;
7328 var el = Roo.getDom(element);
7332 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
7335 if (ename == 'transitionend') {
7336 ename = transitionEnd();
7338 var h = function(e){
7339 e = Roo.EventObject.setEvent(e);
7342 t = e.getTarget(o.delegate, el);
7349 if(o.stopEvent === true){
7352 if(o.preventDefault === true){
7355 if(o.stopPropagation === true){
7356 e.stopPropagation();
7359 if(o.normalized === false){
7363 fn.call(scope || el, e, t, o);
7366 h = createDelayed(h, o);
7369 h = createSingle(h, el, ename, fn);
7372 h = createBuffered(h, o);
7375 fn._handlers = fn._handlers || [];
7378 fn._handlers.push([Roo.id(el), ename, h]);
7382 E.on(el, ename, h); // this adds the actuall listener to the object..
7385 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
7386 el.addEventListener("DOMMouseScroll", h, false);
7387 E.on(window, 'unload', function(){
7388 el.removeEventListener("DOMMouseScroll", h, false);
7391 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7392 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
7397 var stopListening = function(el, ename, fn){
7398 var id = Roo.id(el), hds = fn._handlers, hd = fn;
7400 for(var i = 0, len = hds.length; i < len; i++){
7402 if(h[0] == id && h[1] == ename){
7409 E.un(el, ename, hd);
7410 el = Roo.getDom(el);
7411 if(ename == "mousewheel" && el.addEventListener){
7412 el.removeEventListener("DOMMouseScroll", hd, false);
7414 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7415 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
7419 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
7426 * @scope Roo.EventManager
7431 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
7432 * object with a Roo.EventObject
7433 * @param {Function} fn The method the event invokes
7434 * @param {Object} scope An object that becomes the scope of the handler
7435 * @param {boolean} override If true, the obj passed in becomes
7436 * the execution scope of the listener
7437 * @return {Function} The wrapped function
7440 wrap : function(fn, scope, override){
7442 Roo.EventObject.setEvent(e);
7443 fn.call(override ? scope || window : window, Roo.EventObject, scope);
7448 * Appends an event handler to an element (shorthand for addListener)
7449 * @param {String/HTMLElement} element The html element or id to assign the
7450 * @param {String} eventName The type of event to listen for
7451 * @param {Function} handler The method the event invokes
7452 * @param {Object} scope (optional) The scope in which to execute the handler
7453 * function. The handler function's "this" context.
7454 * @param {Object} options (optional) An object containing handler configuration
7455 * properties. This may contain any of the following properties:<ul>
7456 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7457 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7458 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7459 * <li>preventDefault {Boolean} True to prevent the default action</li>
7460 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7461 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7462 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7463 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7464 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7465 * by the specified number of milliseconds. If the event fires again within that time, the original
7466 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7469 * <b>Combining Options</b><br>
7470 * Using the options argument, it is possible to combine different types of listeners:<br>
7472 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7474 el.on('click', this.onClick, this, {
7481 * <b>Attaching multiple handlers in 1 call</b><br>
7482 * The method also allows for a single argument to be passed which is a config object containing properties
7483 * which specify multiple handlers.
7493 fn: this.onMouseOver
7502 * Or a shorthand syntax:<br>
7505 'click' : this.onClick,
7506 'mouseover' : this.onMouseOver,
7507 'mouseout' : this.onMouseOut
7511 addListener : function(element, eventName, fn, scope, options){
7512 if(typeof eventName == "object"){
7518 if(typeof o[e] == "function"){
7520 listen(element, e, o, o[e], o.scope);
7522 // individual options
7523 listen(element, e, o[e]);
7528 return listen(element, eventName, options, fn, scope);
7532 * Removes an event handler
7534 * @param {String/HTMLElement} element The id or html element to remove the
7536 * @param {String} eventName The type of event
7537 * @param {Function} fn
7538 * @return {Boolean} True if a listener was actually removed
7540 removeListener : function(element, eventName, fn){
7541 return stopListening(element, eventName, fn);
7545 * Fires when the document is ready (before onload and before images are loaded). Can be
7546 * accessed shorthanded Roo.onReady().
7547 * @param {Function} fn The method the event invokes
7548 * @param {Object} scope An object that becomes the scope of the handler
7549 * @param {boolean} options
7551 onDocumentReady : function(fn, scope, options){
7552 if(docReadyState){ // if it already fired
7553 docReadyEvent.addListener(fn, scope, options);
7554 docReadyEvent.fire();
7555 docReadyEvent.clearListeners();
7561 docReadyEvent.addListener(fn, scope, options);
7565 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
7566 * @param {Function} fn The method the event invokes
7567 * @param {Object} scope An object that becomes the scope of the handler
7568 * @param {boolean} options
7570 onWindowResize : function(fn, scope, options)
7573 resizeEvent = new Roo.util.Event();
7574 resizeTask = new Roo.util.DelayedTask(function(){
7575 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7577 E.on(window, "resize", function()
7580 resizeTask.delay(50);
7582 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7586 resizeEvent.addListener(fn, scope, options);
7590 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
7591 * @param {Function} fn The method the event invokes
7592 * @param {Object} scope An object that becomes the scope of the handler
7593 * @param {boolean} options
7595 onTextResize : function(fn, scope, options){
7597 textEvent = new Roo.util.Event();
7598 var textEl = new Roo.Element(document.createElement('div'));
7599 textEl.dom.className = 'x-text-resize';
7600 textEl.dom.innerHTML = 'X';
7601 textEl.appendTo(document.body);
7602 textSize = textEl.dom.offsetHeight;
7603 setInterval(function(){
7604 if(textEl.dom.offsetHeight != textSize){
7605 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
7607 }, this.textResizeInterval);
7609 textEvent.addListener(fn, scope, options);
7613 * Removes the passed window resize listener.
7614 * @param {Function} fn The method the event invokes
7615 * @param {Object} scope The scope of handler
7617 removeResizeListener : function(fn, scope){
7619 resizeEvent.removeListener(fn, scope);
7624 fireResize : function(){
7626 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7630 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
7634 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
7636 textResizeInterval : 50
7641 * @scopeAlias pub=Roo.EventManager
7645 * Appends an event handler to an element (shorthand for addListener)
7646 * @param {String/HTMLElement} element The html element or id to assign the
7647 * @param {String} eventName The type of event to listen for
7648 * @param {Function} handler The method the event invokes
7649 * @param {Object} scope (optional) The scope in which to execute the handler
7650 * function. The handler function's "this" context.
7651 * @param {Object} options (optional) An object containing handler configuration
7652 * properties. This may contain any of the following properties:<ul>
7653 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7654 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7655 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7656 * <li>preventDefault {Boolean} True to prevent the default action</li>
7657 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7658 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7659 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7660 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7661 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7662 * by the specified number of milliseconds. If the event fires again within that time, the original
7663 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7666 * <b>Combining Options</b><br>
7667 * Using the options argument, it is possible to combine different types of listeners:<br>
7669 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7671 el.on('click', this.onClick, this, {
7678 * <b>Attaching multiple handlers in 1 call</b><br>
7679 * The method also allows for a single argument to be passed which is a config object containing properties
7680 * which specify multiple handlers.
7690 fn: this.onMouseOver
7699 * Or a shorthand syntax:<br>
7702 'click' : this.onClick,
7703 'mouseover' : this.onMouseOver,
7704 'mouseout' : this.onMouseOut
7708 pub.on = pub.addListener;
7709 pub.un = pub.removeListener;
7711 pub.stoppedMouseDownEvent = new Roo.util.Event();
7715 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
7716 * @param {Function} fn The method the event invokes
7717 * @param {Object} scope An object that becomes the scope of the handler
7718 * @param {boolean} override If true, the obj passed in becomes
7719 * the execution scope of the listener
7723 Roo.onReady = Roo.EventManager.onDocumentReady;
7725 Roo.onReady(function(){
7726 var bd = Roo.get(document.body);
7731 : Roo.isIE11 ? "roo-ie11"
7732 : Roo.isEdge ? "roo-edge"
7733 : Roo.isGecko ? "roo-gecko"
7734 : Roo.isOpera ? "roo-opera"
7735 : Roo.isSafari ? "roo-safari" : ""];
7738 cls.push("roo-mac");
7741 cls.push("roo-linux");
7744 cls.push("roo-ios");
7747 cls.push("roo-touch");
7749 if(Roo.isBorderBox){
7750 cls.push('roo-border-box');
7752 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
7753 var p = bd.dom.parentNode;
7755 p.className += ' roo-strict';
7758 bd.addClass(cls.join(' '));
7762 * @class Roo.EventObject
7763 * EventObject exposes the Yahoo! UI Event functionality directly on the object
7764 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
7767 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
7769 var target = e.getTarget();
7772 var myDiv = Roo.get("myDiv");
7773 myDiv.on("click", handleClick);
7775 Roo.EventManager.on("myDiv", 'click', handleClick);
7776 Roo.EventManager.addListener("myDiv", 'click', handleClick);
7780 Roo.EventObject = function(){
7782 var E = Roo.lib.Event;
7784 // safari keypress events for special keys return bad keycodes
7787 63235 : 39, // right
7790 63276 : 33, // page up
7791 63277 : 34, // page down
7792 63272 : 46, // delete
7797 // normalize button clicks
7798 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
7799 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
7801 Roo.EventObjectImpl = function(e){
7803 this.setEvent(e.browserEvent || e);
7806 Roo.EventObjectImpl.prototype = {
7808 * Used to fix doc tools.
7809 * @scope Roo.EventObject.prototype
7815 /** The normal browser event */
7816 browserEvent : null,
7817 /** The button pressed in a mouse event */
7819 /** True if the shift key was down during the event */
7821 /** True if the control key was down during the event */
7823 /** True if the alt key was down during the event */
7882 setEvent : function(e){
7883 if(e == this || (e && e.browserEvent)){ // already wrapped
7886 this.browserEvent = e;
7888 // normalize buttons
7889 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
7890 if(e.type == 'click' && this.button == -1){
7894 this.shiftKey = e.shiftKey;
7895 // mac metaKey behaves like ctrlKey
7896 this.ctrlKey = e.ctrlKey || e.metaKey;
7897 this.altKey = e.altKey;
7898 // in getKey these will be normalized for the mac
7899 this.keyCode = e.keyCode;
7900 // keyup warnings on firefox.
7901 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
7902 // cache the target for the delayed and or buffered events
7903 this.target = E.getTarget(e);
7905 this.xy = E.getXY(e);
7908 this.shiftKey = false;
7909 this.ctrlKey = false;
7910 this.altKey = false;
7920 * Stop the event (preventDefault and stopPropagation)
7922 stopEvent : function(){
7923 if(this.browserEvent){
7924 if(this.browserEvent.type == 'mousedown'){
7925 Roo.EventManager.stoppedMouseDownEvent.fire(this);
7927 E.stopEvent(this.browserEvent);
7932 * Prevents the browsers default handling of the event.
7934 preventDefault : function(){
7935 if(this.browserEvent){
7936 E.preventDefault(this.browserEvent);
7941 isNavKeyPress : function(){
7942 var k = this.keyCode;
7943 k = Roo.isSafari ? (safariKeys[k] || k) : k;
7944 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
7947 isSpecialKey : function(){
7948 var k = this.keyCode;
7949 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
7950 (k == 16) || (k == 17) ||
7951 (k >= 18 && k <= 20) ||
7952 (k >= 33 && k <= 35) ||
7953 (k >= 36 && k <= 39) ||
7954 (k >= 44 && k <= 45);
7957 * Cancels bubbling of the event.
7959 stopPropagation : function(){
7960 if(this.browserEvent){
7961 if(this.type == 'mousedown'){
7962 Roo.EventManager.stoppedMouseDownEvent.fire(this);
7964 E.stopPropagation(this.browserEvent);
7969 * Gets the key code for the event.
7972 getCharCode : function(){
7973 return this.charCode || this.keyCode;
7977 * Returns a normalized keyCode for the event.
7978 * @return {Number} The key code
7980 getKey : function(){
7981 var k = this.keyCode || this.charCode;
7982 return Roo.isSafari ? (safariKeys[k] || k) : k;
7986 * Gets the x coordinate of the event.
7989 getPageX : function(){
7994 * Gets the y coordinate of the event.
7997 getPageY : function(){
8002 * Gets the time of the event.
8005 getTime : function(){
8006 if(this.browserEvent){
8007 return E.getTime(this.browserEvent);
8013 * Gets the page coordinates of the event.
8014 * @return {Array} The xy values like [x, y]
8021 * Gets the target for the event.
8022 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
8023 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8024 search as a number or element (defaults to 10 || document.body)
8025 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8026 * @return {HTMLelement}
8028 getTarget : function(selector, maxDepth, returnEl){
8029 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
8032 * Gets the related target.
8033 * @return {HTMLElement}
8035 getRelatedTarget : function(){
8036 if(this.browserEvent){
8037 return E.getRelatedTarget(this.browserEvent);
8043 * Normalizes mouse wheel delta across browsers
8044 * @return {Number} The delta
8046 getWheelDelta : function(){
8047 var e = this.browserEvent;
8049 if(e.wheelDelta){ /* IE/Opera. */
8050 delta = e.wheelDelta/120;
8051 }else if(e.detail){ /* Mozilla case. */
8052 delta = -e.detail/3;
8058 * Returns true if the control, meta, shift or alt key was pressed during this event.
8061 hasModifier : function(){
8062 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
8066 * Returns true if the target of this event equals el or is a child of el
8067 * @param {String/HTMLElement/Element} el
8068 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
8071 within : function(el, related){
8072 var t = this[related ? "getRelatedTarget" : "getTarget"]();
8073 return t && Roo.fly(el).contains(t);
8076 getPoint : function(){
8077 return new Roo.lib.Point(this.xy[0], this.xy[1]);
8081 return new Roo.EventObjectImpl();
8086 * Ext JS Library 1.1.1
8087 * Copyright(c) 2006-2007, Ext JS, LLC.
8089 * Originally Released Under LGPL - original licence link has changed is not relivant.
8092 * <script type="text/javascript">
8096 // was in Composite Element!??!?!
8099 var D = Roo.lib.Dom;
8100 var E = Roo.lib.Event;
8101 var A = Roo.lib.Anim;
8103 // local style camelizing for speed
8105 var camelRe = /(-[a-z])/gi;
8106 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
8107 var view = document.defaultView;
8110 * @class Roo.Element
8111 * Represents an Element in the DOM.<br><br>
8114 var el = Roo.get("my-div");
8117 var el = getEl("my-div");
8119 // or with a DOM element
8120 var el = Roo.get(myDivElement);
8122 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
8123 * each call instead of constructing a new one.<br><br>
8124 * <b>Animations</b><br />
8125 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
8126 * should either be a boolean (true) or an object literal with animation options. The animation options are:
8128 Option Default Description
8129 --------- -------- ---------------------------------------------
8130 duration .35 The duration of the animation in seconds
8131 easing easeOut The YUI easing method
8132 callback none A function to execute when the anim completes
8133 scope this The scope (this) of the callback function
8135 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
8136 * manipulate the animation. Here's an example:
8138 var el = Roo.get("my-div");
8143 // default animation
8144 el.setWidth(100, true);
8146 // animation with some options set
8153 // using the "anim" property to get the Anim object
8159 el.setWidth(100, opt);
8161 if(opt.anim.isAnimated()){
8165 * <b> Composite (Collections of) Elements</b><br />
8166 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
8167 * @constructor Create a new Element directly.
8168 * @param {String/HTMLElement} element
8169 * @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).
8171 Roo.Element = function(element, forceNew)
8173 var dom = typeof element == "string" ?
8174 document.getElementById(element) : element;
8176 this.listeners = {};
8178 if(!dom){ // invalid id/element
8182 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
8183 return Roo.Element.cache[id];
8193 * The DOM element ID
8196 this.id = id || Roo.id(dom);
8198 return this; // assumed for cctor?
8201 var El = Roo.Element;
8205 * The element's default display mode (defaults to "")
8208 originalDisplay : "",
8211 // note this is overridden in BS version..
8214 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
8220 * Sets the element's visibility mode. When setVisible() is called it
8221 * will use this to determine whether to set the visibility or the display property.
8222 * @param visMode Element.VISIBILITY or Element.DISPLAY
8223 * @return {Roo.Element} this
8225 setVisibilityMode : function(visMode){
8226 this.visibilityMode = visMode;
8230 * Convenience method for setVisibilityMode(Element.DISPLAY)
8231 * @param {String} display (optional) What to set display to when visible
8232 * @return {Roo.Element} this
8234 enableDisplayMode : function(display){
8235 this.setVisibilityMode(El.DISPLAY);
8236 if(typeof display != "undefined") { this.originalDisplay = display; }
8241 * 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)
8242 * @param {String} selector The simple selector to test
8243 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8244 search as a number or element (defaults to 10 || document.body)
8245 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8246 * @return {HTMLElement} The matching DOM node (or null if no match was found)
8248 findParent : function(simpleSelector, maxDepth, returnEl){
8249 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
8250 maxDepth = maxDepth || 50;
8251 if(typeof maxDepth != "number"){
8252 stopEl = Roo.getDom(maxDepth);
8255 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
8256 if(dq.is(p, simpleSelector)){
8257 return returnEl ? Roo.get(p) : p;
8267 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
8268 * @param {String} selector The simple selector to test
8269 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8270 search as a number or element (defaults to 10 || document.body)
8271 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8272 * @return {HTMLElement} The matching DOM node (or null if no match was found)
8274 findParentNode : function(simpleSelector, maxDepth, returnEl){
8275 var p = Roo.fly(this.dom.parentNode, '_internal');
8276 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
8280 * Looks at the scrollable parent element
8282 findScrollableParent : function()
8284 var overflowRegex = /(auto|scroll)/;
8286 if(this.getStyle('position') === 'fixed'){
8287 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8290 var excludeStaticParent = this.getStyle('position') === "absolute";
8292 for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
8294 if (excludeStaticParent && parent.getStyle('position') === "static") {
8298 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
8302 if(parent.dom.nodeName.toLowerCase() == 'body'){
8303 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8307 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8311 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
8312 * This is a shortcut for findParentNode() that always returns an Roo.Element.
8313 * @param {String} selector The simple selector to test
8314 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8315 search as a number or element (defaults to 10 || document.body)
8316 * @return {Roo.Element} The matching DOM node (or null if no match was found)
8318 up : function(simpleSelector, maxDepth){
8319 return this.findParentNode(simpleSelector, maxDepth, true);
8325 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
8326 * @param {String} selector The simple selector to test
8327 * @return {Boolean} True if this element matches the selector, else false
8329 is : function(simpleSelector){
8330 return Roo.DomQuery.is(this.dom, simpleSelector);
8334 * Perform animation on this element.
8335 * @param {Object} args The YUI animation control args
8336 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
8337 * @param {Function} onComplete (optional) Function to call when animation completes
8338 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
8339 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
8340 * @return {Roo.Element} this
8342 animate : function(args, duration, onComplete, easing, animType){
8343 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
8348 * @private Internal animation call
8350 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
8351 animType = animType || 'run';
8353 var anim = Roo.lib.Anim[animType](
8355 (opt.duration || defaultDur) || .35,
8356 (opt.easing || defaultEase) || 'easeOut',
8358 Roo.callback(cb, this);
8359 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
8367 // private legacy anim prep
8368 preanim : function(a, i){
8369 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
8373 * Removes worthless text nodes
8374 * @param {Boolean} forceReclean (optional) By default the element
8375 * keeps track if it has been cleaned already so
8376 * you can call this over and over. However, if you update the element and
8377 * need to force a reclean, you can pass true.
8379 clean : function(forceReclean){
8380 if(this.isCleaned && forceReclean !== true){
8384 var d = this.dom, n = d.firstChild, ni = -1;
8386 var nx = n.nextSibling;
8387 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
8394 this.isCleaned = true;
8399 calcOffsetsTo : function(el){
8402 var restorePos = false;
8403 if(el.getStyle('position') == 'static'){
8404 el.position('relative');
8409 while(op && op != d && op.tagName != 'HTML'){
8412 op = op.offsetParent;
8415 el.position('static');
8421 * Scrolls this element into view within the passed container.
8422 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
8423 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
8424 * @return {Roo.Element} this
8426 scrollIntoView : function(container, hscroll){
8427 var c = Roo.getDom(container) || document.body;
8430 var o = this.calcOffsetsTo(c),
8433 b = t+el.offsetHeight,
8434 r = l+el.offsetWidth;
8436 var ch = c.clientHeight;
8437 var ct = parseInt(c.scrollTop, 10);
8438 var cl = parseInt(c.scrollLeft, 10);
8440 var cr = cl + c.clientWidth;
8448 if(hscroll !== false){
8452 c.scrollLeft = r-c.clientWidth;
8459 scrollChildIntoView : function(child, hscroll){
8460 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
8464 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
8465 * the new height may not be available immediately.
8466 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
8467 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
8468 * @param {Function} onComplete (optional) Function to call when animation completes
8469 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
8470 * @return {Roo.Element} this
8472 autoHeight : function(animate, duration, onComplete, easing){
8473 var oldHeight = this.getHeight();
8475 this.setHeight(1); // force clipping
8476 setTimeout(function(){
8477 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
8479 this.setHeight(height);
8481 if(typeof onComplete == "function"){
8485 this.setHeight(oldHeight); // restore original height
8486 this.setHeight(height, animate, duration, function(){
8488 if(typeof onComplete == "function") { onComplete(); }
8489 }.createDelegate(this), easing);
8491 }.createDelegate(this), 0);
8496 * Returns true if this element is an ancestor of the passed element
8497 * @param {HTMLElement/String} el The element to check
8498 * @return {Boolean} True if this element is an ancestor of el, else false
8500 contains : function(el){
8501 if(!el){return false;}
8502 return D.isAncestor(this.dom, el.dom ? el.dom : el);
8506 * Checks whether the element is currently visible using both visibility and display properties.
8507 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
8508 * @return {Boolean} True if the element is currently visible, else false
8510 isVisible : function(deep) {
8511 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
8512 if(deep !== true || !vis){
8515 var p = this.dom.parentNode;
8516 while(p && p.tagName.toLowerCase() != "body"){
8517 if(!Roo.fly(p, '_isVisible').isVisible()){
8526 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
8527 * @param {String} selector The CSS selector
8528 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
8529 * @return {CompositeElement/CompositeElementLite} The composite element
8531 select : function(selector, unique){
8532 return El.select(selector, unique, this.dom);
8536 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
8537 * @param {String} selector The CSS selector
8538 * @return {Array} An array of the matched nodes
8540 query : function(selector, unique){
8541 return Roo.DomQuery.select(selector, this.dom);
8545 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
8546 * @param {String} selector The CSS selector
8547 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8548 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8550 child : function(selector, returnDom){
8551 var n = Roo.DomQuery.selectNode(selector, this.dom);
8552 return returnDom ? n : Roo.get(n);
8556 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
8557 * @param {String} selector The CSS selector
8558 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8559 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8561 down : function(selector, returnDom){
8562 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
8563 return returnDom ? n : Roo.get(n);
8567 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
8568 * @param {String} group The group the DD object is member of
8569 * @param {Object} config The DD config object
8570 * @param {Object} overrides An object containing methods to override/implement on the DD object
8571 * @return {Roo.dd.DD} The DD object
8573 initDD : function(group, config, overrides){
8574 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
8575 return Roo.apply(dd, overrides);
8579 * Initializes a {@link Roo.dd.DDProxy} object for this element.
8580 * @param {String} group The group the DDProxy object is member of
8581 * @param {Object} config The DDProxy config object
8582 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
8583 * @return {Roo.dd.DDProxy} The DDProxy object
8585 initDDProxy : function(group, config, overrides){
8586 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
8587 return Roo.apply(dd, overrides);
8591 * Initializes a {@link Roo.dd.DDTarget} object for this element.
8592 * @param {String} group The group the DDTarget object is member of
8593 * @param {Object} config The DDTarget config object
8594 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
8595 * @return {Roo.dd.DDTarget} The DDTarget object
8597 initDDTarget : function(group, config, overrides){
8598 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
8599 return Roo.apply(dd, overrides);
8603 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
8604 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
8605 * @param {Boolean} visible Whether the element is visible
8606 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8607 * @return {Roo.Element} this
8609 setVisible : function(visible, animate){
8611 if(this.visibilityMode == El.DISPLAY){
8612 this.setDisplayed(visible);
8615 this.dom.style.visibility = visible ? "visible" : "hidden";
8618 // closure for composites
8620 var visMode = this.visibilityMode;
8622 this.setOpacity(.01);
8623 this.setVisible(true);
8625 this.anim({opacity: { to: (visible?1:0) }},
8626 this.preanim(arguments, 1),
8627 null, .35, 'easeIn', function(){
8629 if(visMode == El.DISPLAY){
8630 dom.style.display = "none";
8632 dom.style.visibility = "hidden";
8634 Roo.get(dom).setOpacity(1);
8642 * Returns true if display is not "none"
8645 isDisplayed : function() {
8646 return this.getStyle("display") != "none";
8650 * Toggles the element's visibility or display, depending on visibility mode.
8651 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8652 * @return {Roo.Element} this
8654 toggle : function(animate){
8655 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
8660 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
8661 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
8662 * @return {Roo.Element} this
8664 setDisplayed : function(value) {
8665 if(typeof value == "boolean"){
8666 value = value ? this.originalDisplay : "none";
8668 this.setStyle("display", value);
8673 * Tries to focus the element. Any exceptions are caught and ignored.
8674 * @return {Roo.Element} this
8676 focus : function() {
8684 * Tries to blur the element. Any exceptions are caught and ignored.
8685 * @return {Roo.Element} this
8695 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
8696 * @param {String/Array} className The CSS class to add, or an array of classes
8697 * @return {Roo.Element} this
8699 addClass : function(className){
8700 if(className instanceof Array){
8701 for(var i = 0, len = className.length; i < len; i++) {
8702 this.addClass(className[i]);
8705 if(className && !this.hasClass(className)){
8706 if (this.dom instanceof SVGElement) {
8707 this.dom.className.baseVal =this.dom.className.baseVal + " " + className;
8709 this.dom.className = this.dom.className + " " + className;
8717 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
8718 * @param {String/Array} className The CSS class to add, or an array of classes
8719 * @return {Roo.Element} this
8721 radioClass : function(className){
8722 var siblings = this.dom.parentNode.childNodes;
8723 for(var i = 0; i < siblings.length; i++) {
8724 var s = siblings[i];
8725 if(s.nodeType == 1){
8726 Roo.get(s).removeClass(className);
8729 this.addClass(className);
8734 * Removes one or more CSS classes from the element.
8735 * @param {String/Array} className The CSS class to remove, or an array of classes
8736 * @return {Roo.Element} this
8738 removeClass : function(className){
8740 var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
8741 if(!className || !cn){
8744 if(className instanceof Array){
8745 for(var i = 0, len = className.length; i < len; i++) {
8746 this.removeClass(className[i]);
8749 if(this.hasClass(className)){
8750 var re = this.classReCache[className];
8752 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
8753 this.classReCache[className] = re;
8755 if (this.dom instanceof SVGElement) {
8756 this.dom.className.baseVal = cn.replace(re, " ");
8758 this.dom.className = cn.replace(re, " ");
8769 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
8770 * @param {String} className The CSS class to toggle
8771 * @return {Roo.Element} this
8773 toggleClass : function(className){
8774 if(this.hasClass(className)){
8775 this.removeClass(className);
8777 this.addClass(className);
8783 * Checks if the specified CSS class exists on this element's DOM node.
8784 * @param {String} className The CSS class to check for
8785 * @return {Boolean} True if the class exists, else false
8787 hasClass : function(className){
8788 if (this.dom instanceof SVGElement) {
8789 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1;
8791 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
8795 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
8796 * @param {String} oldClassName The CSS class to replace
8797 * @param {String} newClassName The replacement CSS class
8798 * @return {Roo.Element} this
8800 replaceClass : function(oldClassName, newClassName){
8801 this.removeClass(oldClassName);
8802 this.addClass(newClassName);
8807 * Returns an object with properties matching the styles requested.
8808 * For example, el.getStyles('color', 'font-size', 'width') might return
8809 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
8810 * @param {String} style1 A style name
8811 * @param {String} style2 A style name
8812 * @param {String} etc.
8813 * @return {Object} The style object
8815 getStyles : function(){
8816 var a = arguments, len = a.length, r = {};
8817 for(var i = 0; i < len; i++){
8818 r[a[i]] = this.getStyle(a[i]);
8824 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
8825 * @param {String} property The style property whose value is returned.
8826 * @return {String} The current value of the style property for this element.
8828 getStyle : function(){
8829 return view && view.getComputedStyle ?
8831 var el = this.dom, v, cs, camel;
8832 if(prop == 'float'){
8835 if(el.style && (v = el.style[prop])){
8838 if(cs = view.getComputedStyle(el, "")){
8839 if(!(camel = propCache[prop])){
8840 camel = propCache[prop] = prop.replace(camelRe, camelFn);
8847 var el = this.dom, v, cs, camel;
8848 if(prop == 'opacity'){
8849 if(typeof el.style.filter == 'string'){
8850 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
8852 var fv = parseFloat(m[1]);
8854 return fv ? fv / 100 : 0;
8859 }else if(prop == 'float'){
8860 prop = "styleFloat";
8862 if(!(camel = propCache[prop])){
8863 camel = propCache[prop] = prop.replace(camelRe, camelFn);
8865 if(v = el.style[camel]){
8868 if(cs = el.currentStyle){
8876 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
8877 * @param {String/Object} property The style property to be set, or an object of multiple styles.
8878 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
8879 * @return {Roo.Element} this
8881 setStyle : function(prop, value){
8882 if(typeof prop == "string"){
8884 if (prop == 'float') {
8885 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
8890 if(!(camel = propCache[prop])){
8891 camel = propCache[prop] = prop.replace(camelRe, camelFn);
8894 if(camel == 'opacity') {
8895 this.setOpacity(value);
8897 this.dom.style[camel] = value;
8900 for(var style in prop){
8901 if(typeof prop[style] != "function"){
8902 this.setStyle(style, prop[style]);
8910 * More flexible version of {@link #setStyle} for setting style properties.
8911 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
8912 * a function which returns such a specification.
8913 * @return {Roo.Element} this
8915 applyStyles : function(style){
8916 Roo.DomHelper.applyStyles(this.dom, style);
8921 * 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).
8922 * @return {Number} The X position of the element
8925 return D.getX(this.dom);
8929 * 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).
8930 * @return {Number} The Y position of the element
8933 return D.getY(this.dom);
8937 * 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).
8938 * @return {Array} The XY position of the element
8941 return D.getXY(this.dom);
8945 * 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).
8946 * @param {Number} The X position of the element
8947 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8948 * @return {Roo.Element} this
8950 setX : function(x, animate){
8952 D.setX(this.dom, x);
8954 this.setXY([x, this.getY()], this.preanim(arguments, 1));
8960 * 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).
8961 * @param {Number} The Y position of the element
8962 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8963 * @return {Roo.Element} this
8965 setY : function(y, animate){
8967 D.setY(this.dom, y);
8969 this.setXY([this.getX(), y], this.preanim(arguments, 1));
8975 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
8976 * @param {String} left The left CSS property value
8977 * @return {Roo.Element} this
8979 setLeft : function(left){
8980 this.setStyle("left", this.addUnits(left));
8985 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
8986 * @param {String} top The top CSS property value
8987 * @return {Roo.Element} this
8989 setTop : function(top){
8990 this.setStyle("top", this.addUnits(top));
8995 * Sets the element's CSS right style.
8996 * @param {String} right The right CSS property value
8997 * @return {Roo.Element} this
8999 setRight : function(right){
9000 this.setStyle("right", this.addUnits(right));
9005 * Sets the element's CSS bottom style.
9006 * @param {String} bottom The bottom CSS property value
9007 * @return {Roo.Element} this
9009 setBottom : function(bottom){
9010 this.setStyle("bottom", this.addUnits(bottom));
9015 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9016 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9017 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
9018 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9019 * @return {Roo.Element} this
9021 setXY : function(pos, animate){
9023 D.setXY(this.dom, pos);
9025 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
9031 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9032 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9033 * @param {Number} x X value for new position (coordinates are page-based)
9034 * @param {Number} y Y value for new position (coordinates are page-based)
9035 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9036 * @return {Roo.Element} this
9038 setLocation : function(x, y, animate){
9039 this.setXY([x, y], this.preanim(arguments, 2));
9044 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9045 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9046 * @param {Number} x X value for new position (coordinates are page-based)
9047 * @param {Number} y Y value for new position (coordinates are page-based)
9048 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9049 * @return {Roo.Element} this
9051 moveTo : function(x, y, animate){
9052 this.setXY([x, y], this.preanim(arguments, 2));
9057 * Returns the region of the given element.
9058 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
9059 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
9061 getRegion : function(){
9062 return D.getRegion(this.dom);
9066 * Returns the offset height of the element
9067 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
9068 * @return {Number} The element's height
9070 getHeight : function(contentHeight){
9071 var h = this.dom.offsetHeight || 0;
9072 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
9076 * Returns the offset width of the element
9077 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
9078 * @return {Number} The element's width
9080 getWidth : function(contentWidth){
9081 var w = this.dom.offsetWidth || 0;
9082 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
9086 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
9087 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
9088 * if a height has not been set using CSS.
9091 getComputedHeight : function(){
9092 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
9094 h = parseInt(this.getStyle('height'), 10) || 0;
9095 if(!this.isBorderBox()){
9096 h += this.getFrameWidth('tb');
9103 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
9104 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
9105 * if a width has not been set using CSS.
9108 getComputedWidth : function(){
9109 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
9111 w = parseInt(this.getStyle('width'), 10) || 0;
9112 if(!this.isBorderBox()){
9113 w += this.getFrameWidth('lr');
9120 * Returns the size of the element.
9121 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
9122 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
9124 getSize : function(contentSize){
9125 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
9129 * Returns the width and height of the viewport.
9130 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
9132 getViewSize : function(){
9133 var d = this.dom, doc = document, aw = 0, ah = 0;
9134 if(d == doc || d == doc.body){
9135 return {width : D.getViewWidth(), height: D.getViewHeight()};
9138 width : d.clientWidth,
9139 height: d.clientHeight
9145 * Returns the value of the "value" attribute
9146 * @param {Boolean} asNumber true to parse the value as a number
9147 * @return {String/Number}
9149 getValue : function(asNumber){
9150 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
9154 adjustWidth : function(width){
9155 if(typeof width == "number"){
9156 if(this.autoBoxAdjust && !this.isBorderBox()){
9157 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9167 adjustHeight : function(height){
9168 if(typeof height == "number"){
9169 if(this.autoBoxAdjust && !this.isBorderBox()){
9170 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9180 * Set the width of the element
9181 * @param {Number} width The new width
9182 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9183 * @return {Roo.Element} this
9185 setWidth : function(width, animate){
9186 width = this.adjustWidth(width);
9188 this.dom.style.width = this.addUnits(width);
9190 this.anim({width: {to: width}}, this.preanim(arguments, 1));
9196 * Set the height of the element
9197 * @param {Number} height The new height
9198 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9199 * @return {Roo.Element} this
9201 setHeight : function(height, animate){
9202 height = this.adjustHeight(height);
9204 this.dom.style.height = this.addUnits(height);
9206 this.anim({height: {to: height}}, this.preanim(arguments, 1));
9212 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
9213 * @param {Number} width The new width
9214 * @param {Number} height The new height
9215 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9216 * @return {Roo.Element} this
9218 setSize : function(width, height, animate){
9219 if(typeof width == "object"){ // in case of object from getSize()
9220 height = width.height; width = width.width;
9222 width = this.adjustWidth(width); height = this.adjustHeight(height);
9224 this.dom.style.width = this.addUnits(width);
9225 this.dom.style.height = this.addUnits(height);
9227 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
9233 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
9234 * @param {Number} x X value for new position (coordinates are page-based)
9235 * @param {Number} y Y value for new position (coordinates are page-based)
9236 * @param {Number} width The new width
9237 * @param {Number} height The new height
9238 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9239 * @return {Roo.Element} this
9241 setBounds : function(x, y, width, height, animate){
9243 this.setSize(width, height);
9244 this.setLocation(x, y);
9246 width = this.adjustWidth(width); height = this.adjustHeight(height);
9247 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
9248 this.preanim(arguments, 4), 'motion');
9254 * 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.
9255 * @param {Roo.lib.Region} region The region to fill
9256 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9257 * @return {Roo.Element} this
9259 setRegion : function(region, animate){
9260 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
9265 * Appends an event handler
9267 * @param {String} eventName The type of event to append
9268 * @param {Function} fn The method the event invokes
9269 * @param {Object} scope (optional) The scope (this object) of the fn
9270 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9272 addListener : function(eventName, fn, scope, options)
9274 if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
9275 this.addListener('touchstart', this.onTapHandler, this);
9278 // we need to handle a special case where dom element is a svg element.
9279 // in this case we do not actua
9284 if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
9285 if (typeof(this.listeners[eventName]) == 'undefined') {
9286 this.listeners[eventName] = new Roo.util.Event(this, eventName);
9288 this.listeners[eventName].addListener(fn, scope, options);
9293 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
9298 onTapHandler : function(event)
9300 if(!this.tapedTwice) {
9301 this.tapedTwice = true;
9303 setTimeout( function() {
9304 s.tapedTwice = false;
9308 event.preventDefault();
9309 var revent = new MouseEvent('dblclick', {
9315 this.dom.dispatchEvent(revent);
9316 //action on double tap goes below
9321 * Removes an event handler from this element
9322 * @param {String} eventName the type of event to remove
9323 * @param {Function} fn the method the event invokes
9324 * @param {Function} scope (needed for svg fake listeners)
9325 * @return {Roo.Element} this
9327 removeListener : function(eventName, fn, scope){
9328 Roo.EventManager.removeListener(this.dom, eventName, fn);
9329 if (typeof(this.listeners) == 'undefined' || typeof(this.listeners[eventName]) == 'undefined') {
9332 this.listeners[eventName].removeListener(fn, scope);
9337 * Removes all previous added listeners from this element
9338 * @return {Roo.Element} this
9340 removeAllListeners : function(){
9341 E.purgeElement(this.dom);
9342 this.listeners = {};
9346 relayEvent : function(eventName, observable){
9347 this.on(eventName, function(e){
9348 observable.fireEvent(eventName, e);
9354 * Set the opacity of the element
9355 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
9356 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9357 * @return {Roo.Element} this
9359 setOpacity : function(opacity, animate){
9361 var s = this.dom.style;
9364 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
9365 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
9367 s.opacity = opacity;
9370 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
9376 * Gets the left X coordinate
9377 * @param {Boolean} local True to get the local css position instead of page coordinate
9380 getLeft : function(local){
9384 return parseInt(this.getStyle("left"), 10) || 0;
9389 * Gets the right X coordinate of the element (element X position + element width)
9390 * @param {Boolean} local True to get the local css position instead of page coordinate
9393 getRight : function(local){
9395 return this.getX() + this.getWidth();
9397 return (this.getLeft(true) + this.getWidth()) || 0;
9402 * Gets the top Y coordinate
9403 * @param {Boolean} local True to get the local css position instead of page coordinate
9406 getTop : function(local) {
9410 return parseInt(this.getStyle("top"), 10) || 0;
9415 * Gets the bottom Y coordinate of the element (element Y position + element height)
9416 * @param {Boolean} local True to get the local css position instead of page coordinate
9419 getBottom : function(local){
9421 return this.getY() + this.getHeight();
9423 return (this.getTop(true) + this.getHeight()) || 0;
9428 * Initializes positioning on this element. If a desired position is not passed, it will make the
9429 * the element positioned relative IF it is not already positioned.
9430 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
9431 * @param {Number} zIndex (optional) The zIndex to apply
9432 * @param {Number} x (optional) Set the page X position
9433 * @param {Number} y (optional) Set the page Y position
9435 position : function(pos, zIndex, x, y){
9437 if(this.getStyle('position') == 'static'){
9438 this.setStyle('position', 'relative');
9441 this.setStyle("position", pos);
9444 this.setStyle("z-index", zIndex);
9446 if(x !== undefined && y !== undefined){
9448 }else if(x !== undefined){
9450 }else if(y !== undefined){
9456 * Clear positioning back to the default when the document was loaded
9457 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
9458 * @return {Roo.Element} this
9460 clearPositioning : function(value){
9468 "position" : "static"
9474 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
9475 * snapshot before performing an update and then restoring the element.
9478 getPositioning : function(){
9479 var l = this.getStyle("left");
9480 var t = this.getStyle("top");
9482 "position" : this.getStyle("position"),
9484 "right" : l ? "" : this.getStyle("right"),
9486 "bottom" : t ? "" : this.getStyle("bottom"),
9487 "z-index" : this.getStyle("z-index")
9492 * Gets the width of the border(s) for the specified side(s)
9493 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9494 * passing lr would get the border (l)eft width + the border (r)ight width.
9495 * @return {Number} The width of the sides passed added together
9497 getBorderWidth : function(side){
9498 return this.addStyles(side, El.borders);
9502 * Gets the width of the padding(s) for the specified side(s)
9503 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9504 * passing lr would get the padding (l)eft + the padding (r)ight.
9505 * @return {Number} The padding of the sides passed added together
9507 getPadding : function(side){
9508 return this.addStyles(side, El.paddings);
9512 * Set positioning with an object returned by getPositioning().
9513 * @param {Object} posCfg
9514 * @return {Roo.Element} this
9516 setPositioning : function(pc){
9517 this.applyStyles(pc);
9518 if(pc.right == "auto"){
9519 this.dom.style.right = "";
9521 if(pc.bottom == "auto"){
9522 this.dom.style.bottom = "";
9528 fixDisplay : function(){
9529 if(this.getStyle("display") == "none"){
9530 this.setStyle("visibility", "hidden");
9531 this.setStyle("display", this.originalDisplay); // first try reverting to default
9532 if(this.getStyle("display") == "none"){ // if that fails, default to block
9533 this.setStyle("display", "block");
9539 * Quick set left and top adding default units
9540 * @param {String} left The left CSS property value
9541 * @param {String} top The top CSS property value
9542 * @return {Roo.Element} this
9544 setLeftTop : function(left, top){
9545 this.dom.style.left = this.addUnits(left);
9546 this.dom.style.top = this.addUnits(top);
9551 * Move this element relative to its current position.
9552 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9553 * @param {Number} distance How far to move the element in pixels
9554 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9555 * @return {Roo.Element} this
9557 move : function(direction, distance, animate){
9558 var xy = this.getXY();
9559 direction = direction.toLowerCase();
9563 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
9567 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
9572 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
9577 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
9584 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
9585 * @return {Roo.Element} this
9588 if(!this.isClipped){
9589 this.isClipped = true;
9590 this.originalClip = {
9591 "o": this.getStyle("overflow"),
9592 "x": this.getStyle("overflow-x"),
9593 "y": this.getStyle("overflow-y")
9595 this.setStyle("overflow", "hidden");
9596 this.setStyle("overflow-x", "hidden");
9597 this.setStyle("overflow-y", "hidden");
9603 * Return clipping (overflow) to original clipping before clip() was called
9604 * @return {Roo.Element} this
9606 unclip : function(){
9608 this.isClipped = false;
9609 var o = this.originalClip;
9610 if(o.o){this.setStyle("overflow", o.o);}
9611 if(o.x){this.setStyle("overflow-x", o.x);}
9612 if(o.y){this.setStyle("overflow-y", o.y);}
9619 * Gets the x,y coordinates specified by the anchor position on the element.
9620 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
9621 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
9622 * {width: (target width), height: (target height)} (defaults to the element's current size)
9623 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
9624 * @return {Array} [x, y] An array containing the element's x and y coordinates
9626 getAnchorXY : function(anchor, local, s){
9627 //Passing a different size is useful for pre-calculating anchors,
9628 //especially for anchored animations that change the el size.
9630 var w, h, vp = false;
9633 if(d == document.body || d == document){
9635 w = D.getViewWidth(); h = D.getViewHeight();
9637 w = this.getWidth(); h = this.getHeight();
9640 w = s.width; h = s.height;
9642 var x = 0, y = 0, r = Math.round;
9643 switch((anchor || "tl").toLowerCase()){
9685 var sc = this.getScroll();
9686 return [x + sc.left, y + sc.top];
9688 //Add the element's offset xy
9689 var o = this.getXY();
9690 return [x+o[0], y+o[1]];
9694 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
9695 * supported position values.
9696 * @param {String/HTMLElement/Roo.Element} element The element to align to.
9697 * @param {String} position The position to align to.
9698 * @param {Array} offsets (optional) Offset the positioning by [x, y]
9699 * @return {Array} [x, y]
9701 getAlignToXY : function(el, p, o)
9706 throw "Element.alignTo with an element that doesn't exist";
9708 var c = false; //constrain to viewport
9709 var p1 = "", p2 = "";
9716 }else if(p.indexOf("-") == -1){
9719 p = p.toLowerCase();
9720 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
9722 throw "Element.alignTo with an invalid alignment " + p;
9724 p1 = m[1]; p2 = m[2]; c = !!m[3];
9726 //Subtract the aligned el's internal xy from the target's offset xy
9727 //plus custom offset to get the aligned el's new offset xy
9728 var a1 = this.getAnchorXY(p1, true);
9729 var a2 = el.getAnchorXY(p2, false);
9730 var x = a2[0] - a1[0] + o[0];
9731 var y = a2[1] - a1[1] + o[1];
9733 //constrain the aligned el to viewport if necessary
9734 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
9735 // 5px of margin for ie
9736 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
9738 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
9739 //perpendicular to the vp border, allow the aligned el to slide on that border,
9740 //otherwise swap the aligned el to the opposite border of the target.
9741 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
9742 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
9743 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t") );
9744 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
9747 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
9748 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
9750 if((x+w) > dw + scrollX){
9751 x = swapX ? r.left-w : dw+scrollX-w;
9754 x = swapX ? r.right : scrollX;
9756 if((y+h) > dh + scrollY){
9757 y = swapY ? r.top-h : dh+scrollY-h;
9760 y = swapY ? r.bottom : scrollY;
9767 getConstrainToXY : function(){
9768 var os = {top:0, left:0, bottom:0, right: 0};
9770 return function(el, local, offsets, proposedXY){
9772 offsets = offsets ? Roo.applyIf(offsets, os) : os;
9774 var vw, vh, vx = 0, vy = 0;
9775 if(el.dom == document.body || el.dom == document){
9776 vw = Roo.lib.Dom.getViewWidth();
9777 vh = Roo.lib.Dom.getViewHeight();
9779 vw = el.dom.clientWidth;
9780 vh = el.dom.clientHeight;
9782 var vxy = el.getXY();
9788 var s = el.getScroll();
9790 vx += offsets.left + s.left;
9791 vy += offsets.top + s.top;
9793 vw -= offsets.right;
9794 vh -= offsets.bottom;
9799 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
9800 var x = xy[0], y = xy[1];
9801 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
9803 // only move it if it needs it
9806 // first validate right/bottom
9815 // then make sure top/left isn't negative
9824 return moved ? [x, y] : false;
9829 adjustForConstraints : function(xy, parent, offsets){
9830 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
9834 * Aligns this element with another element relative to the specified anchor points. If the other element is the
9835 * document it aligns it to the viewport.
9836 * The position parameter is optional, and can be specified in any one of the following formats:
9838 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
9839 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
9840 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
9841 * deprecated in favor of the newer two anchor syntax below</i>.</li>
9842 * <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
9843 * element's anchor point, and the second value is used as the target's anchor point.</li>
9845 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
9846 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
9847 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
9848 * that specified in order to enforce the viewport constraints.
9849 * Following are all of the supported anchor positions:
9852 ----- -----------------------------
9853 tl The top left corner (default)
9854 t The center of the top edge
9855 tr The top right corner
9856 l The center of the left edge
9857 c In the center of the element
9858 r The center of the right edge
9859 bl The bottom left corner
9860 b The center of the bottom edge
9861 br The bottom right corner
9865 // align el to other-el using the default positioning ("tl-bl", non-constrained)
9866 el.alignTo("other-el");
9868 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
9869 el.alignTo("other-el", "tr?");
9871 // align the bottom right corner of el with the center left edge of other-el
9872 el.alignTo("other-el", "br-l?");
9874 // align the center of el with the bottom left corner of other-el and
9875 // adjust the x position by -6 pixels (and the y position by 0)
9876 el.alignTo("other-el", "c-bl", [-6, 0]);
9878 * @param {String/HTMLElement/Roo.Element} element The element to align to.
9879 * @param {String} position The position to align to.
9880 * @param {Array} offsets (optional) Offset the positioning by [x, y]
9881 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9882 * @return {Roo.Element} this
9884 alignTo : function(element, position, offsets, animate){
9885 var xy = this.getAlignToXY(element, position, offsets);
9886 this.setXY(xy, this.preanim(arguments, 3));
9891 * Anchors an element to another element and realigns it when the window is resized.
9892 * @param {String/HTMLElement/Roo.Element} element The element to align to.
9893 * @param {String} position The position to align to.
9894 * @param {Array} offsets (optional) Offset the positioning by [x, y]
9895 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
9896 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
9897 * is a number, it is used as the buffer delay (defaults to 50ms).
9898 * @param {Function} callback The function to call after the animation finishes
9899 * @return {Roo.Element} this
9901 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
9902 var action = function(){
9903 this.alignTo(el, alignment, offsets, animate);
9904 Roo.callback(callback, this);
9906 Roo.EventManager.onWindowResize(action, this);
9907 var tm = typeof monitorScroll;
9908 if(tm != 'undefined'){
9909 Roo.EventManager.on(window, 'scroll', action, this,
9910 {buffer: tm == 'number' ? monitorScroll : 50});
9912 action.call(this); // align immediately
9916 * Clears any opacity settings from this element. Required in some cases for IE.
9917 * @return {Roo.Element} this
9919 clearOpacity : function(){
9920 if (window.ActiveXObject) {
9921 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
9922 this.dom.style.filter = "";
9925 this.dom.style.opacity = "";
9926 this.dom.style["-moz-opacity"] = "";
9927 this.dom.style["-khtml-opacity"] = "";
9933 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
9934 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9935 * @return {Roo.Element} this
9937 hide : function(animate){
9938 this.setVisible(false, this.preanim(arguments, 0));
9943 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
9944 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9945 * @return {Roo.Element} this
9947 show : function(animate){
9948 this.setVisible(true, this.preanim(arguments, 0));
9953 * @private Test if size has a unit, otherwise appends the default
9955 addUnits : function(size){
9956 return Roo.Element.addUnits(size, this.defaultUnit);
9960 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
9961 * @return {Roo.Element} this
9963 beginMeasure : function(){
9965 if(el.offsetWidth || el.offsetHeight){
9966 return this; // offsets work already
9969 var p = this.dom, b = document.body; // start with this element
9970 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
9971 var pe = Roo.get(p);
9972 if(pe.getStyle('display') == 'none'){
9973 changed.push({el: p, visibility: pe.getStyle("visibility")});
9974 p.style.visibility = "hidden";
9975 p.style.display = "block";
9979 this._measureChanged = changed;
9985 * Restores displays to before beginMeasure was called
9986 * @return {Roo.Element} this
9988 endMeasure : function(){
9989 var changed = this._measureChanged;
9991 for(var i = 0, len = changed.length; i < len; i++) {
9993 r.el.style.visibility = r.visibility;
9994 r.el.style.display = "none";
9996 this._measureChanged = null;
10002 * Update the innerHTML of this element, optionally searching for and processing scripts
10003 * @param {String} html The new HTML
10004 * @param {Boolean} loadScripts (optional) true to look for and process scripts
10005 * @param {Function} callback For async script loading you can be noticed when the update completes
10006 * @return {Roo.Element} this
10008 update : function(html, loadScripts, callback){
10009 if(typeof html == "undefined"){
10012 if(loadScripts !== true){
10013 this.dom.innerHTML = html;
10014 if(typeof callback == "function"){
10020 var dom = this.dom;
10022 html += '<span id="' + id + '"></span>';
10024 E.onAvailable(id, function(){
10025 var hd = document.getElementsByTagName("head")[0];
10026 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
10027 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
10028 var typeRe = /\stype=([\'\"])(.*?)\1/i;
10031 while(match = re.exec(html)){
10032 var attrs = match[1];
10033 var srcMatch = attrs ? attrs.match(srcRe) : false;
10034 if(srcMatch && srcMatch[2]){
10035 var s = document.createElement("script");
10036 s.src = srcMatch[2];
10037 var typeMatch = attrs.match(typeRe);
10038 if(typeMatch && typeMatch[2]){
10039 s.type = typeMatch[2];
10042 }else if(match[2] && match[2].length > 0){
10043 if(window.execScript) {
10044 window.execScript(match[2]);
10052 window.eval(match[2]);
10056 var el = document.getElementById(id);
10057 if(el){el.parentNode.removeChild(el);}
10058 if(typeof callback == "function"){
10062 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
10067 * Direct access to the UpdateManager update() method (takes the same parameters).
10068 * @param {String/Function} url The url for this request or a function to call to get the url
10069 * @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}
10070 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
10071 * @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.
10072 * @return {Roo.Element} this
10075 var um = this.getUpdateManager();
10076 um.update.apply(um, arguments);
10081 * Gets this element's UpdateManager
10082 * @return {Roo.UpdateManager} The UpdateManager
10084 getUpdateManager : function(){
10085 if(!this.updateManager){
10086 this.updateManager = new Roo.UpdateManager(this);
10088 return this.updateManager;
10092 * Disables text selection for this element (normalized across browsers)
10093 * @return {Roo.Element} this
10095 unselectable : function(){
10096 this.dom.unselectable = "on";
10097 this.swallowEvent("selectstart", true);
10098 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
10099 this.addClass("x-unselectable");
10104 * Calculates the x, y to center this element on the screen
10105 * @return {Array} The x, y values [x, y]
10107 getCenterXY : function(){
10108 return this.getAlignToXY(document, 'c-c');
10112 * Centers the Element in either the viewport, or another Element.
10113 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
10115 center : function(centerIn){
10116 this.alignTo(centerIn || document, 'c-c');
10121 * Tests various css rules/browsers to determine if this element uses a border box
10122 * @return {Boolean}
10124 isBorderBox : function(){
10125 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
10129 * Return a box {x, y, width, height} that can be used to set another elements
10130 * size/location to match this element.
10131 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
10132 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
10133 * @return {Object} box An object in the format {x, y, width, height}
10135 getBox : function(contentBox, local){
10140 var left = parseInt(this.getStyle("left"), 10) || 0;
10141 var top = parseInt(this.getStyle("top"), 10) || 0;
10144 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
10146 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
10148 var l = this.getBorderWidth("l")+this.getPadding("l");
10149 var r = this.getBorderWidth("r")+this.getPadding("r");
10150 var t = this.getBorderWidth("t")+this.getPadding("t");
10151 var b = this.getBorderWidth("b")+this.getPadding("b");
10152 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)};
10154 bx.right = bx.x + bx.width;
10155 bx.bottom = bx.y + bx.height;
10160 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
10161 for more information about the sides.
10162 * @param {String} sides
10165 getFrameWidth : function(sides, onlyContentBox){
10166 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
10170 * 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.
10171 * @param {Object} box The box to fill {x, y, width, height}
10172 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
10173 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10174 * @return {Roo.Element} this
10176 setBox : function(box, adjust, animate){
10177 var w = box.width, h = box.height;
10178 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
10179 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
10180 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
10182 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
10187 * Forces the browser to repaint this element
10188 * @return {Roo.Element} this
10190 repaint : function(){
10191 var dom = this.dom;
10192 this.addClass("x-repaint");
10193 setTimeout(function(){
10194 Roo.get(dom).removeClass("x-repaint");
10200 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
10201 * then it returns the calculated width of the sides (see getPadding)
10202 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
10203 * @return {Object/Number}
10205 getMargins : function(side){
10208 top: parseInt(this.getStyle("margin-top"), 10) || 0,
10209 left: parseInt(this.getStyle("margin-left"), 10) || 0,
10210 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
10211 right: parseInt(this.getStyle("margin-right"), 10) || 0
10214 return this.addStyles(side, El.margins);
10219 addStyles : function(sides, styles){
10221 for(var i = 0, len = sides.length; i < len; i++){
10222 v = this.getStyle(styles[sides.charAt(i)]);
10224 w = parseInt(v, 10);
10232 * Creates a proxy element of this element
10233 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
10234 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
10235 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
10236 * @return {Roo.Element} The new proxy element
10238 createProxy : function(config, renderTo, matchBox){
10240 renderTo = Roo.getDom(renderTo);
10242 renderTo = document.body;
10244 config = typeof config == "object" ?
10245 config : {tag : "div", cls: config};
10246 var proxy = Roo.DomHelper.append(renderTo, config, true);
10248 proxy.setBox(this.getBox());
10254 * Puts a mask over this element to disable user interaction. Requires core.css.
10255 * This method can only be applied to elements which accept child nodes.
10256 * @param {String} msg (optional) A message to display in the mask
10257 * @param {String} msgCls (optional) A css class to apply to the msg element - use no-spinner to hide the spinner on bootstrap
10258 * @return {Element} The mask element
10260 mask : function(msg, msgCls)
10262 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
10263 this.setStyle("position", "relative");
10266 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
10269 this.addClass("x-masked");
10270 this._mask.setDisplayed(true);
10274 var dom = this.dom;
10275 while (dom && dom.style) {
10276 if (!isNaN(parseInt(dom.style.zIndex))) {
10277 z = Math.max(z, parseInt(dom.style.zIndex));
10279 dom = dom.parentNode;
10281 // if we are masking the body - then it hides everything..
10282 if (this.dom == document.body) {
10284 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
10285 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
10288 if(typeof msg == 'string'){
10289 if(!this._maskMsg){
10290 this._maskMsg = Roo.DomHelper.append(this.dom, {
10291 cls: "roo-el-mask-msg",
10295 cls: 'fa fa-spinner fa-spin'
10303 var mm = this._maskMsg;
10304 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
10305 if (mm.dom.lastChild) { // weird IE issue?
10306 mm.dom.lastChild.innerHTML = msg;
10308 mm.setDisplayed(true);
10310 mm.setStyle('z-index', z + 102);
10312 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
10313 this._mask.setHeight(this.getHeight());
10315 this._mask.setStyle('z-index', z + 100);
10321 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
10322 * it is cached for reuse.
10324 unmask : function(removeEl){
10326 if(removeEl === true){
10327 this._mask.remove();
10330 this._maskMsg.remove();
10331 delete this._maskMsg;
10334 this._mask.setDisplayed(false);
10336 this._maskMsg.setDisplayed(false);
10340 this.removeClass("x-masked");
10344 * Returns true if this element is masked
10345 * @return {Boolean}
10347 isMasked : function(){
10348 return this._mask && this._mask.isVisible();
10352 * Creates an iframe shim for this element to keep selects and other windowed objects from
10354 * @return {Roo.Element} The new shim element
10356 createShim : function(){
10357 var el = document.createElement('iframe');
10358 el.frameBorder = 'no';
10359 el.className = 'roo-shim';
10360 if(Roo.isIE && Roo.isSecure){
10361 el.src = Roo.SSL_SECURE_URL;
10363 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
10364 shim.autoBoxAdjust = false;
10369 * Removes this element from the DOM and deletes it from the cache
10371 remove : function(){
10372 if(this.dom.parentNode){
10373 this.dom.parentNode.removeChild(this.dom);
10375 delete El.cache[this.dom.id];
10379 * Sets up event handlers to add and remove a css class when the mouse is over this element
10380 * @param {String} className
10381 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
10382 * mouseout events for children elements
10383 * @return {Roo.Element} this
10385 addClassOnOver : function(className, preventFlicker){
10386 this.on("mouseover", function(){
10387 Roo.fly(this, '_internal').addClass(className);
10389 var removeFn = function(e){
10390 if(preventFlicker !== true || !e.within(this, true)){
10391 Roo.fly(this, '_internal').removeClass(className);
10394 this.on("mouseout", removeFn, this.dom);
10399 * Sets up event handlers to add and remove a css class when this element has the focus
10400 * @param {String} className
10401 * @return {Roo.Element} this
10403 addClassOnFocus : function(className){
10404 this.on("focus", function(){
10405 Roo.fly(this, '_internal').addClass(className);
10407 this.on("blur", function(){
10408 Roo.fly(this, '_internal').removeClass(className);
10413 * 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)
10414 * @param {String} className
10415 * @return {Roo.Element} this
10417 addClassOnClick : function(className){
10418 var dom = this.dom;
10419 this.on("mousedown", function(){
10420 Roo.fly(dom, '_internal').addClass(className);
10421 var d = Roo.get(document);
10422 var fn = function(){
10423 Roo.fly(dom, '_internal').removeClass(className);
10424 d.removeListener("mouseup", fn);
10426 d.on("mouseup", fn);
10432 * Stops the specified event from bubbling and optionally prevents the default action
10433 * @param {String} eventName
10434 * @param {Boolean} preventDefault (optional) true to prevent the default action too
10435 * @return {Roo.Element} this
10437 swallowEvent : function(eventName, preventDefault){
10438 var fn = function(e){
10439 e.stopPropagation();
10440 if(preventDefault){
10441 e.preventDefault();
10444 if(eventName instanceof Array){
10445 for(var i = 0, len = eventName.length; i < len; i++){
10446 this.on(eventName[i], fn);
10450 this.on(eventName, fn);
10457 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
10460 * Sizes this element to its parent element's dimensions performing
10461 * neccessary box adjustments.
10462 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
10463 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
10464 * @return {Roo.Element} this
10466 fitToParent : function(monitorResize, targetParent) {
10467 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
10468 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
10469 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
10472 var p = Roo.get(targetParent || this.dom.parentNode);
10473 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
10474 if (monitorResize === true) {
10475 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
10476 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
10482 * Gets the next sibling, skipping text nodes
10483 * @return {HTMLElement} The next sibling or null
10485 getNextSibling : function(){
10486 var n = this.dom.nextSibling;
10487 while(n && n.nodeType != 1){
10494 * Gets the previous sibling, skipping text nodes
10495 * @return {HTMLElement} The previous sibling or null
10497 getPrevSibling : function(){
10498 var n = this.dom.previousSibling;
10499 while(n && n.nodeType != 1){
10500 n = n.previousSibling;
10507 * Appends the passed element(s) to this element
10508 * @param {String/HTMLElement/Array/Element/CompositeElement} el
10509 * @return {Roo.Element} this
10511 appendChild: function(el){
10518 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
10519 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
10520 * automatically generated with the specified attributes.
10521 * @param {HTMLElement} insertBefore (optional) a child element of this element
10522 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
10523 * @return {Roo.Element} The new child element
10525 createChild: function(config, insertBefore, returnDom){
10526 config = config || {tag:'div'};
10528 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
10530 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
10534 * Appends this element to the passed element
10535 * @param {String/HTMLElement/Element} el The new parent element
10536 * @return {Roo.Element} this
10538 appendTo: function(el){
10539 el = Roo.getDom(el);
10540 el.appendChild(this.dom);
10545 * Inserts this element before the passed element in the DOM
10546 * @param {String/HTMLElement/Element} el The element to insert before
10547 * @return {Roo.Element} this
10549 insertBefore: function(el){
10550 el = Roo.getDom(el);
10551 el.parentNode.insertBefore(this.dom, el);
10556 * Inserts this element after the passed element in the DOM
10557 * @param {String/HTMLElement/Element} el The element to insert after
10558 * @return {Roo.Element} this
10560 insertAfter: function(el){
10561 el = Roo.getDom(el);
10562 el.parentNode.insertBefore(this.dom, el.nextSibling);
10567 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
10568 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10569 * @return {Roo.Element} The new child
10571 insertFirst: function(el, returnDom){
10573 if(typeof el == 'object' && !el.nodeType){ // dh config
10574 return this.createChild(el, this.dom.firstChild, returnDom);
10576 el = Roo.getDom(el);
10577 this.dom.insertBefore(el, this.dom.firstChild);
10578 return !returnDom ? Roo.get(el) : el;
10583 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
10584 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10585 * @param {String} where (optional) 'before' or 'after' defaults to before
10586 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10587 * @return {Roo.Element} the inserted Element
10589 insertSibling: function(el, where, returnDom){
10590 where = where ? where.toLowerCase() : 'before';
10592 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
10594 if(typeof el == 'object' && !el.nodeType){ // dh config
10595 if(where == 'after' && !this.dom.nextSibling){
10596 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
10598 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
10602 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
10603 where == 'before' ? this.dom : this.dom.nextSibling);
10612 * Creates and wraps this element with another element
10613 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
10614 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10615 * @return {HTMLElement/Element} The newly created wrapper element
10617 wrap: function(config, returnDom){
10619 config = {tag: "div"};
10621 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
10622 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
10627 * Replaces the passed element with this element
10628 * @param {String/HTMLElement/Element} el The element to replace
10629 * @return {Roo.Element} this
10631 replace: function(el){
10633 this.insertBefore(el);
10639 * Inserts an html fragment into this element
10640 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
10641 * @param {String} html The HTML fragment
10642 * @param {Boolean} returnEl True to return an Roo.Element
10643 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
10645 insertHtml : function(where, html, returnEl){
10646 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
10647 return returnEl ? Roo.get(el) : el;
10651 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
10652 * @param {Object} o The object with the attributes
10653 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
10654 * @return {Roo.Element} this
10656 set : function(o, useSet){
10658 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
10659 for(var attr in o){
10660 if(attr == "style" || typeof o[attr] == "function") { continue; }
10662 el.className = o["cls"];
10665 el.setAttribute(attr, o[attr]);
10667 el[attr] = o[attr];
10672 Roo.DomHelper.applyStyles(el, o.style);
10678 * Convenience method for constructing a KeyMap
10679 * @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:
10680 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
10681 * @param {Function} fn The function to call
10682 * @param {Object} scope (optional) The scope of the function
10683 * @return {Roo.KeyMap} The KeyMap created
10685 addKeyListener : function(key, fn, scope){
10687 if(typeof key != "object" || key instanceof Array){
10703 return new Roo.KeyMap(this, config);
10707 * Creates a KeyMap for this element
10708 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
10709 * @return {Roo.KeyMap} The KeyMap created
10711 addKeyMap : function(config){
10712 return new Roo.KeyMap(this, config);
10716 * Returns true if this element is scrollable.
10717 * @return {Boolean}
10719 isScrollable : function(){
10720 var dom = this.dom;
10721 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
10725 * 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().
10726 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
10727 * @param {Number} value The new scroll value
10728 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10729 * @return {Element} this
10732 scrollTo : function(side, value, animate){
10733 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
10734 if(!animate || !A){
10735 this.dom[prop] = value;
10737 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
10738 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
10744 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
10745 * within this element's scrollable range.
10746 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
10747 * @param {Number} distance How far to scroll the element in pixels
10748 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10749 * @return {Boolean} Returns true if a scroll was triggered or false if the element
10750 * was scrolled as far as it could go.
10752 scroll : function(direction, distance, animate){
10753 if(!this.isScrollable()){
10757 var l = el.scrollLeft, t = el.scrollTop;
10758 var w = el.scrollWidth, h = el.scrollHeight;
10759 var cw = el.clientWidth, ch = el.clientHeight;
10760 direction = direction.toLowerCase();
10761 var scrolled = false;
10762 var a = this.preanim(arguments, 2);
10767 var v = Math.min(l + distance, w-cw);
10768 this.scrollTo("left", v, a);
10775 var v = Math.max(l - distance, 0);
10776 this.scrollTo("left", v, a);
10784 var v = Math.max(t - distance, 0);
10785 this.scrollTo("top", v, a);
10793 var v = Math.min(t + distance, h-ch);
10794 this.scrollTo("top", v, a);
10803 * Translates the passed page coordinates into left/top css values for this element
10804 * @param {Number/Array} x The page x or an array containing [x, y]
10805 * @param {Number} y The page y
10806 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
10808 translatePoints : function(x, y){
10809 if(typeof x == 'object' || x instanceof Array){
10810 y = x[1]; x = x[0];
10812 var p = this.getStyle('position');
10813 var o = this.getXY();
10815 var l = parseInt(this.getStyle('left'), 10);
10816 var t = parseInt(this.getStyle('top'), 10);
10819 l = (p == "relative") ? 0 : this.dom.offsetLeft;
10822 t = (p == "relative") ? 0 : this.dom.offsetTop;
10825 return {left: (x - o[0] + l), top: (y - o[1] + t)};
10829 * Returns the current scroll position of the element.
10830 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
10832 getScroll : function(){
10833 var d = this.dom, doc = document;
10834 if(d == doc || d == doc.body){
10835 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
10836 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
10837 return {left: l, top: t};
10839 return {left: d.scrollLeft, top: d.scrollTop};
10844 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
10845 * are convert to standard 6 digit hex color.
10846 * @param {String} attr The css attribute
10847 * @param {String} defaultValue The default value to use when a valid color isn't found
10848 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
10851 getColor : function(attr, defaultValue, prefix){
10852 var v = this.getStyle(attr);
10853 if(!v || v == "transparent" || v == "inherit") {
10854 return defaultValue;
10856 var color = typeof prefix == "undefined" ? "#" : prefix;
10857 if(v.substr(0, 4) == "rgb("){
10858 var rvs = v.slice(4, v.length -1).split(",");
10859 for(var i = 0; i < 3; i++){
10860 var h = parseInt(rvs[i]).toString(16);
10867 if(v.substr(0, 1) == "#"){
10868 if(v.length == 4) {
10869 for(var i = 1; i < 4; i++){
10870 var c = v.charAt(i);
10873 }else if(v.length == 7){
10874 color += v.substr(1);
10878 return(color.length > 5 ? color.toLowerCase() : defaultValue);
10882 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
10883 * gradient background, rounded corners and a 4-way shadow.
10884 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
10885 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
10886 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
10887 * @return {Roo.Element} this
10889 boxWrap : function(cls){
10890 cls = cls || 'x-box';
10891 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
10892 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
10897 * Returns the value of a namespaced attribute from the element's underlying DOM node.
10898 * @param {String} namespace The namespace in which to look for the attribute
10899 * @param {String} name The attribute name
10900 * @return {String} The attribute value
10902 getAttributeNS : Roo.isIE ? function(ns, name){
10904 var type = typeof d[ns+":"+name];
10905 if(type != 'undefined' && type != 'unknown'){
10906 return d[ns+":"+name];
10909 } : function(ns, name){
10911 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
10916 * Sets or Returns the value the dom attribute value
10917 * @param {String|Object} name The attribute name (or object to set multiple attributes)
10918 * @param {String} value (optional) The value to set the attribute to
10919 * @return {String} The attribute value
10921 attr : function(name){
10922 if (arguments.length > 1) {
10923 this.dom.setAttribute(name, arguments[1]);
10924 return arguments[1];
10926 if (typeof(name) == 'object') {
10927 for(var i in name) {
10928 this.attr(i, name[i]);
10934 if (!this.dom.hasAttribute(name)) {
10937 return this.dom.getAttribute(name);
10944 var ep = El.prototype;
10947 * Appends an event handler (Shorthand for addListener)
10948 * @param {String} eventName The type of event to append
10949 * @param {Function} fn The method the event invokes
10950 * @param {Object} scope (optional) The scope (this object) of the fn
10951 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
10954 ep.on = ep.addListener;
10955 // backwards compat
10956 ep.mon = ep.addListener;
10959 * Removes an event handler from this element (shorthand for removeListener)
10960 * @param {String} eventName the type of event to remove
10961 * @param {Function} fn the method the event invokes
10962 * @return {Roo.Element} this
10965 ep.un = ep.removeListener;
10968 * true to automatically adjust width and height settings for box-model issues (default to true)
10970 ep.autoBoxAdjust = true;
10973 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
10976 El.addUnits = function(v, defaultUnit){
10977 if(v === "" || v == "auto"){
10980 if(v === undefined){
10983 if(typeof v == "number" || !El.unitPattern.test(v)){
10984 return v + (defaultUnit || 'px');
10989 // special markup used throughout Roo when box wrapping elements
10990 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>';
10992 * Visibility mode constant - Use visibility to hide element
10998 * Visibility mode constant - Use display to hide element
11004 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
11005 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
11006 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
11018 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
11019 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
11020 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
11021 * @return {Element} The Element object
11024 El.get = function(el){
11026 if(!el){ return null; }
11027 if(typeof el == "string"){ // element id
11028 if(!(elm = document.getElementById(el))){
11031 if(ex = El.cache[el]){
11034 ex = El.cache[el] = new El(elm);
11037 }else if(el.tagName){ // dom element
11041 if(ex = El.cache[id]){
11044 ex = El.cache[id] = new El(el);
11047 }else if(el instanceof El){
11049 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
11050 // catch case where it hasn't been appended
11051 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
11054 }else if(el.isComposite){
11056 }else if(el instanceof Array){
11057 return El.select(el);
11058 }else if(el == document){
11059 // create a bogus element object representing the document object
11061 var f = function(){};
11062 f.prototype = El.prototype;
11064 docEl.dom = document;
11072 El.uncache = function(el){
11073 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
11075 delete El.cache[a[i].id || a[i]];
11081 // Garbage collection - uncache elements/purge listeners on orphaned elements
11082 // so we don't hold a reference and cause the browser to retain them
11083 El.garbageCollect = function(){
11084 if(!Roo.enableGarbageCollector){
11085 clearInterval(El.collectorThread);
11088 for(var eid in El.cache){
11089 var el = El.cache[eid], d = el.dom;
11090 // -------------------------------------------------------
11091 // Determining what is garbage:
11092 // -------------------------------------------------------
11094 // dom node is null, definitely garbage
11095 // -------------------------------------------------------
11097 // no parentNode == direct orphan, definitely garbage
11098 // -------------------------------------------------------
11099 // !d.offsetParent && !document.getElementById(eid)
11100 // display none elements have no offsetParent so we will
11101 // also try to look it up by it's id. However, check
11102 // offsetParent first so we don't do unneeded lookups.
11103 // This enables collection of elements that are not orphans
11104 // directly, but somewhere up the line they have an orphan
11106 // -------------------------------------------------------
11107 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
11108 delete El.cache[eid];
11109 if(d && Roo.enableListenerCollection){
11115 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
11119 El.Flyweight = function(dom){
11122 El.Flyweight.prototype = El.prototype;
11124 El._flyweights = {};
11126 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
11127 * the dom node can be overwritten by other code.
11128 * @param {String/HTMLElement} el The dom node or id
11129 * @param {String} named (optional) Allows for creation of named reusable flyweights to
11130 * prevent conflicts (e.g. internally Roo uses "_internal")
11132 * @return {Element} The shared Element object
11134 El.fly = function(el, named){
11135 named = named || '_global';
11136 el = Roo.getDom(el);
11140 if(!El._flyweights[named]){
11141 El._flyweights[named] = new El.Flyweight();
11143 El._flyweights[named].dom = el;
11144 return El._flyweights[named];
11148 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
11149 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
11150 * Shorthand of {@link Roo.Element#get}
11151 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
11152 * @return {Element} The Element object
11158 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
11159 * the dom node can be overwritten by other code.
11160 * Shorthand of {@link Roo.Element#fly}
11161 * @param {String/HTMLElement} el The dom node or id
11162 * @param {String} named (optional) Allows for creation of named reusable flyweights to
11163 * prevent conflicts (e.g. internally Roo uses "_internal")
11165 * @return {Element} The shared Element object
11171 // speedy lookup for elements never to box adjust
11172 var noBoxAdjust = Roo.isStrict ? {
11175 input:1, select:1, textarea:1
11177 if(Roo.isIE || Roo.isGecko){
11178 noBoxAdjust['button'] = 1;
11182 Roo.EventManager.on(window, 'unload', function(){
11184 delete El._flyweights;
11192 Roo.Element.selectorFunction = Roo.DomQuery.select;
11195 Roo.Element.select = function(selector, unique, root){
11197 if(typeof selector == "string"){
11198 els = Roo.Element.selectorFunction(selector, root);
11199 }else if(selector.length !== undefined){
11202 throw "Invalid selector";
11204 if(unique === true){
11205 return new Roo.CompositeElement(els);
11207 return new Roo.CompositeElementLite(els);
11211 * Selects elements based on the passed CSS selector to enable working on them as 1.
11212 * @param {String/Array} selector The CSS selector or an array of elements
11213 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
11214 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
11215 * @return {CompositeElementLite/CompositeElement}
11219 Roo.select = Roo.Element.select;
11236 * Ext JS Library 1.1.1
11237 * Copyright(c) 2006-2007, Ext JS, LLC.
11239 * Originally Released Under LGPL - original licence link has changed is not relivant.
11242 * <script type="text/javascript">
11247 //Notifies Element that fx methods are available
11248 Roo.enableFx = true;
11252 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
11253 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
11254 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
11255 * Element effects to work.</p><br/>
11257 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
11258 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
11259 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
11260 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
11261 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
11262 * expected results and should be done with care.</p><br/>
11264 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
11265 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
11268 ----- -----------------------------
11269 tl The top left corner
11270 t The center of the top edge
11271 tr The top right corner
11272 l The center of the left edge
11273 r The center of the right edge
11274 bl The bottom left corner
11275 b The center of the bottom edge
11276 br The bottom right corner
11278 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
11279 * below are common options that can be passed to any Fx method.</b>
11280 * @cfg {Function} callback A function called when the effect is finished
11281 * @cfg {Object} scope The scope of the effect function
11282 * @cfg {String} easing A valid Easing value for the effect
11283 * @cfg {String} afterCls A css class to apply after the effect
11284 * @cfg {Number} duration The length of time (in seconds) that the effect should last
11285 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
11286 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
11287 * effects that end with the element being visually hidden, ignored otherwise)
11288 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
11289 * a function which returns such a specification that will be applied to the Element after the effect finishes
11290 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
11291 * @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
11292 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
11296 * Slides the element into view. An anchor point can be optionally passed to set the point of
11297 * origin for the slide effect. This function automatically handles wrapping the element with
11298 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
11301 // default: slide the element in from the top
11304 // custom: slide the element in from the right with a 2-second duration
11305 el.slideIn('r', { duration: 2 });
11307 // common config options shown with default values
11313 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11314 * @param {Object} options (optional) Object literal with any of the Fx config options
11315 * @return {Roo.Element} The Element
11317 slideIn : function(anchor, o){
11318 var el = this.getFxEl();
11321 el.queueFx(o, function(){
11323 anchor = anchor || "t";
11325 // fix display to visibility
11328 // restore values after effect
11329 var r = this.getFxRestore();
11330 var b = this.getBox();
11331 // fixed size for slide
11335 var wrap = this.fxWrap(r.pos, o, "hidden");
11337 var st = this.dom.style;
11338 st.visibility = "visible";
11339 st.position = "absolute";
11341 // clear out temp styles after slide and unwrap
11342 var after = function(){
11343 el.fxUnwrap(wrap, r.pos, o);
11344 st.width = r.width;
11345 st.height = r.height;
11348 // time to calc the positions
11349 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
11351 switch(anchor.toLowerCase()){
11353 wrap.setSize(b.width, 0);
11354 st.left = st.bottom = "0";
11358 wrap.setSize(0, b.height);
11359 st.right = st.top = "0";
11363 wrap.setSize(0, b.height);
11364 wrap.setX(b.right);
11365 st.left = st.top = "0";
11366 a = {width: bw, points: pt};
11369 wrap.setSize(b.width, 0);
11370 wrap.setY(b.bottom);
11371 st.left = st.top = "0";
11372 a = {height: bh, points: pt};
11375 wrap.setSize(0, 0);
11376 st.right = st.bottom = "0";
11377 a = {width: bw, height: bh};
11380 wrap.setSize(0, 0);
11381 wrap.setY(b.y+b.height);
11382 st.right = st.top = "0";
11383 a = {width: bw, height: bh, points: pt};
11386 wrap.setSize(0, 0);
11387 wrap.setXY([b.right, b.bottom]);
11388 st.left = st.top = "0";
11389 a = {width: bw, height: bh, points: pt};
11392 wrap.setSize(0, 0);
11393 wrap.setX(b.x+b.width);
11394 st.left = st.bottom = "0";
11395 a = {width: bw, height: bh, points: pt};
11398 this.dom.style.visibility = "visible";
11401 arguments.callee.anim = wrap.fxanim(a,
11411 * Slides the element out of view. An anchor point can be optionally passed to set the end point
11412 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
11413 * 'hidden') but block elements will still take up space in the document. The element must be removed
11414 * from the DOM using the 'remove' config option if desired. This function automatically handles
11415 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
11418 // default: slide the element out to the top
11421 // custom: slide the element out to the right with a 2-second duration
11422 el.slideOut('r', { duration: 2 });
11424 // common config options shown with default values
11432 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11433 * @param {Object} options (optional) Object literal with any of the Fx config options
11434 * @return {Roo.Element} The Element
11436 slideOut : function(anchor, o){
11437 var el = this.getFxEl();
11440 el.queueFx(o, function(){
11442 anchor = anchor || "t";
11444 // restore values after effect
11445 var r = this.getFxRestore();
11447 var b = this.getBox();
11448 // fixed size for slide
11452 var wrap = this.fxWrap(r.pos, o, "visible");
11454 var st = this.dom.style;
11455 st.visibility = "visible";
11456 st.position = "absolute";
11460 var after = function(){
11462 el.setDisplayed(false);
11467 el.fxUnwrap(wrap, r.pos, o);
11469 st.width = r.width;
11470 st.height = r.height;
11475 var a, zero = {to: 0};
11476 switch(anchor.toLowerCase()){
11478 st.left = st.bottom = "0";
11479 a = {height: zero};
11482 st.right = st.top = "0";
11486 st.left = st.top = "0";
11487 a = {width: zero, points: {to:[b.right, b.y]}};
11490 st.left = st.top = "0";
11491 a = {height: zero, points: {to:[b.x, b.bottom]}};
11494 st.right = st.bottom = "0";
11495 a = {width: zero, height: zero};
11498 st.right = st.top = "0";
11499 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
11502 st.left = st.top = "0";
11503 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
11506 st.left = st.bottom = "0";
11507 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
11511 arguments.callee.anim = wrap.fxanim(a,
11521 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
11522 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
11523 * The element must be removed from the DOM using the 'remove' config option if desired.
11529 // common config options shown with default values
11537 * @param {Object} options (optional) Object literal with any of the Fx config options
11538 * @return {Roo.Element} The Element
11540 puff : function(o){
11541 var el = this.getFxEl();
11544 el.queueFx(o, function(){
11545 this.clearOpacity();
11548 // restore values after effect
11549 var r = this.getFxRestore();
11550 var st = this.dom.style;
11552 var after = function(){
11554 el.setDisplayed(false);
11561 el.setPositioning(r.pos);
11562 st.width = r.width;
11563 st.height = r.height;
11568 var width = this.getWidth();
11569 var height = this.getHeight();
11571 arguments.callee.anim = this.fxanim({
11572 width : {to: this.adjustWidth(width * 2)},
11573 height : {to: this.adjustHeight(height * 2)},
11574 points : {by: [-(width * .5), -(height * .5)]},
11576 fontSize: {to:200, unit: "%"}
11587 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
11588 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
11589 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
11595 // all config options shown with default values
11603 * @param {Object} options (optional) Object literal with any of the Fx config options
11604 * @return {Roo.Element} The Element
11606 switchOff : function(o){
11607 var el = this.getFxEl();
11610 el.queueFx(o, function(){
11611 this.clearOpacity();
11614 // restore values after effect
11615 var r = this.getFxRestore();
11616 var st = this.dom.style;
11618 var after = function(){
11620 el.setDisplayed(false);
11626 el.setPositioning(r.pos);
11627 st.width = r.width;
11628 st.height = r.height;
11633 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
11634 this.clearOpacity();
11638 points:{by:[0, this.getHeight() * .5]}
11639 }, o, 'motion', 0.3, 'easeIn', after);
11640 }).defer(100, this);
11647 * Highlights the Element by setting a color (applies to the background-color by default, but can be
11648 * changed using the "attr" config option) and then fading back to the original color. If no original
11649 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
11652 // default: highlight background to yellow
11655 // custom: highlight foreground text to blue for 2 seconds
11656 el.highlight("0000ff", { attr: 'color', duration: 2 });
11658 // common config options shown with default values
11659 el.highlight("ffff9c", {
11660 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
11661 endColor: (current color) or "ffffff",
11666 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
11667 * @param {Object} options (optional) Object literal with any of the Fx config options
11668 * @return {Roo.Element} The Element
11670 highlight : function(color, o){
11671 var el = this.getFxEl();
11674 el.queueFx(o, function(){
11675 color = color || "ffff9c";
11676 attr = o.attr || "backgroundColor";
11678 this.clearOpacity();
11681 var origColor = this.getColor(attr);
11682 var restoreColor = this.dom.style[attr];
11683 endColor = (o.endColor || origColor) || "ffffff";
11685 var after = function(){
11686 el.dom.style[attr] = restoreColor;
11691 a[attr] = {from: color, to: endColor};
11692 arguments.callee.anim = this.fxanim(a,
11702 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
11705 // default: a single light blue ripple
11708 // custom: 3 red ripples lasting 3 seconds total
11709 el.frame("ff0000", 3, { duration: 3 });
11711 // common config options shown with default values
11712 el.frame("C3DAF9", 1, {
11713 duration: 1 //duration of entire animation (not each individual ripple)
11714 // Note: Easing is not configurable and will be ignored if included
11717 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
11718 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
11719 * @param {Object} options (optional) Object literal with any of the Fx config options
11720 * @return {Roo.Element} The Element
11722 frame : function(color, count, o){
11723 var el = this.getFxEl();
11726 el.queueFx(o, function(){
11727 color = color || "#C3DAF9";
11728 if(color.length == 6){
11729 color = "#" + color;
11731 count = count || 1;
11732 duration = o.duration || 1;
11735 var b = this.getBox();
11736 var animFn = function(){
11737 var proxy = this.createProxy({
11740 visbility:"hidden",
11741 position:"absolute",
11742 "z-index":"35000", // yee haw
11743 border:"0px solid " + color
11746 var scale = Roo.isBorderBox ? 2 : 1;
11748 top:{from:b.y, to:b.y - 20},
11749 left:{from:b.x, to:b.x - 20},
11750 borderWidth:{from:0, to:10},
11751 opacity:{from:1, to:0},
11752 height:{from:b.height, to:(b.height + (20*scale))},
11753 width:{from:b.width, to:(b.width + (20*scale))}
11754 }, duration, function(){
11758 animFn.defer((duration/2)*1000, this);
11769 * Creates a pause before any subsequent queued effects begin. If there are
11770 * no effects queued after the pause it will have no effect.
11775 * @param {Number} seconds The length of time to pause (in seconds)
11776 * @return {Roo.Element} The Element
11778 pause : function(seconds){
11779 var el = this.getFxEl();
11782 el.queueFx(o, function(){
11783 setTimeout(function(){
11785 }, seconds * 1000);
11791 * Fade an element in (from transparent to opaque). The ending opacity can be specified
11792 * using the "endOpacity" config option.
11795 // default: fade in from opacity 0 to 100%
11798 // custom: fade in from opacity 0 to 75% over 2 seconds
11799 el.fadeIn({ endOpacity: .75, duration: 2});
11801 // common config options shown with default values
11803 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
11808 * @param {Object} options (optional) Object literal with any of the Fx config options
11809 * @return {Roo.Element} The Element
11811 fadeIn : function(o){
11812 var el = this.getFxEl();
11814 el.queueFx(o, function(){
11815 this.setOpacity(0);
11817 this.dom.style.visibility = 'visible';
11818 var to = o.endOpacity || 1;
11819 arguments.callee.anim = this.fxanim({opacity:{to:to}},
11820 o, null, .5, "easeOut", function(){
11822 this.clearOpacity();
11831 * Fade an element out (from opaque to transparent). The ending opacity can be specified
11832 * using the "endOpacity" config option.
11835 // default: fade out from the element's current opacity to 0
11838 // custom: fade out from the element's current opacity to 25% over 2 seconds
11839 el.fadeOut({ endOpacity: .25, duration: 2});
11841 // common config options shown with default values
11843 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
11850 * @param {Object} options (optional) Object literal with any of the Fx config options
11851 * @return {Roo.Element} The Element
11853 fadeOut : function(o){
11854 var el = this.getFxEl();
11856 el.queueFx(o, function(){
11857 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
11858 o, null, .5, "easeOut", function(){
11859 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
11860 this.dom.style.display = "none";
11862 this.dom.style.visibility = "hidden";
11864 this.clearOpacity();
11872 * Animates the transition of an element's dimensions from a starting height/width
11873 * to an ending height/width.
11876 // change height and width to 100x100 pixels
11877 el.scale(100, 100);
11879 // common config options shown with default values. The height and width will default to
11880 // the element's existing values if passed as null.
11883 [element's height], {
11888 * @param {Number} width The new width (pass undefined to keep the original width)
11889 * @param {Number} height The new height (pass undefined to keep the original height)
11890 * @param {Object} options (optional) Object literal with any of the Fx config options
11891 * @return {Roo.Element} The Element
11893 scale : function(w, h, o){
11894 this.shift(Roo.apply({}, o, {
11902 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
11903 * Any of these properties not specified in the config object will not be changed. This effect
11904 * requires that at least one new dimension, position or opacity setting must be passed in on
11905 * the config object in order for the function to have any effect.
11908 // slide the element horizontally to x position 200 while changing the height and opacity
11909 el.shift({ x: 200, height: 50, opacity: .8 });
11911 // common config options shown with default values.
11913 width: [element's width],
11914 height: [element's height],
11915 x: [element's x position],
11916 y: [element's y position],
11917 opacity: [element's opacity],
11922 * @param {Object} options Object literal with any of the Fx config options
11923 * @return {Roo.Element} The Element
11925 shift : function(o){
11926 var el = this.getFxEl();
11928 el.queueFx(o, function(){
11929 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
11930 if(w !== undefined){
11931 a.width = {to: this.adjustWidth(w)};
11933 if(h !== undefined){
11934 a.height = {to: this.adjustHeight(h)};
11936 if(x !== undefined || y !== undefined){
11938 x !== undefined ? x : this.getX(),
11939 y !== undefined ? y : this.getY()
11942 if(op !== undefined){
11943 a.opacity = {to: op};
11945 if(o.xy !== undefined){
11946 a.points = {to: o.xy};
11948 arguments.callee.anim = this.fxanim(a,
11949 o, 'motion', .35, "easeOut", function(){
11957 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
11958 * ending point of the effect.
11961 // default: slide the element downward while fading out
11964 // custom: slide the element out to the right with a 2-second duration
11965 el.ghost('r', { duration: 2 });
11967 // common config options shown with default values
11975 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
11976 * @param {Object} options (optional) Object literal with any of the Fx config options
11977 * @return {Roo.Element} The Element
11979 ghost : function(anchor, o){
11980 var el = this.getFxEl();
11983 el.queueFx(o, function(){
11984 anchor = anchor || "b";
11986 // restore values after effect
11987 var r = this.getFxRestore();
11988 var w = this.getWidth(),
11989 h = this.getHeight();
11991 var st = this.dom.style;
11993 var after = function(){
11995 el.setDisplayed(false);
12001 el.setPositioning(r.pos);
12002 st.width = r.width;
12003 st.height = r.height;
12008 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
12009 switch(anchor.toLowerCase()){
12036 arguments.callee.anim = this.fxanim(a,
12046 * Ensures that all effects queued after syncFx is called on the element are
12047 * run concurrently. This is the opposite of {@link #sequenceFx}.
12048 * @return {Roo.Element} The Element
12050 syncFx : function(){
12051 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
12060 * Ensures that all effects queued after sequenceFx is called on the element are
12061 * run in sequence. This is the opposite of {@link #syncFx}.
12062 * @return {Roo.Element} The Element
12064 sequenceFx : function(){
12065 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
12067 concurrent : false,
12074 nextFx : function(){
12075 var ef = this.fxQueue[0];
12082 * Returns true if the element has any effects actively running or queued, else returns false.
12083 * @return {Boolean} True if element has active effects, else false
12085 hasActiveFx : function(){
12086 return this.fxQueue && this.fxQueue[0];
12090 * Stops any running effects and clears the element's internal effects queue if it contains
12091 * any additional effects that haven't started yet.
12092 * @return {Roo.Element} The Element
12094 stopFx : function(){
12095 if(this.hasActiveFx()){
12096 var cur = this.fxQueue[0];
12097 if(cur && cur.anim && cur.anim.isAnimated()){
12098 this.fxQueue = [cur]; // clear out others
12099 cur.anim.stop(true);
12106 beforeFx : function(o){
12107 if(this.hasActiveFx() && !o.concurrent){
12118 * Returns true if the element is currently blocking so that no other effect can be queued
12119 * until this effect is finished, else returns false if blocking is not set. This is commonly
12120 * used to ensure that an effect initiated by a user action runs to completion prior to the
12121 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
12122 * @return {Boolean} True if blocking, else false
12124 hasFxBlock : function(){
12125 var q = this.fxQueue;
12126 return q && q[0] && q[0].block;
12130 queueFx : function(o, fn){
12134 if(!this.hasFxBlock()){
12135 Roo.applyIf(o, this.fxDefaults);
12137 var run = this.beforeFx(o);
12138 fn.block = o.block;
12139 this.fxQueue.push(fn);
12151 fxWrap : function(pos, o, vis){
12153 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
12156 wrapXY = this.getXY();
12158 var div = document.createElement("div");
12159 div.style.visibility = vis;
12160 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
12161 wrap.setPositioning(pos);
12162 if(wrap.getStyle("position") == "static"){
12163 wrap.position("relative");
12165 this.clearPositioning('auto');
12167 wrap.dom.appendChild(this.dom);
12169 wrap.setXY(wrapXY);
12176 fxUnwrap : function(wrap, pos, o){
12177 this.clearPositioning();
12178 this.setPositioning(pos);
12180 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
12186 getFxRestore : function(){
12187 var st = this.dom.style;
12188 return {pos: this.getPositioning(), width: st.width, height : st.height};
12192 afterFx : function(o){
12194 this.applyStyles(o.afterStyle);
12197 this.addClass(o.afterCls);
12199 if(o.remove === true){
12202 Roo.callback(o.callback, o.scope, [this]);
12204 this.fxQueue.shift();
12210 getFxEl : function(){ // support for composite element fx
12211 return Roo.get(this.dom);
12215 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
12216 animType = animType || 'run';
12218 var anim = Roo.lib.Anim[animType](
12220 (opt.duration || defaultDur) || .35,
12221 (opt.easing || defaultEase) || 'easeOut',
12223 Roo.callback(cb, this);
12232 // backwords compat
12233 Roo.Fx.resize = Roo.Fx.scale;
12235 //When included, Roo.Fx is automatically applied to Element so that all basic
12236 //effects are available directly via the Element API
12237 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
12239 * Ext JS Library 1.1.1
12240 * Copyright(c) 2006-2007, Ext JS, LLC.
12242 * Originally Released Under LGPL - original licence link has changed is not relivant.
12245 * <script type="text/javascript">
12250 * @class Roo.CompositeElement
12251 * Standard composite class. Creates a Roo.Element for every element in the collection.
12253 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12254 * actions will be performed on all the elements in this collection.</b>
12256 * All methods return <i>this</i> and can be chained.
12258 var els = Roo.select("#some-el div.some-class", true);
12259 // or select directly from an existing element
12260 var el = Roo.get('some-el');
12261 el.select('div.some-class', true);
12263 els.setWidth(100); // all elements become 100 width
12264 els.hide(true); // all elements fade out and hide
12266 els.setWidth(100).hide(true);
12269 Roo.CompositeElement = function(els){
12270 this.elements = [];
12271 this.addElements(els);
12273 Roo.CompositeElement.prototype = {
12275 addElements : function(els){
12279 if(typeof els == "string"){
12280 els = Roo.Element.selectorFunction(els);
12282 var yels = this.elements;
12283 var index = yels.length-1;
12284 for(var i = 0, len = els.length; i < len; i++) {
12285 yels[++index] = Roo.get(els[i]);
12291 * Clears this composite and adds the elements returned by the passed selector.
12292 * @param {String/Array} els A string CSS selector, an array of elements or an element
12293 * @return {CompositeElement} this
12295 fill : function(els){
12296 this.elements = [];
12302 * Filters this composite to only elements that match the passed selector.
12303 * @param {String} selector A string CSS selector
12304 * @param {Boolean} inverse return inverse filter (not matches)
12305 * @return {CompositeElement} this
12307 filter : function(selector, inverse){
12309 inverse = inverse || false;
12310 this.each(function(el){
12311 var match = inverse ? !el.is(selector) : el.is(selector);
12313 els[els.length] = el.dom;
12320 invoke : function(fn, args){
12321 var els = this.elements;
12322 for(var i = 0, len = els.length; i < len; i++) {
12323 Roo.Element.prototype[fn].apply(els[i], args);
12328 * Adds elements to this composite.
12329 * @param {String/Array} els A string CSS selector, an array of elements or an element
12330 * @return {CompositeElement} this
12332 add : function(els){
12333 if(typeof els == "string"){
12334 this.addElements(Roo.Element.selectorFunction(els));
12335 }else if(els.length !== undefined){
12336 this.addElements(els);
12338 this.addElements([els]);
12343 * Calls the passed function passing (el, this, index) for each element in this composite.
12344 * @param {Function} fn The function to call
12345 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12346 * @return {CompositeElement} this
12348 each : function(fn, scope){
12349 var els = this.elements;
12350 for(var i = 0, len = els.length; i < len; i++){
12351 if(fn.call(scope || els[i], els[i], this, i) === false) {
12359 * Returns the Element object at the specified index
12360 * @param {Number} index
12361 * @return {Roo.Element}
12363 item : function(index){
12364 return this.elements[index] || null;
12368 * Returns the first Element
12369 * @return {Roo.Element}
12371 first : function(){
12372 return this.item(0);
12376 * Returns the last Element
12377 * @return {Roo.Element}
12380 return this.item(this.elements.length-1);
12384 * Returns the number of elements in this composite
12387 getCount : function(){
12388 return this.elements.length;
12392 * Returns true if this composite contains the passed element
12395 contains : function(el){
12396 return this.indexOf(el) !== -1;
12400 * Returns true if this composite contains the passed element
12403 indexOf : function(el){
12404 return this.elements.indexOf(Roo.get(el));
12409 * Removes the specified element(s).
12410 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
12411 * or an array of any of those.
12412 * @param {Boolean} removeDom (optional) True to also remove the element from the document
12413 * @return {CompositeElement} this
12415 removeElement : function(el, removeDom){
12416 if(el instanceof Array){
12417 for(var i = 0, len = el.length; i < len; i++){
12418 this.removeElement(el[i]);
12422 var index = typeof el == 'number' ? el : this.indexOf(el);
12425 var d = this.elements[index];
12429 d.parentNode.removeChild(d);
12432 this.elements.splice(index, 1);
12438 * Replaces the specified element with the passed element.
12439 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
12441 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
12442 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
12443 * @return {CompositeElement} this
12445 replaceElement : function(el, replacement, domReplace){
12446 var index = typeof el == 'number' ? el : this.indexOf(el);
12449 this.elements[index].replaceWith(replacement);
12451 this.elements.splice(index, 1, Roo.get(replacement))
12458 * Removes all elements.
12460 clear : function(){
12461 this.elements = [];
12465 Roo.CompositeElement.createCall = function(proto, fnName){
12466 if(!proto[fnName]){
12467 proto[fnName] = function(){
12468 return this.invoke(fnName, arguments);
12472 for(var fnName in Roo.Element.prototype){
12473 if(typeof Roo.Element.prototype[fnName] == "function"){
12474 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
12480 * Ext JS Library 1.1.1
12481 * Copyright(c) 2006-2007, Ext JS, LLC.
12483 * Originally Released Under LGPL - original licence link has changed is not relivant.
12486 * <script type="text/javascript">
12490 * @class Roo.CompositeElementLite
12491 * @extends Roo.CompositeElement
12492 * Flyweight composite class. Reuses the same Roo.Element for element operations.
12494 var els = Roo.select("#some-el div.some-class");
12495 // or select directly from an existing element
12496 var el = Roo.get('some-el');
12497 el.select('div.some-class');
12499 els.setWidth(100); // all elements become 100 width
12500 els.hide(true); // all elements fade out and hide
12502 els.setWidth(100).hide(true);
12503 </code></pre><br><br>
12504 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12505 * actions will be performed on all the elements in this collection.</b>
12507 Roo.CompositeElementLite = function(els){
12508 Roo.CompositeElementLite.superclass.constructor.call(this, els);
12509 this.el = new Roo.Element.Flyweight();
12511 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
12512 addElements : function(els){
12514 if(els instanceof Array){
12515 this.elements = this.elements.concat(els);
12517 var yels = this.elements;
12518 var index = yels.length-1;
12519 for(var i = 0, len = els.length; i < len; i++) {
12520 yels[++index] = els[i];
12526 invoke : function(fn, args){
12527 var els = this.elements;
12529 for(var i = 0, len = els.length; i < len; i++) {
12531 Roo.Element.prototype[fn].apply(el, args);
12536 * Returns a flyweight Element of the dom element object at the specified index
12537 * @param {Number} index
12538 * @return {Roo.Element}
12540 item : function(index){
12541 if(!this.elements[index]){
12544 this.el.dom = this.elements[index];
12548 // fixes scope with flyweight
12549 addListener : function(eventName, handler, scope, opt){
12550 var els = this.elements;
12551 for(var i = 0, len = els.length; i < len; i++) {
12552 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
12558 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
12559 * passed is the flyweight (shared) Roo.Element instance, so if you require a
12560 * a reference to the dom node, use el.dom.</b>
12561 * @param {Function} fn The function to call
12562 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12563 * @return {CompositeElement} this
12565 each : function(fn, scope){
12566 var els = this.elements;
12568 for(var i = 0, len = els.length; i < len; i++){
12570 if(fn.call(scope || el, el, this, i) === false){
12577 indexOf : function(el){
12578 return this.elements.indexOf(Roo.getDom(el));
12581 replaceElement : function(el, replacement, domReplace){
12582 var index = typeof el == 'number' ? el : this.indexOf(el);
12584 replacement = Roo.getDom(replacement);
12586 var d = this.elements[index];
12587 d.parentNode.insertBefore(replacement, d);
12588 d.parentNode.removeChild(d);
12590 this.elements.splice(index, 1, replacement);
12595 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
12599 * Ext JS Library 1.1.1
12600 * Copyright(c) 2006-2007, Ext JS, LLC.
12602 * Originally Released Under LGPL - original licence link has changed is not relivant.
12605 * <script type="text/javascript">
12611 * @class Roo.data.Connection
12612 * @extends Roo.util.Observable
12613 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
12614 * either to a configured URL, or to a URL specified at request time.
12616 * Requests made by this class are asynchronous, and will return immediately. No data from
12617 * the server will be available to the statement immediately following the {@link #request} call.
12618 * To process returned data, use a callback in the request options object, or an event listener.
12620 * Note: If you are doing a file upload, you will not get a normal response object sent back to
12621 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
12622 * The response object is created using the innerHTML of the IFRAME's document as the responseText
12623 * property and, if present, the IFRAME's XML document as the responseXML property.
12625 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
12626 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
12627 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
12628 * standard DOM methods.
12630 * @param {Object} config a configuration object.
12632 Roo.data.Connection = function(config){
12633 Roo.apply(this, config);
12636 * @event beforerequest
12637 * Fires before a network request is made to retrieve a data object.
12638 * @param {Connection} conn This Connection object.
12639 * @param {Object} options The options config object passed to the {@link #request} method.
12641 "beforerequest" : true,
12643 * @event requestcomplete
12644 * Fires if the request was successfully completed.
12645 * @param {Connection} conn This Connection object.
12646 * @param {Object} response The XHR object containing the response data.
12647 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12648 * @param {Object} options The options config object passed to the {@link #request} method.
12650 "requestcomplete" : true,
12652 * @event requestexception
12653 * Fires if an error HTTP status was returned from the server.
12654 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
12655 * @param {Connection} conn This Connection object.
12656 * @param {Object} response The XHR object containing the response data.
12657 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12658 * @param {Object} options The options config object passed to the {@link #request} method.
12660 "requestexception" : true
12662 Roo.data.Connection.superclass.constructor.call(this);
12665 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
12667 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12670 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12671 * extra parameters to each request made by this object. (defaults to undefined)
12674 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12675 * to each request made by this object. (defaults to undefined)
12678 * @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)
12681 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12685 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12691 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12694 disableCaching: true,
12697 * Sends an HTTP request to a remote server.
12698 * @param {Object} options An object which may contain the following properties:<ul>
12699 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
12700 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
12701 * request, a url encoded string or a function to call to get either.</li>
12702 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
12703 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
12704 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
12705 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
12706 * <li>options {Object} The parameter to the request call.</li>
12707 * <li>success {Boolean} True if the request succeeded.</li>
12708 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12710 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
12711 * The callback is passed the following parameters:<ul>
12712 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12713 * <li>options {Object} The parameter to the request call.</li>
12715 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
12716 * The callback is passed the following parameters:<ul>
12717 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12718 * <li>options {Object} The parameter to the request call.</li>
12720 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
12721 * for the callback function. Defaults to the browser window.</li>
12722 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
12723 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
12724 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
12725 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
12726 * params for the post data. Any params will be appended to the URL.</li>
12727 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
12729 * @return {Number} transactionId
12731 request : function(o){
12732 if(this.fireEvent("beforerequest", this, o) !== false){
12735 if(typeof p == "function"){
12736 p = p.call(o.scope||window, o);
12738 if(typeof p == "object"){
12739 p = Roo.urlEncode(o.params);
12741 if(this.extraParams){
12742 var extras = Roo.urlEncode(this.extraParams);
12743 p = p ? (p + '&' + extras) : extras;
12746 var url = o.url || this.url;
12747 if(typeof url == 'function'){
12748 url = url.call(o.scope||window, o);
12752 var form = Roo.getDom(o.form);
12753 url = url || form.action;
12755 var enctype = form.getAttribute("enctype");
12758 return this.doFormDataUpload(o, url);
12761 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
12762 return this.doFormUpload(o, p, url);
12764 var f = Roo.lib.Ajax.serializeForm(form);
12765 p = p ? (p + '&' + f) : f;
12768 if (!o.form && o.formData) {
12769 o.formData = o.formData === true ? new FormData() : o.formData;
12770 for (var k in o.params) {
12771 o.formData.append(k,o.params[k]);
12774 return this.doFormDataUpload(o, url);
12778 var hs = o.headers;
12779 if(this.defaultHeaders){
12780 hs = Roo.apply(hs || {}, this.defaultHeaders);
12787 success: this.handleResponse,
12788 failure: this.handleFailure,
12790 argument: {options: o},
12791 timeout : o.timeout || this.timeout
12794 var method = o.method||this.method||(p ? "POST" : "GET");
12796 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
12797 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
12800 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
12804 }else if(this.autoAbort !== false){
12808 if((method == 'GET' && p) || o.xmlData){
12809 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
12812 Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
12813 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
12814 Roo.lib.Ajax.useDefaultHeader == true;
12815 return this.transId;
12817 Roo.callback(o.callback, o.scope, [o, null, null]);
12823 * Determine whether this object has a request outstanding.
12824 * @param {Number} transactionId (Optional) defaults to the last transaction
12825 * @return {Boolean} True if there is an outstanding request.
12827 isLoading : function(transId){
12829 return Roo.lib.Ajax.isCallInProgress(transId);
12831 return this.transId ? true : false;
12836 * Aborts any outstanding request.
12837 * @param {Number} transactionId (Optional) defaults to the last transaction
12839 abort : function(transId){
12840 if(transId || this.isLoading()){
12841 Roo.lib.Ajax.abort(transId || this.transId);
12846 handleResponse : function(response){
12847 this.transId = false;
12848 var options = response.argument.options;
12849 response.argument = options ? options.argument : null;
12850 this.fireEvent("requestcomplete", this, response, options);
12851 Roo.callback(options.success, options.scope, [response, options]);
12852 Roo.callback(options.callback, options.scope, [options, true, response]);
12856 handleFailure : function(response, e){
12857 this.transId = false;
12858 var options = response.argument.options;
12859 response.argument = options ? options.argument : null;
12860 this.fireEvent("requestexception", this, response, options, e);
12861 Roo.callback(options.failure, options.scope, [response, options]);
12862 Roo.callback(options.callback, options.scope, [options, false, response]);
12866 doFormUpload : function(o, ps, url){
12868 var frame = document.createElement('iframe');
12871 frame.className = 'x-hidden';
12873 frame.src = Roo.SSL_SECURE_URL;
12875 document.body.appendChild(frame);
12878 document.frames[id].name = id;
12881 var form = Roo.getDom(o.form);
12883 form.method = 'POST';
12884 form.enctype = form.encoding = 'multipart/form-data';
12890 if(ps){ // add dynamic params
12892 ps = Roo.urlDecode(ps, false);
12894 if(ps.hasOwnProperty(k)){
12895 hd = document.createElement('input');
12896 hd.type = 'hidden';
12899 form.appendChild(hd);
12906 var r = { // bogus response object
12911 r.argument = o ? o.argument : null;
12916 doc = frame.contentWindow.document;
12918 doc = (frame.contentDocument || window.frames[id].document);
12920 if(doc && doc.body){
12921 r.responseText = doc.body.innerHTML;
12923 if(doc && doc.XMLDocument){
12924 r.responseXML = doc.XMLDocument;
12926 r.responseXML = doc;
12933 Roo.EventManager.removeListener(frame, 'load', cb, this);
12935 this.fireEvent("requestcomplete", this, r, o);
12936 Roo.callback(o.success, o.scope, [r, o]);
12937 Roo.callback(o.callback, o.scope, [o, true, r]);
12939 setTimeout(function(){document.body.removeChild(frame);}, 100);
12942 Roo.EventManager.on(frame, 'load', cb, this);
12945 if(hiddens){ // remove dynamic params
12946 for(var i = 0, len = hiddens.length; i < len; i++){
12947 form.removeChild(hiddens[i]);
12951 // this is a 'formdata version???'
12954 doFormDataUpload : function(o, url)
12958 var form = Roo.getDom(o.form);
12959 form.enctype = form.encoding = 'multipart/form-data';
12960 formData = o.formData === true ? new FormData(form) : o.formData;
12962 formData = o.formData === true ? new FormData() : o.formData;
12967 success: this.handleResponse,
12968 failure: this.handleFailure,
12970 argument: {options: o},
12971 timeout : o.timeout || this.timeout
12974 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
12978 }else if(this.autoAbort !== false){
12982 //Roo.lib.Ajax.defaultPostHeader = null;
12983 Roo.lib.Ajax.useDefaultHeader = false;
12984 this.transId = Roo.lib.Ajax.request( "POST", url, cb, formData, o);
12985 Roo.lib.Ajax.useDefaultHeader = true;
12993 * Ext JS Library 1.1.1
12994 * Copyright(c) 2006-2007, Ext JS, LLC.
12996 * Originally Released Under LGPL - original licence link has changed is not relivant.
12999 * <script type="text/javascript">
13003 * Global Ajax request class.
13006 * @extends Roo.data.Connection
13009 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
13010 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
13011 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
13012 * @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)
13013 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
13014 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
13015 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
13017 Roo.Ajax = new Roo.data.Connection({
13026 * Serialize the passed form into a url encoded string
13028 * @param {String/HTMLElement} form
13031 serializeForm : function(form){
13032 return Roo.lib.Ajax.serializeForm(form);
13036 * Ext JS Library 1.1.1
13037 * Copyright(c) 2006-2007, Ext JS, LLC.
13039 * Originally Released Under LGPL - original licence link has changed is not relivant.
13042 * <script type="text/javascript">
13047 * @class Roo.UpdateManager
13048 * @extends Roo.util.Observable
13049 * Provides AJAX-style update for Element object.<br><br>
13052 * // Get it from a Roo.Element object
13053 * var el = Roo.get("foo");
13054 * var mgr = el.getUpdateManager();
13055 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
13057 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
13059 * // or directly (returns the same UpdateManager instance)
13060 * var mgr = new Roo.UpdateManager("myElementId");
13061 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
13062 * mgr.on("update", myFcnNeedsToKnow);
13064 // short handed call directly from the element object
13065 Roo.get("foo").load({
13069 text: "Loading Foo..."
13073 * Create new UpdateManager directly.
13074 * @param {String/HTMLElement/Roo.Element} el The element to update
13075 * @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).
13077 Roo.UpdateManager = function(el, forceNew){
13079 if(!forceNew && el.updateManager){
13080 return el.updateManager;
13083 * The Element object
13084 * @type Roo.Element
13088 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
13091 this.defaultUrl = null;
13095 * @event beforeupdate
13096 * Fired before an update is made, return false from your handler and the update is cancelled.
13097 * @param {Roo.Element} el
13098 * @param {String/Object/Function} url
13099 * @param {String/Object} params
13101 "beforeupdate": true,
13104 * Fired after successful update is made.
13105 * @param {Roo.Element} el
13106 * @param {Object} oResponseObject The response Object
13111 * Fired on update failure.
13112 * @param {Roo.Element} el
13113 * @param {Object} oResponseObject The response Object
13117 var d = Roo.UpdateManager.defaults;
13119 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
13122 this.sslBlankUrl = d.sslBlankUrl;
13124 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
13127 this.disableCaching = d.disableCaching;
13129 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
13132 this.indicatorText = d.indicatorText;
13134 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
13137 this.showLoadIndicator = d.showLoadIndicator;
13139 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
13142 this.timeout = d.timeout;
13145 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
13148 this.loadScripts = d.loadScripts;
13151 * Transaction object of current executing transaction
13153 this.transaction = null;
13158 this.autoRefreshProcId = null;
13160 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
13163 this.refreshDelegate = this.refresh.createDelegate(this);
13165 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
13168 this.updateDelegate = this.update.createDelegate(this);
13170 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
13173 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
13177 this.successDelegate = this.processSuccess.createDelegate(this);
13181 this.failureDelegate = this.processFailure.createDelegate(this);
13183 if(!this.renderer){
13185 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
13187 this.renderer = new Roo.UpdateManager.BasicRenderer();
13190 Roo.UpdateManager.superclass.constructor.call(this);
13193 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
13195 * Get the Element this UpdateManager is bound to
13196 * @return {Roo.Element} The element
13198 getEl : function(){
13202 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
13203 * @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:
13206 url: "your-url.php",<br/>
13207 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
13208 callback: yourFunction,<br/>
13209 scope: yourObject, //(optional scope) <br/>
13210 discardUrl: false, <br/>
13211 nocache: false,<br/>
13212 text: "Loading...",<br/>
13214 scripts: false<br/>
13217 * The only required property is url. The optional properties nocache, text and scripts
13218 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
13219 * @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}
13220 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13221 * @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.
13223 update : function(url, params, callback, discardUrl){
13224 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
13225 var method = this.method,
13227 if(typeof url == "object"){ // must be config object
13230 params = params || cfg.params;
13231 callback = callback || cfg.callback;
13232 discardUrl = discardUrl || cfg.discardUrl;
13233 if(callback && cfg.scope){
13234 callback = callback.createDelegate(cfg.scope);
13236 if(typeof cfg.method != "undefined"){method = cfg.method;};
13237 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
13238 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
13239 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
13240 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
13242 this.showLoading();
13244 this.defaultUrl = url;
13246 if(typeof url == "function"){
13247 url = url.call(this);
13250 method = method || (params ? "POST" : "GET");
13251 if(method == "GET"){
13252 url = this.prepareUrl(url);
13255 var o = Roo.apply(cfg ||{}, {
13258 success: this.successDelegate,
13259 failure: this.failureDelegate,
13260 callback: undefined,
13261 timeout: (this.timeout*1000),
13262 argument: {"url": url, "form": null, "callback": callback, "params": params}
13264 Roo.log("updated manager called with timeout of " + o.timeout);
13265 this.transaction = Roo.Ajax.request(o);
13270 * 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.
13271 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
13272 * @param {String/HTMLElement} form The form Id or form element
13273 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
13274 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
13275 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13277 formUpdate : function(form, url, reset, callback){
13278 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
13279 if(typeof url == "function"){
13280 url = url.call(this);
13282 form = Roo.getDom(form);
13283 this.transaction = Roo.Ajax.request({
13286 success: this.successDelegate,
13287 failure: this.failureDelegate,
13288 timeout: (this.timeout*1000),
13289 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
13291 this.showLoading.defer(1, this);
13296 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
13297 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13299 refresh : function(callback){
13300 if(this.defaultUrl == null){
13303 this.update(this.defaultUrl, null, callback, true);
13307 * Set this element to auto refresh.
13308 * @param {Number} interval How often to update (in seconds).
13309 * @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)
13310 * @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}
13311 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13312 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
13314 startAutoRefresh : function(interval, url, params, callback, refreshNow){
13316 this.update(url || this.defaultUrl, params, callback, true);
13318 if(this.autoRefreshProcId){
13319 clearInterval(this.autoRefreshProcId);
13321 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
13325 * Stop auto refresh on this element.
13327 stopAutoRefresh : function(){
13328 if(this.autoRefreshProcId){
13329 clearInterval(this.autoRefreshProcId);
13330 delete this.autoRefreshProcId;
13334 isAutoRefreshing : function(){
13335 return this.autoRefreshProcId ? true : false;
13338 * Called to update the element to "Loading" state. Override to perform custom action.
13340 showLoading : function(){
13341 if(this.showLoadIndicator){
13342 this.el.update(this.indicatorText);
13347 * Adds unique parameter to query string if disableCaching = true
13350 prepareUrl : function(url){
13351 if(this.disableCaching){
13352 var append = "_dc=" + (new Date().getTime());
13353 if(url.indexOf("?") !== -1){
13354 url += "&" + append;
13356 url += "?" + append;
13365 processSuccess : function(response){
13366 this.transaction = null;
13367 if(response.argument.form && response.argument.reset){
13368 try{ // put in try/catch since some older FF releases had problems with this
13369 response.argument.form.reset();
13372 if(this.loadScripts){
13373 this.renderer.render(this.el, response, this,
13374 this.updateComplete.createDelegate(this, [response]));
13376 this.renderer.render(this.el, response, this);
13377 this.updateComplete(response);
13381 updateComplete : function(response){
13382 this.fireEvent("update", this.el, response);
13383 if(typeof response.argument.callback == "function"){
13384 response.argument.callback(this.el, true, response);
13391 processFailure : function(response){
13392 this.transaction = null;
13393 this.fireEvent("failure", this.el, response);
13394 if(typeof response.argument.callback == "function"){
13395 response.argument.callback(this.el, false, response);
13400 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
13401 * @param {Object} renderer The object implementing the render() method
13403 setRenderer : function(renderer){
13404 this.renderer = renderer;
13407 getRenderer : function(){
13408 return this.renderer;
13412 * Set the defaultUrl used for updates
13413 * @param {String/Function} defaultUrl The url or a function to call to get the url
13415 setDefaultUrl : function(defaultUrl){
13416 this.defaultUrl = defaultUrl;
13420 * Aborts the executing transaction
13422 abort : function(){
13423 if(this.transaction){
13424 Roo.Ajax.abort(this.transaction);
13429 * Returns true if an update is in progress
13430 * @return {Boolean}
13432 isUpdating : function(){
13433 if(this.transaction){
13434 return Roo.Ajax.isLoading(this.transaction);
13441 * @class Roo.UpdateManager.defaults
13442 * @static (not really - but it helps the doc tool)
13443 * The defaults collection enables customizing the default properties of UpdateManager
13445 Roo.UpdateManager.defaults = {
13447 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
13453 * True to process scripts by default (Defaults to false).
13456 loadScripts : false,
13459 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
13462 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
13464 * Whether to append unique parameter on get request to disable caching (Defaults to false).
13467 disableCaching : false,
13469 * Whether to show indicatorText when loading (Defaults to true).
13472 showLoadIndicator : true,
13474 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
13477 indicatorText : '<div class="loading-indicator">Loading...</div>'
13481 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
13483 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
13484 * @param {String/HTMLElement/Roo.Element} el The element to update
13485 * @param {String} url The url
13486 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
13487 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
13490 * @member Roo.UpdateManager
13492 Roo.UpdateManager.updateElement = function(el, url, params, options){
13493 var um = Roo.get(el, true).getUpdateManager();
13494 Roo.apply(um, options);
13495 um.update(url, params, options ? options.callback : null);
13497 // alias for backwards compat
13498 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
13500 * @class Roo.UpdateManager.BasicRenderer
13501 * Default Content renderer. Updates the elements innerHTML with the responseText.
13503 Roo.UpdateManager.BasicRenderer = function(){};
13505 Roo.UpdateManager.BasicRenderer.prototype = {
13507 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
13508 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
13509 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
13510 * @param {Roo.Element} el The element being rendered
13511 * @param {Object} response The YUI Connect response object
13512 * @param {UpdateManager} updateManager The calling update manager
13513 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
13515 render : function(el, response, updateManager, callback){
13516 el.update(response.responseText, updateManager.loadScripts, callback);
13522 * (c)) Alan Knowles
13528 * @class Roo.DomTemplate
13529 * @extends Roo.Template
13530 * An effort at a dom based template engine..
13532 * Similar to XTemplate, except it uses dom parsing to create the template..
13534 * Supported features:
13539 {a_variable} - output encoded.
13540 {a_variable.format:("Y-m-d")} - call a method on the variable
13541 {a_variable:raw} - unencoded output
13542 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
13543 {a_variable:this.method_on_template(...)} - call a method on the template object.
13548 <div roo-for="a_variable or condition.."></div>
13549 <div roo-if="a_variable or condition"></div>
13550 <div roo-exec="some javascript"></div>
13551 <div roo-name="named_template"></div>
13556 Roo.DomTemplate = function()
13558 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
13565 Roo.extend(Roo.DomTemplate, Roo.Template, {
13567 * id counter for sub templates.
13571 * flag to indicate if dom parser is inside a pre,
13572 * it will strip whitespace if not.
13577 * The various sub templates
13585 * basic tag replacing syntax
13588 * // you can fake an object call by doing this
13592 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
13593 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
13595 iterChild : function (node, method) {
13597 var oldPre = this.inPre;
13598 if (node.tagName == 'PRE') {
13601 for( var i = 0; i < node.childNodes.length; i++) {
13602 method.call(this, node.childNodes[i]);
13604 this.inPre = oldPre;
13610 * compile the template
13612 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
13615 compile: function()
13619 // covert the html into DOM...
13623 doc = document.implementation.createHTMLDocument("");
13624 doc.documentElement.innerHTML = this.html ;
13625 div = doc.documentElement;
13627 // old IE... - nasty -- it causes all sorts of issues.. with
13628 // images getting pulled from server..
13629 div = document.createElement('div');
13630 div.innerHTML = this.html;
13632 //doc.documentElement.innerHTML = htmlBody
13638 this.iterChild(div, function(n) {_t.compileNode(n, true); });
13640 var tpls = this.tpls;
13642 // create a top level template from the snippet..
13644 //Roo.log(div.innerHTML);
13651 body : div.innerHTML,
13664 Roo.each(tpls, function(tp){
13665 this.compileTpl(tp);
13666 this.tpls[tp.id] = tp;
13669 this.master = tpls[0];
13675 compileNode : function(node, istop) {
13680 // skip anything not a tag..
13681 if (node.nodeType != 1) {
13682 if (node.nodeType == 3 && !this.inPre) {
13683 // reduce white space..
13684 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
13707 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
13708 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
13709 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
13710 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
13716 // just itterate children..
13717 this.iterChild(node,this.compileNode);
13720 tpl.uid = this.id++;
13721 tpl.value = node.getAttribute('roo-' + tpl.attr);
13722 node.removeAttribute('roo-'+ tpl.attr);
13723 if (tpl.attr != 'name') {
13724 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
13725 node.parentNode.replaceChild(placeholder, node);
13728 var placeholder = document.createElement('span');
13729 placeholder.className = 'roo-tpl-' + tpl.value;
13730 node.parentNode.replaceChild(placeholder, node);
13733 // parent now sees '{domtplXXXX}
13734 this.iterChild(node,this.compileNode);
13736 // we should now have node body...
13737 var div = document.createElement('div');
13738 div.appendChild(node);
13740 // this has the unfortunate side effect of converting tagged attributes
13741 // eg. href="{...}" into %7C...%7D
13742 // this has been fixed by searching for those combo's although it's a bit hacky..
13745 tpl.body = div.innerHTML;
13752 switch (tpl.value) {
13753 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
13754 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
13755 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
13760 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13764 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13768 tpl.id = tpl.value; // replace non characters???
13774 this.tpls.push(tpl);
13784 * Compile a segment of the template into a 'sub-template'
13790 compileTpl : function(tpl)
13792 var fm = Roo.util.Format;
13793 var useF = this.disableFormats !== true;
13795 var sep = Roo.isGecko ? "+\n" : ",\n";
13797 var undef = function(str) {
13798 Roo.debug && Roo.log("Property not found :" + str);
13802 //Roo.log(tpl.body);
13806 var fn = function(m, lbrace, name, format, args)
13809 //Roo.log(arguments);
13810 args = args ? args.replace(/\\'/g,"'") : args;
13811 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
13812 if (typeof(format) == 'undefined') {
13813 format = 'htmlEncode';
13815 if (format == 'raw' ) {
13819 if(name.substr(0, 6) == 'domtpl'){
13820 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
13823 // build an array of options to determine if value is undefined..
13825 // basically get 'xxxx.yyyy' then do
13826 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
13827 // (function () { Roo.log("Property not found"); return ''; })() :
13832 Roo.each(name.split('.'), function(st) {
13833 lookfor += (lookfor.length ? '.': '') + st;
13834 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
13837 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
13840 if(format && useF){
13842 args = args ? ',' + args : "";
13844 if(format.substr(0, 5) != "this."){
13845 format = "fm." + format + '(';
13847 format = 'this.call("'+ format.substr(5) + '", ';
13851 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
13854 if (args && args.length) {
13855 // called with xxyx.yuu:(test,test)
13857 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
13859 // raw.. - :raw modifier..
13860 return "'"+ sep + udef_st + name + ")"+sep+"'";
13864 // branched to use + in gecko and [].join() in others
13866 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
13867 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
13870 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
13871 body.push(tpl.body.replace(/(\r\n|\n)/g,
13872 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
13873 body.push("'].join('');};};");
13874 body = body.join('');
13877 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
13879 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
13886 * same as applyTemplate, except it's done to one of the subTemplates
13887 * when using named templates, you can do:
13889 * var str = pl.applySubTemplate('your-name', values);
13892 * @param {Number} id of the template
13893 * @param {Object} values to apply to template
13894 * @param {Object} parent (normaly the instance of this object)
13896 applySubTemplate : function(id, values, parent)
13900 var t = this.tpls[id];
13904 if(t.ifCall && !t.ifCall.call(this, values, parent)){
13905 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
13909 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
13916 if(t.execCall && t.execCall.call(this, values, parent)){
13920 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
13926 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
13927 parent = t.target ? values : parent;
13928 if(t.forCall && vs instanceof Array){
13930 for(var i = 0, len = vs.length; i < len; i++){
13932 buf[buf.length] = t.compiled.call(this, vs[i], parent);
13934 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
13936 //Roo.log(t.compiled);
13940 return buf.join('');
13943 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
13948 return t.compiled.call(this, vs, parent);
13950 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
13952 //Roo.log(t.compiled);
13960 applyTemplate : function(values){
13961 return this.master.compiled.call(this, values, {});
13962 //var s = this.subs;
13965 apply : function(){
13966 return this.applyTemplate.apply(this, arguments);
13971 Roo.DomTemplate.from = function(el){
13972 el = Roo.getDom(el);
13973 return new Roo.Domtemplate(el.value || el.innerHTML);
13976 * Ext JS Library 1.1.1
13977 * Copyright(c) 2006-2007, Ext JS, LLC.
13979 * Originally Released Under LGPL - original licence link has changed is not relivant.
13982 * <script type="text/javascript">
13986 * @class Roo.util.DelayedTask
13987 * Provides a convenient method of performing setTimeout where a new
13988 * timeout cancels the old timeout. An example would be performing validation on a keypress.
13989 * You can use this class to buffer
13990 * the keypress events for a certain number of milliseconds, and perform only if they stop
13991 * for that amount of time.
13992 * @constructor The parameters to this constructor serve as defaults and are not required.
13993 * @param {Function} fn (optional) The default function to timeout
13994 * @param {Object} scope (optional) The default scope of that timeout
13995 * @param {Array} args (optional) The default Array of arguments
13997 Roo.util.DelayedTask = function(fn, scope, args){
13998 var id = null, d, t;
14000 var call = function(){
14001 var now = new Date().getTime();
14005 fn.apply(scope, args || []);
14009 * Cancels any pending timeout and queues a new one
14010 * @param {Number} delay The milliseconds to delay
14011 * @param {Function} newFn (optional) Overrides function passed to constructor
14012 * @param {Object} newScope (optional) Overrides scope passed to constructor
14013 * @param {Array} newArgs (optional) Overrides args passed to constructor
14015 this.delay = function(delay, newFn, newScope, newArgs){
14016 if(id && delay != d){
14020 t = new Date().getTime();
14022 scope = newScope || scope;
14023 args = newArgs || args;
14025 id = setInterval(call, d);
14030 * Cancel the last queued timeout
14032 this.cancel = function(){
14040 * Ext JS Library 1.1.1
14041 * Copyright(c) 2006-2007, Ext JS, LLC.
14043 * Originally Released Under LGPL - original licence link has changed is not relivant.
14046 * <script type="text/javascript">
14049 * @class Roo.util.TaskRunner
14050 * Manage background tasks - not sure why this is better that setInterval?
14055 Roo.util.TaskRunner = function(interval){
14056 interval = interval || 10;
14057 var tasks = [], removeQueue = [];
14059 var running = false;
14061 var stopThread = function(){
14067 var startThread = function(){
14070 id = setInterval(runTasks, interval);
14074 var removeTask = function(task){
14075 removeQueue.push(task);
14081 var runTasks = function(){
14082 if(removeQueue.length > 0){
14083 for(var i = 0, len = removeQueue.length; i < len; i++){
14084 tasks.remove(removeQueue[i]);
14087 if(tasks.length < 1){
14092 var now = new Date().getTime();
14093 for(var i = 0, len = tasks.length; i < len; ++i){
14095 var itime = now - t.taskRunTime;
14096 if(t.interval <= itime){
14097 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
14098 t.taskRunTime = now;
14099 if(rt === false || t.taskRunCount === t.repeat){
14104 if(t.duration && t.duration <= (now - t.taskStartTime)){
14111 * Queues a new task.
14112 * @param {Object} task
14114 * Task property : interval = how frequent to run.
14115 * Task object should implement
14117 * Task object may implement
14118 * function onStop()
14120 this.start = function(task){
14122 task.taskStartTime = new Date().getTime();
14123 task.taskRunTime = 0;
14124 task.taskRunCount = 0;
14130 * @param {Object} task
14132 this.stop = function(task){
14139 this.stopAll = function(){
14141 for(var i = 0, len = tasks.length; i < len; i++){
14142 if(tasks[i].onStop){
14151 Roo.TaskMgr = new Roo.util.TaskRunner();/*
14153 * Ext JS Library 1.1.1
14154 * Copyright(c) 2006-2007, Ext JS, LLC.
14156 * Originally Released Under LGPL - original licence link has changed is not relivant.
14159 * <script type="text/javascript">
14164 * @class Roo.util.MixedCollection
14165 * @extends Roo.util.Observable
14166 * A Collection class that maintains both numeric indexes and keys and exposes events.
14168 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
14169 * collection (defaults to false)
14170 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
14171 * and return the key value for that item. This is used when available to look up the key on items that
14172 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
14173 * equivalent to providing an implementation for the {@link #getKey} method.
14175 Roo.util.MixedCollection = function(allowFunctions, keyFn){
14183 * Fires when the collection is cleared.
14188 * Fires when an item is added to the collection.
14189 * @param {Number} index The index at which the item was added.
14190 * @param {Object} o The item added.
14191 * @param {String} key The key associated with the added item.
14196 * Fires when an item is replaced in the collection.
14197 * @param {String} key he key associated with the new added.
14198 * @param {Object} old The item being replaced.
14199 * @param {Object} new The new item.
14204 * Fires when an item is removed from the collection.
14205 * @param {Object} o The item being removed.
14206 * @param {String} key (optional) The key associated with the removed item.
14211 this.allowFunctions = allowFunctions === true;
14213 this.getKey = keyFn;
14215 Roo.util.MixedCollection.superclass.constructor.call(this);
14218 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
14219 allowFunctions : false,
14222 * Adds an item to the collection.
14223 * @param {String} key The key to associate with the item
14224 * @param {Object} o The item to add.
14225 * @return {Object} The item added.
14227 add : function(key, o){
14228 if(arguments.length == 1){
14230 key = this.getKey(o);
14232 if(typeof key == "undefined" || key === null){
14234 this.items.push(o);
14235 this.keys.push(null);
14237 var old = this.map[key];
14239 return this.replace(key, o);
14242 this.items.push(o);
14244 this.keys.push(key);
14246 this.fireEvent("add", this.length-1, o, key);
14251 * MixedCollection has a generic way to fetch keys if you implement getKey.
14254 var mc = new Roo.util.MixedCollection();
14255 mc.add(someEl.dom.id, someEl);
14256 mc.add(otherEl.dom.id, otherEl);
14260 var mc = new Roo.util.MixedCollection();
14261 mc.getKey = function(el){
14267 // or via the constructor
14268 var mc = new Roo.util.MixedCollection(false, function(el){
14274 * @param o {Object} The item for which to find the key.
14275 * @return {Object} The key for the passed item.
14277 getKey : function(o){
14282 * Replaces an item in the collection.
14283 * @param {String} key The key associated with the item to replace, or the item to replace.
14284 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
14285 * @return {Object} The new item.
14287 replace : function(key, o){
14288 if(arguments.length == 1){
14290 key = this.getKey(o);
14292 var old = this.item(key);
14293 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
14294 return this.add(key, o);
14296 var index = this.indexOfKey(key);
14297 this.items[index] = o;
14299 this.fireEvent("replace", key, old, o);
14304 * Adds all elements of an Array or an Object to the collection.
14305 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
14306 * an Array of values, each of which are added to the collection.
14308 addAll : function(objs){
14309 if(arguments.length > 1 || objs instanceof Array){
14310 var args = arguments.length > 1 ? arguments : objs;
14311 for(var i = 0, len = args.length; i < len; i++){
14315 for(var key in objs){
14316 if(this.allowFunctions || typeof objs[key] != "function"){
14317 this.add(key, objs[key]);
14324 * Executes the specified function once for every item in the collection, passing each
14325 * item as the first and only parameter. returning false from the function will stop the iteration.
14326 * @param {Function} fn The function to execute for each item.
14327 * @param {Object} scope (optional) The scope in which to execute the function.
14329 each : function(fn, scope){
14330 var items = [].concat(this.items); // each safe for removal
14331 for(var i = 0, len = items.length; i < len; i++){
14332 if(fn.call(scope || items[i], items[i], i, len) === false){
14339 * Executes the specified function once for every key in the collection, passing each
14340 * key, and its associated item as the first two parameters.
14341 * @param {Function} fn The function to execute for each item.
14342 * @param {Object} scope (optional) The scope in which to execute the function.
14344 eachKey : function(fn, scope){
14345 for(var i = 0, len = this.keys.length; i < len; i++){
14346 fn.call(scope || window, this.keys[i], this.items[i], i, len);
14351 * Returns the first item in the collection which elicits a true return value from the
14352 * passed selection function.
14353 * @param {Function} fn The selection function to execute for each item.
14354 * @param {Object} scope (optional) The scope in which to execute the function.
14355 * @return {Object} The first item in the collection which returned true from the selection function.
14357 find : function(fn, scope){
14358 for(var i = 0, len = this.items.length; i < len; i++){
14359 if(fn.call(scope || window, this.items[i], this.keys[i])){
14360 return this.items[i];
14367 * Inserts an item at the specified index in the collection.
14368 * @param {Number} index The index to insert the item at.
14369 * @param {String} key The key to associate with the new item, or the item itself.
14370 * @param {Object} o (optional) If the second parameter was a key, the new item.
14371 * @return {Object} The item inserted.
14373 insert : function(index, key, o){
14374 if(arguments.length == 2){
14376 key = this.getKey(o);
14378 if(index >= this.length){
14379 return this.add(key, o);
14382 this.items.splice(index, 0, o);
14383 if(typeof key != "undefined" && key != null){
14386 this.keys.splice(index, 0, key);
14387 this.fireEvent("add", index, o, key);
14392 * Removed an item from the collection.
14393 * @param {Object} o The item to remove.
14394 * @return {Object} The item removed.
14396 remove : function(o){
14397 return this.removeAt(this.indexOf(o));
14401 * Remove an item from a specified index in the collection.
14402 * @param {Number} index The index within the collection of the item to remove.
14404 removeAt : function(index){
14405 if(index < this.length && index >= 0){
14407 var o = this.items[index];
14408 this.items.splice(index, 1);
14409 var key = this.keys[index];
14410 if(typeof key != "undefined"){
14411 delete this.map[key];
14413 this.keys.splice(index, 1);
14414 this.fireEvent("remove", o, key);
14419 * Removed an item associated with the passed key fom the collection.
14420 * @param {String} key The key of the item to remove.
14422 removeKey : function(key){
14423 return this.removeAt(this.indexOfKey(key));
14427 * Returns the number of items in the collection.
14428 * @return {Number} the number of items in the collection.
14430 getCount : function(){
14431 return this.length;
14435 * Returns index within the collection of the passed Object.
14436 * @param {Object} o The item to find the index of.
14437 * @return {Number} index of the item.
14439 indexOf : function(o){
14440 if(!this.items.indexOf){
14441 for(var i = 0, len = this.items.length; i < len; i++){
14442 if(this.items[i] == o) {
14448 return this.items.indexOf(o);
14453 * Returns index within the collection of the passed key.
14454 * @param {String} key The key to find the index of.
14455 * @return {Number} index of the key.
14457 indexOfKey : function(key){
14458 if(!this.keys.indexOf){
14459 for(var i = 0, len = this.keys.length; i < len; i++){
14460 if(this.keys[i] == key) {
14466 return this.keys.indexOf(key);
14471 * Returns the item associated with the passed key OR index. Key has priority over index.
14472 * @param {String/Number} key The key or index of the item.
14473 * @return {Object} The item associated with the passed key.
14475 item : function(key){
14476 if (key === 'length') {
14479 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
14480 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
14484 * Returns the item at the specified index.
14485 * @param {Number} index The index of the item.
14488 itemAt : function(index){
14489 return this.items[index];
14493 * Returns the item associated with the passed key.
14494 * @param {String/Number} key The key of the item.
14495 * @return {Object} The item associated with the passed key.
14497 key : function(key){
14498 return this.map[key];
14502 * Returns true if the collection contains the passed Object as an item.
14503 * @param {Object} o The Object to look for in the collection.
14504 * @return {Boolean} True if the collection contains the Object as an item.
14506 contains : function(o){
14507 return this.indexOf(o) != -1;
14511 * Returns true if the collection contains the passed Object as a key.
14512 * @param {String} key The key to look for in the collection.
14513 * @return {Boolean} True if the collection contains the Object as a key.
14515 containsKey : function(key){
14516 return typeof this.map[key] != "undefined";
14520 * Removes all items from the collection.
14522 clear : function(){
14527 this.fireEvent("clear");
14531 * Returns the first item in the collection.
14532 * @return {Object} the first item in the collection..
14534 first : function(){
14535 return this.items[0];
14539 * Returns the last item in the collection.
14540 * @return {Object} the last item in the collection..
14543 return this.items[this.length-1];
14546 _sort : function(property, dir, fn){
14547 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
14548 fn = fn || function(a, b){
14551 var c = [], k = this.keys, items = this.items;
14552 for(var i = 0, len = items.length; i < len; i++){
14553 c[c.length] = {key: k[i], value: items[i], index: i};
14555 c.sort(function(a, b){
14556 var v = fn(a[property], b[property]) * dsc;
14558 v = (a.index < b.index ? -1 : 1);
14562 for(var i = 0, len = c.length; i < len; i++){
14563 items[i] = c[i].value;
14566 this.fireEvent("sort", this);
14570 * Sorts this collection with the passed comparison function
14571 * @param {String} direction (optional) "ASC" or "DESC"
14572 * @param {Function} fn (optional) comparison function
14574 sort : function(dir, fn){
14575 this._sort("value", dir, fn);
14579 * Sorts this collection by keys
14580 * @param {String} direction (optional) "ASC" or "DESC"
14581 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
14583 keySort : function(dir, fn){
14584 this._sort("key", dir, fn || function(a, b){
14585 return String(a).toUpperCase()-String(b).toUpperCase();
14590 * Returns a range of items in this collection
14591 * @param {Number} startIndex (optional) defaults to 0
14592 * @param {Number} endIndex (optional) default to the last item
14593 * @return {Array} An array of items
14595 getRange : function(start, end){
14596 var items = this.items;
14597 if(items.length < 1){
14600 start = start || 0;
14601 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
14604 for(var i = start; i <= end; i++) {
14605 r[r.length] = items[i];
14608 for(var i = start; i >= end; i--) {
14609 r[r.length] = items[i];
14616 * Filter the <i>objects</i> in this collection by a specific property.
14617 * Returns a new collection that has been filtered.
14618 * @param {String} property A property on your objects
14619 * @param {String/RegExp} value Either string that the property values
14620 * should start with or a RegExp to test against the property
14621 * @return {MixedCollection} The new filtered collection
14623 filter : function(property, value){
14624 if(!value.exec){ // not a regex
14625 value = String(value);
14626 if(value.length == 0){
14627 return this.clone();
14629 value = new RegExp("^" + Roo.escapeRe(value), "i");
14631 return this.filterBy(function(o){
14632 return o && value.test(o[property]);
14637 * Filter by a function. * Returns a new collection that has been filtered.
14638 * The passed function will be called with each
14639 * object in the collection. If the function returns true, the value is included
14640 * otherwise it is filtered.
14641 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
14642 * @param {Object} scope (optional) The scope of the function (defaults to this)
14643 * @return {MixedCollection} The new filtered collection
14645 filterBy : function(fn, scope){
14646 var r = new Roo.util.MixedCollection();
14647 r.getKey = this.getKey;
14648 var k = this.keys, it = this.items;
14649 for(var i = 0, len = it.length; i < len; i++){
14650 if(fn.call(scope||this, it[i], k[i])){
14651 r.add(k[i], it[i]);
14658 * Creates a duplicate of this collection
14659 * @return {MixedCollection}
14661 clone : function(){
14662 var r = new Roo.util.MixedCollection();
14663 var k = this.keys, it = this.items;
14664 for(var i = 0, len = it.length; i < len; i++){
14665 r.add(k[i], it[i]);
14667 r.getKey = this.getKey;
14672 * Returns the item associated with the passed key or index.
14674 * @param {String/Number} key The key or index of the item.
14675 * @return {Object} The item associated with the passed key.
14677 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
14679 * Ext JS Library 1.1.1
14680 * Copyright(c) 2006-2007, Ext JS, LLC.
14682 * Originally Released Under LGPL - original licence link has changed is not relivant.
14685 * <script type="text/javascript">
14688 * @class Roo.util.JSON
14689 * Modified version of Douglas Crockford"s json.js that doesn"t
14690 * mess with the Object prototype
14691 * http://www.json.org/js.html
14694 Roo.util.JSON = new (function(){
14695 var useHasOwn = {}.hasOwnProperty ? true : false;
14697 // crashes Safari in some instances
14698 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
14700 var pad = function(n) {
14701 return n < 10 ? "0" + n : n;
14714 var encodeString = function(s){
14715 if (/["\\\x00-\x1f]/.test(s)) {
14716 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
14721 c = b.charCodeAt();
14723 Math.floor(c / 16).toString(16) +
14724 (c % 16).toString(16);
14727 return '"' + s + '"';
14730 var encodeArray = function(o){
14731 var a = ["["], b, i, l = o.length, v;
14732 for (i = 0; i < l; i += 1) {
14734 switch (typeof v) {
14743 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
14751 var encodeDate = function(o){
14752 return '"' + o.getFullYear() + "-" +
14753 pad(o.getMonth() + 1) + "-" +
14754 pad(o.getDate()) + "T" +
14755 pad(o.getHours()) + ":" +
14756 pad(o.getMinutes()) + ":" +
14757 pad(o.getSeconds()) + '"';
14761 * Encodes an Object, Array or other value
14762 * @param {Mixed} o The variable to encode
14763 * @return {String} The JSON string
14765 this.encode = function(o)
14767 // should this be extended to fully wrap stringify..
14769 if(typeof o == "undefined" || o === null){
14771 }else if(o instanceof Array){
14772 return encodeArray(o);
14773 }else if(o instanceof Date){
14774 return encodeDate(o);
14775 }else if(typeof o == "string"){
14776 return encodeString(o);
14777 }else if(typeof o == "number"){
14778 return isFinite(o) ? String(o) : "null";
14779 }else if(typeof o == "boolean"){
14782 var a = ["{"], b, i, v;
14784 if(!useHasOwn || o.hasOwnProperty(i)) {
14786 switch (typeof v) {
14795 a.push(this.encode(i), ":",
14796 v === null ? "null" : this.encode(v));
14807 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
14808 * @param {String} json The JSON string
14809 * @return {Object} The resulting object
14811 this.decode = function(json){
14813 return /** eval:var:json */ eval("(" + json + ')');
14817 * Shorthand for {@link Roo.util.JSON#encode}
14818 * @member Roo encode
14820 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
14822 * Shorthand for {@link Roo.util.JSON#decode}
14823 * @member Roo decode
14825 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
14828 * Ext JS Library 1.1.1
14829 * Copyright(c) 2006-2007, Ext JS, LLC.
14831 * Originally Released Under LGPL - original licence link has changed is not relivant.
14834 * <script type="text/javascript">
14838 * @class Roo.util.Format
14839 * Reusable data formatting functions
14842 Roo.util.Format = function(){
14843 var trimRe = /^\s+|\s+$/g;
14846 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
14847 * @param {String} value The string to truncate
14848 * @param {Number} length The maximum length to allow before truncating
14849 * @return {String} The converted text
14851 ellipsis : function(value, len){
14852 if(value && value.length > len){
14853 return value.substr(0, len-3)+"...";
14859 * Checks a reference and converts it to empty string if it is undefined
14860 * @param {Mixed} value Reference to check
14861 * @return {Mixed} Empty string if converted, otherwise the original value
14863 undef : function(value){
14864 return typeof value != "undefined" ? value : "";
14868 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
14869 * @param {String} value The string to encode
14870 * @return {String} The encoded text
14872 htmlEncode : function(value){
14873 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
14877 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
14878 * @param {String} value The string to decode
14879 * @return {String} The decoded text
14881 htmlDecode : function(value){
14882 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
14886 * Trims any whitespace from either side of a string
14887 * @param {String} value The text to trim
14888 * @return {String} The trimmed text
14890 trim : function(value){
14891 return String(value).replace(trimRe, "");
14895 * Returns a substring from within an original string
14896 * @param {String} value The original text
14897 * @param {Number} start The start index of the substring
14898 * @param {Number} length The length of the substring
14899 * @return {String} The substring
14901 substr : function(value, start, length){
14902 return String(value).substr(start, length);
14906 * Converts a string to all lower case letters
14907 * @param {String} value The text to convert
14908 * @return {String} The converted text
14910 lowercase : function(value){
14911 return String(value).toLowerCase();
14915 * Converts a string to all upper case letters
14916 * @param {String} value The text to convert
14917 * @return {String} The converted text
14919 uppercase : function(value){
14920 return String(value).toUpperCase();
14924 * Converts the first character only of a string to upper case
14925 * @param {String} value The text to convert
14926 * @return {String} The converted text
14928 capitalize : function(value){
14929 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
14933 call : function(value, fn){
14934 if(arguments.length > 2){
14935 var args = Array.prototype.slice.call(arguments, 2);
14936 args.unshift(value);
14938 return /** eval:var:value */ eval(fn).apply(window, args);
14940 /** eval:var:value */
14941 return /** eval:var:value */ eval(fn).call(window, value);
14947 * safer version of Math.toFixed..??/
14948 * @param {Number/String} value The numeric value to format
14949 * @param {Number/String} value Decimal places
14950 * @return {String} The formatted currency string
14952 toFixed : function(v, n)
14954 // why not use to fixed - precision is buggered???
14956 return Math.round(v-0);
14958 var fact = Math.pow(10,n+1);
14959 v = (Math.round((v-0)*fact))/fact;
14960 var z = (''+fact).substring(2);
14961 if (v == Math.floor(v)) {
14962 return Math.floor(v) + '.' + z;
14965 // now just padd decimals..
14966 var ps = String(v).split('.');
14967 var fd = (ps[1] + z);
14968 var r = fd.substring(0,n);
14969 var rm = fd.substring(n);
14971 return ps[0] + '.' + r;
14973 r*=1; // turn it into a number;
14975 if (String(r).length != n) {
14978 r = String(r).substring(1); // chop the end off.
14981 return ps[0] + '.' + r;
14986 * Format a number as US currency
14987 * @param {Number/String} value The numeric value to format
14988 * @return {String} The formatted currency string
14990 usMoney : function(v){
14991 return '$' + Roo.util.Format.number(v);
14996 * eventually this should probably emulate php's number_format
14997 * @param {Number/String} value The numeric value to format
14998 * @param {Number} decimals number of decimal places
14999 * @param {String} delimiter for thousands (default comma)
15000 * @return {String} The formatted currency string
15002 number : function(v, decimals, thousandsDelimiter)
15004 // multiply and round.
15005 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
15006 thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
15008 var mul = Math.pow(10, decimals);
15009 var zero = String(mul).substring(1);
15010 v = (Math.round((v-0)*mul))/mul;
15012 // if it's '0' number.. then
15014 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
15016 var ps = v.split('.');
15019 var r = /(\d+)(\d{3})/;
15022 if(thousandsDelimiter.length != 0) {
15023 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
15028 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
15029 // does not have decimals
15030 (decimals ? ('.' + zero) : '');
15033 return whole + sub ;
15037 * Parse a value into a formatted date using the specified format pattern.
15038 * @param {Mixed} value The value to format
15039 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
15040 * @return {String} The formatted date string
15042 date : function(v, format){
15046 if(!(v instanceof Date)){
15047 v = new Date(Date.parse(v));
15049 return v.dateFormat(format || Roo.util.Format.defaults.date);
15053 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
15054 * @param {String} format Any valid date format string
15055 * @return {Function} The date formatting function
15057 dateRenderer : function(format){
15058 return function(v){
15059 return Roo.util.Format.date(v, format);
15064 stripTagsRE : /<\/?[^>]+>/gi,
15067 * Strips all HTML tags
15068 * @param {Mixed} value The text from which to strip tags
15069 * @return {String} The stripped text
15071 stripTags : function(v){
15072 return !v ? v : String(v).replace(this.stripTagsRE, "");
15076 * Size in Mb,Gb etc.
15077 * @param {Number} value The number to be formated
15078 * @param {number} decimals how many decimal places
15079 * @return {String} the formated string
15081 size : function(value, decimals)
15083 var sizes = ['b', 'k', 'M', 'G', 'T'];
15087 var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
15088 return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals) + sizes[i];
15095 Roo.util.Format.defaults = {
15099 * Ext JS Library 1.1.1
15100 * Copyright(c) 2006-2007, Ext JS, LLC.
15102 * Originally Released Under LGPL - original licence link has changed is not relivant.
15105 * <script type="text/javascript">
15112 * @class Roo.MasterTemplate
15113 * @extends Roo.Template
15114 * Provides a template that can have child templates. The syntax is:
15116 var t = new Roo.MasterTemplate(
15117 '<select name="{name}">',
15118 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
15121 t.add('options', {value: 'foo', text: 'bar'});
15122 // or you can add multiple child elements in one shot
15123 t.addAll('options', [
15124 {value: 'foo', text: 'bar'},
15125 {value: 'foo2', text: 'bar2'},
15126 {value: 'foo3', text: 'bar3'}
15128 // then append, applying the master template values
15129 t.append('my-form', {name: 'my-select'});
15131 * A name attribute for the child template is not required if you have only one child
15132 * template or you want to refer to them by index.
15134 Roo.MasterTemplate = function(){
15135 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
15136 this.originalHtml = this.html;
15138 var m, re = this.subTemplateRe;
15141 while(m = re.exec(this.html)){
15142 var name = m[1], content = m[2];
15147 tpl : new Roo.Template(content)
15150 st[name] = st[subIndex];
15152 st[subIndex].tpl.compile();
15153 st[subIndex].tpl.call = this.call.createDelegate(this);
15156 this.subCount = subIndex;
15159 Roo.extend(Roo.MasterTemplate, Roo.Template, {
15161 * The regular expression used to match sub templates
15165 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
15168 * Applies the passed values to a child template.
15169 * @param {String/Number} name (optional) The name or index of the child template
15170 * @param {Array/Object} values The values to be applied to the template
15171 * @return {MasterTemplate} this
15173 add : function(name, values){
15174 if(arguments.length == 1){
15175 values = arguments[0];
15178 var s = this.subs[name];
15179 s.buffer[s.buffer.length] = s.tpl.apply(values);
15184 * Applies all the passed values to a child template.
15185 * @param {String/Number} name (optional) The name or index of the child template
15186 * @param {Array} values The values to be applied to the template, this should be an array of objects.
15187 * @param {Boolean} reset (optional) True to reset the template first
15188 * @return {MasterTemplate} this
15190 fill : function(name, values, reset){
15192 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
15200 for(var i = 0, len = values.length; i < len; i++){
15201 this.add(name, values[i]);
15207 * Resets the template for reuse
15208 * @return {MasterTemplate} this
15210 reset : function(){
15212 for(var i = 0; i < this.subCount; i++){
15218 applyTemplate : function(values){
15220 var replaceIndex = -1;
15221 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
15222 return s[++replaceIndex].buffer.join("");
15224 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
15227 apply : function(){
15228 return this.applyTemplate.apply(this, arguments);
15231 compile : function(){return this;}
15235 * Alias for fill().
15238 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
15240 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
15241 * var tpl = Roo.MasterTemplate.from('element-id');
15242 * @param {String/HTMLElement} el
15243 * @param {Object} config
15246 Roo.MasterTemplate.from = function(el, config){
15247 el = Roo.getDom(el);
15248 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
15251 * Ext JS Library 1.1.1
15252 * Copyright(c) 2006-2007, Ext JS, LLC.
15254 * Originally Released Under LGPL - original licence link has changed is not relivant.
15257 * <script type="text/javascript">
15262 * @class Roo.util.CSS
15263 * Utility class for manipulating CSS rules
15267 Roo.util.CSS = function(){
15269 var doc = document;
15271 var camelRe = /(-[a-z])/gi;
15272 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
15276 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
15277 * tag and appended to the HEAD of the document.
15278 * @param {String|Object} cssText The text containing the css rules
15279 * @param {String} id An id to add to the stylesheet for later removal
15280 * @return {StyleSheet}
15282 createStyleSheet : function(cssText, id){
15284 var head = doc.getElementsByTagName("head")[0];
15285 var nrules = doc.createElement("style");
15286 nrules.setAttribute("type", "text/css");
15288 nrules.setAttribute("id", id);
15290 if (typeof(cssText) != 'string') {
15291 // support object maps..
15292 // not sure if this a good idea..
15293 // perhaps it should be merged with the general css handling
15294 // and handle js style props.
15295 var cssTextNew = [];
15296 for(var n in cssText) {
15298 for(var k in cssText[n]) {
15299 citems.push( k + ' : ' +cssText[n][k] + ';' );
15301 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
15304 cssText = cssTextNew.join("\n");
15310 head.appendChild(nrules);
15311 ss = nrules.styleSheet;
15312 ss.cssText = cssText;
15315 nrules.appendChild(doc.createTextNode(cssText));
15317 nrules.cssText = cssText;
15319 head.appendChild(nrules);
15320 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
15322 this.cacheStyleSheet(ss);
15327 * Removes a style or link tag by id
15328 * @param {String} id The id of the tag
15330 removeStyleSheet : function(id){
15331 var existing = doc.getElementById(id);
15333 existing.parentNode.removeChild(existing);
15338 * Dynamically swaps an existing stylesheet reference for a new one
15339 * @param {String} id The id of an existing link tag to remove
15340 * @param {String} url The href of the new stylesheet to include
15342 swapStyleSheet : function(id, url){
15343 this.removeStyleSheet(id);
15344 var ss = doc.createElement("link");
15345 ss.setAttribute("rel", "stylesheet");
15346 ss.setAttribute("type", "text/css");
15347 ss.setAttribute("id", id);
15348 ss.setAttribute("href", url);
15349 doc.getElementsByTagName("head")[0].appendChild(ss);
15353 * Refresh the rule cache if you have dynamically added stylesheets
15354 * @return {Object} An object (hash) of rules indexed by selector
15356 refreshCache : function(){
15357 return this.getRules(true);
15361 cacheStyleSheet : function(stylesheet){
15365 try{// try catch for cross domain access issue
15366 var ssRules = stylesheet.cssRules || stylesheet.rules;
15367 for(var j = ssRules.length-1; j >= 0; --j){
15368 rules[ssRules[j].selectorText] = ssRules[j];
15374 * Gets all css rules for the document
15375 * @param {Boolean} refreshCache true to refresh the internal cache
15376 * @return {Object} An object (hash) of rules indexed by selector
15378 getRules : function(refreshCache){
15379 if(rules == null || refreshCache){
15381 var ds = doc.styleSheets;
15382 for(var i =0, len = ds.length; i < len; i++){
15384 this.cacheStyleSheet(ds[i]);
15392 * Gets an an individual CSS rule by selector(s)
15393 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
15394 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
15395 * @return {CSSRule} The CSS rule or null if one is not found
15397 getRule : function(selector, refreshCache){
15398 var rs = this.getRules(refreshCache);
15399 if(!(selector instanceof Array)){
15400 return rs[selector];
15402 for(var i = 0; i < selector.length; i++){
15403 if(rs[selector[i]]){
15404 return rs[selector[i]];
15412 * Updates a rule property
15413 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
15414 * @param {String} property The css property
15415 * @param {String} value The new value for the property
15416 * @return {Boolean} true If a rule was found and updated
15418 updateRule : function(selector, property, value){
15419 if(!(selector instanceof Array)){
15420 var rule = this.getRule(selector);
15422 rule.style[property.replace(camelRe, camelFn)] = value;
15426 for(var i = 0; i < selector.length; i++){
15427 if(this.updateRule(selector[i], property, value)){
15437 * Ext JS Library 1.1.1
15438 * Copyright(c) 2006-2007, Ext JS, LLC.
15440 * Originally Released Under LGPL - original licence link has changed is not relivant.
15443 * <script type="text/javascript">
15449 * @class Roo.util.ClickRepeater
15450 * @extends Roo.util.Observable
15452 * A wrapper class which can be applied to any element. Fires a "click" event while the
15453 * mouse is pressed. The interval between firings may be specified in the config but
15454 * defaults to 10 milliseconds.
15456 * Optionally, a CSS class may be applied to the element during the time it is pressed.
15458 * @cfg {String/HTMLElement/Element} el The element to act as a button.
15459 * @cfg {Number} delay The initial delay before the repeating event begins firing.
15460 * Similar to an autorepeat key delay.
15461 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
15462 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
15463 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
15464 * "interval" and "delay" are ignored. "immediate" is honored.
15465 * @cfg {Boolean} preventDefault True to prevent the default click event
15466 * @cfg {Boolean} stopDefault True to stop the default click event
15469 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
15470 * 2007-02-02 jvs Renamed to ClickRepeater
15471 * 2007-02-03 jvs Modifications for FF Mac and Safari
15474 * @param {String/HTMLElement/Element} el The element to listen on
15475 * @param {Object} config
15477 Roo.util.ClickRepeater = function(el, config)
15479 this.el = Roo.get(el);
15480 this.el.unselectable();
15482 Roo.apply(this, config);
15487 * Fires when the mouse button is depressed.
15488 * @param {Roo.util.ClickRepeater} this
15490 "mousedown" : true,
15493 * Fires on a specified interval during the time the element is pressed.
15494 * @param {Roo.util.ClickRepeater} this
15499 * Fires when the mouse key is released.
15500 * @param {Roo.util.ClickRepeater} this
15505 this.el.on("mousedown", this.handleMouseDown, this);
15506 if(this.preventDefault || this.stopDefault){
15507 this.el.on("click", function(e){
15508 if(this.preventDefault){
15509 e.preventDefault();
15511 if(this.stopDefault){
15517 // allow inline handler
15519 this.on("click", this.handler, this.scope || this);
15522 Roo.util.ClickRepeater.superclass.constructor.call(this);
15525 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
15528 preventDefault : true,
15529 stopDefault : false,
15533 handleMouseDown : function(){
15534 clearTimeout(this.timer);
15536 if(this.pressClass){
15537 this.el.addClass(this.pressClass);
15539 this.mousedownTime = new Date();
15541 Roo.get(document).on("mouseup", this.handleMouseUp, this);
15542 this.el.on("mouseout", this.handleMouseOut, this);
15544 this.fireEvent("mousedown", this);
15545 this.fireEvent("click", this);
15547 this.timer = this.click.defer(this.delay || this.interval, this);
15551 click : function(){
15552 this.fireEvent("click", this);
15553 this.timer = this.click.defer(this.getInterval(), this);
15557 getInterval: function(){
15558 if(!this.accelerate){
15559 return this.interval;
15561 var pressTime = this.mousedownTime.getElapsed();
15562 if(pressTime < 500){
15564 }else if(pressTime < 1700){
15566 }else if(pressTime < 2600){
15568 }else if(pressTime < 3500){
15570 }else if(pressTime < 4400){
15572 }else if(pressTime < 5300){
15574 }else if(pressTime < 6200){
15582 handleMouseOut : function(){
15583 clearTimeout(this.timer);
15584 if(this.pressClass){
15585 this.el.removeClass(this.pressClass);
15587 this.el.on("mouseover", this.handleMouseReturn, this);
15591 handleMouseReturn : function(){
15592 this.el.un("mouseover", this.handleMouseReturn);
15593 if(this.pressClass){
15594 this.el.addClass(this.pressClass);
15600 handleMouseUp : function(){
15601 clearTimeout(this.timer);
15602 this.el.un("mouseover", this.handleMouseReturn);
15603 this.el.un("mouseout", this.handleMouseOut);
15604 Roo.get(document).un("mouseup", this.handleMouseUp);
15605 this.el.removeClass(this.pressClass);
15606 this.fireEvent("mouseup", this);
15609 * @class Roo.util.Clipboard
15615 Roo.util.Clipboard = {
15617 * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
15618 * @param {String} text to copy to clipboard
15620 write : function(text) {
15621 // navigator clipboard api needs a secure context (https)
15622 if (navigator.clipboard && window.isSecureContext) {
15623 // navigator clipboard api method'
15624 navigator.clipboard.writeText(text);
15627 // text area method
15628 var ta = document.createElement("textarea");
15630 // make the textarea out of viewport
15631 ta.style.position = "fixed";
15632 ta.style.left = "-999999px";
15633 ta.style.top = "-999999px";
15634 document.body.appendChild(ta);
15637 document.execCommand('copy');
15647 * Ext JS Library 1.1.1
15648 * Copyright(c) 2006-2007, Ext JS, LLC.
15650 * Originally Released Under LGPL - original licence link has changed is not relivant.
15653 * <script type="text/javascript">
15658 * @class Roo.KeyNav
15659 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
15660 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
15661 * way to implement custom navigation schemes for any UI component.</p>
15662 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
15663 * pageUp, pageDown, del, home, end. Usage:</p>
15665 var nav = new Roo.KeyNav("my-element", {
15666 "left" : function(e){
15667 this.moveLeft(e.ctrlKey);
15669 "right" : function(e){
15670 this.moveRight(e.ctrlKey);
15672 "enter" : function(e){
15679 * @param {String/HTMLElement/Roo.Element} el The element to bind to
15680 * @param {Object} config The config
15682 Roo.KeyNav = function(el, config){
15683 this.el = Roo.get(el);
15684 Roo.apply(this, config);
15685 if(!this.disabled){
15686 this.disabled = true;
15691 Roo.KeyNav.prototype = {
15693 * @cfg {Boolean} disabled
15694 * True to disable this KeyNav instance (defaults to false)
15698 * @cfg {String} defaultEventAction
15699 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
15700 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
15701 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
15703 defaultEventAction: "stopEvent",
15705 * @cfg {Boolean} forceKeyDown
15706 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
15707 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
15708 * handle keydown instead of keypress.
15710 forceKeyDown : false,
15713 prepareEvent : function(e){
15714 var k = e.getKey();
15715 var h = this.keyToHandler[k];
15716 //if(h && this[h]){
15717 // e.stopPropagation();
15719 if(Roo.isSafari && h && k >= 37 && k <= 40){
15725 relay : function(e){
15726 var k = e.getKey();
15727 var h = this.keyToHandler[k];
15729 if(this.doRelay(e, this[h], h) !== true){
15730 e[this.defaultEventAction]();
15736 doRelay : function(e, h, hname){
15737 return h.call(this.scope || this, e);
15740 // possible handlers
15754 // quick lookup hash
15771 * Enable this KeyNav
15773 enable: function(){
15775 // ie won't do special keys on keypress, no one else will repeat keys with keydown
15776 // the EventObject will normalize Safari automatically
15777 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15778 this.el.on("keydown", this.relay, this);
15780 this.el.on("keydown", this.prepareEvent, this);
15781 this.el.on("keypress", this.relay, this);
15783 this.disabled = false;
15788 * Disable this KeyNav
15790 disable: function(){
15791 if(!this.disabled){
15792 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15793 this.el.un("keydown", this.relay);
15795 this.el.un("keydown", this.prepareEvent);
15796 this.el.un("keypress", this.relay);
15798 this.disabled = true;
15803 * Ext JS Library 1.1.1
15804 * Copyright(c) 2006-2007, Ext JS, LLC.
15806 * Originally Released Under LGPL - original licence link has changed is not relivant.
15809 * <script type="text/javascript">
15814 * @class Roo.KeyMap
15815 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
15816 * The constructor accepts the same config object as defined by {@link #addBinding}.
15817 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
15818 * combination it will call the function with this signature (if the match is a multi-key
15819 * combination the callback will still be called only once): (String key, Roo.EventObject e)
15820 * A KeyMap can also handle a string representation of keys.<br />
15823 // map one key by key code
15824 var map = new Roo.KeyMap("my-element", {
15825 key: 13, // or Roo.EventObject.ENTER
15830 // map multiple keys to one action by string
15831 var map = new Roo.KeyMap("my-element", {
15837 // map multiple keys to multiple actions by strings and array of codes
15838 var map = new Roo.KeyMap("my-element", [
15841 fn: function(){ alert("Return was pressed"); }
15844 fn: function(){ alert('a, b or c was pressed'); }
15849 fn: function(){ alert('Control + shift + tab was pressed.'); }
15853 * <b>Note: A KeyMap starts enabled</b>
15855 * @param {String/HTMLElement/Roo.Element} el The element to bind to
15856 * @param {Object} config The config (see {@link #addBinding})
15857 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
15859 Roo.KeyMap = function(el, config, eventName){
15860 this.el = Roo.get(el);
15861 this.eventName = eventName || "keydown";
15862 this.bindings = [];
15864 this.addBinding(config);
15869 Roo.KeyMap.prototype = {
15871 * True to stop the event from bubbling and prevent the default browser action if the
15872 * key was handled by the KeyMap (defaults to false)
15878 * Add a new binding to this KeyMap. The following config object properties are supported:
15880 Property Type Description
15881 ---------- --------------- ----------------------------------------------------------------------
15882 key String/Array A single keycode or an array of keycodes to handle
15883 shift Boolean True to handle key only when shift is pressed (defaults to false)
15884 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
15885 alt Boolean True to handle key only when alt is pressed (defaults to false)
15886 fn Function The function to call when KeyMap finds the expected key combination
15887 scope Object The scope of the callback function
15893 var map = new Roo.KeyMap(document, {
15894 key: Roo.EventObject.ENTER,
15899 //Add a new binding to the existing KeyMap later
15907 * @param {Object/Array} config A single KeyMap config or an array of configs
15909 addBinding : function(config){
15910 if(config instanceof Array){
15911 for(var i = 0, len = config.length; i < len; i++){
15912 this.addBinding(config[i]);
15916 var keyCode = config.key,
15917 shift = config.shift,
15918 ctrl = config.ctrl,
15921 scope = config.scope;
15922 if(typeof keyCode == "string"){
15924 var keyString = keyCode.toUpperCase();
15925 for(var j = 0, len = keyString.length; j < len; j++){
15926 ks.push(keyString.charCodeAt(j));
15930 var keyArray = keyCode instanceof Array;
15931 var handler = function(e){
15932 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
15933 var k = e.getKey();
15935 for(var i = 0, len = keyCode.length; i < len; i++){
15936 if(keyCode[i] == k){
15937 if(this.stopEvent){
15940 fn.call(scope || window, k, e);
15946 if(this.stopEvent){
15949 fn.call(scope || window, k, e);
15954 this.bindings.push(handler);
15958 * Shorthand for adding a single key listener
15959 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
15960 * following options:
15961 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
15962 * @param {Function} fn The function to call
15963 * @param {Object} scope (optional) The scope of the function
15965 on : function(key, fn, scope){
15966 var keyCode, shift, ctrl, alt;
15967 if(typeof key == "object" && !(key instanceof Array)){
15986 handleKeyDown : function(e){
15987 if(this.enabled){ //just in case
15988 var b = this.bindings;
15989 for(var i = 0, len = b.length; i < len; i++){
15990 b[i].call(this, e);
15996 * Returns true if this KeyMap is enabled
15997 * @return {Boolean}
15999 isEnabled : function(){
16000 return this.enabled;
16004 * Enables this KeyMap
16006 enable: function(){
16008 this.el.on(this.eventName, this.handleKeyDown, this);
16009 this.enabled = true;
16014 * Disable this KeyMap
16016 disable: function(){
16018 this.el.removeListener(this.eventName, this.handleKeyDown, this);
16019 this.enabled = false;
16024 * Ext JS Library 1.1.1
16025 * Copyright(c) 2006-2007, Ext JS, LLC.
16027 * Originally Released Under LGPL - original licence link has changed is not relivant.
16030 * <script type="text/javascript">
16035 * @class Roo.util.TextMetrics
16036 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
16037 * wide, in pixels, a given block of text will be.
16040 Roo.util.TextMetrics = function(){
16044 * Measures the size of the specified text
16045 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
16046 * that can affect the size of the rendered text
16047 * @param {String} text The text to measure
16048 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
16049 * in order to accurately measure the text height
16050 * @return {Object} An object containing the text's size {width: (width), height: (height)}
16052 measure : function(el, text, fixedWidth){
16054 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
16057 shared.setFixedWidth(fixedWidth || 'auto');
16058 return shared.getSize(text);
16062 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
16063 * the overhead of multiple calls to initialize the style properties on each measurement.
16064 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
16065 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
16066 * in order to accurately measure the text height
16067 * @return {Roo.util.TextMetrics.Instance} instance The new instance
16069 createInstance : function(el, fixedWidth){
16070 return Roo.util.TextMetrics.Instance(el, fixedWidth);
16076 * @class Roo.util.TextMetrics.Instance
16077 * Instance of TextMetrics Calcuation
16079 * Create a new TextMetrics Instance
16080 * @param {Object} bindto
16081 * @param {Boolean} fixedWidth
16084 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth)
16086 var ml = new Roo.Element(document.createElement('div'));
16087 document.body.appendChild(ml.dom);
16088 ml.position('absolute');
16089 ml.setLeftTop(-1000, -1000);
16093 ml.setWidth(fixedWidth);
16098 * Returns the size of the specified text based on the internal element's style and width properties
16099 * @param {String} text The text to measure
16100 * @return {Object} An object containing the text's size {width: (width), height: (height)}
16102 getSize : function(text){
16104 var s = ml.getSize();
16110 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
16111 * that can affect the size of the rendered text
16112 * @param {String/HTMLElement} el The element, dom node or id
16114 bind : function(el){
16116 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
16121 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
16122 * to set a fixed width in order to accurately measure the text height.
16123 * @param {Number} width The width to set on the element
16125 setFixedWidth : function(width){
16126 ml.setWidth(width);
16130 * Returns the measured width of the specified text
16131 * @param {String} text The text to measure
16132 * @return {Number} width The width in pixels
16134 getWidth : function(text){
16135 ml.dom.style.width = 'auto';
16136 return this.getSize(text).width;
16140 * Returns the measured height of the specified text. For multiline text, be sure to call
16141 * {@link #setFixedWidth} if necessary.
16142 * @param {String} text The text to measure
16143 * @return {Number} height The height in pixels
16145 getHeight : function(text){
16146 return this.getSize(text).height;
16150 instance.bind(bindTo);
16155 // backwards compat
16156 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
16158 * Ext JS Library 1.1.1
16159 * Copyright(c) 2006-2007, Ext JS, LLC.
16161 * Originally Released Under LGPL - original licence link has changed is not relivant.
16164 * <script type="text/javascript">
16168 * @class Roo.state.Provider
16169 * Abstract base class for state provider implementations. This class provides methods
16170 * for encoding and decoding <b>typed</b> variables including dates and defines the
16171 * Provider interface.
16173 Roo.state.Provider = function(){
16175 * @event statechange
16176 * Fires when a state change occurs.
16177 * @param {Provider} this This state provider
16178 * @param {String} key The state key which was changed
16179 * @param {String} value The encoded value for the state
16182 "statechange": true
16185 Roo.state.Provider.superclass.constructor.call(this);
16187 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
16189 * Returns the current value for a key
16190 * @param {String} name The key name
16191 * @param {Mixed} defaultValue A default value to return if the key's value is not found
16192 * @return {Mixed} The state data
16194 get : function(name, defaultValue){
16195 return typeof this.state[name] == "undefined" ?
16196 defaultValue : this.state[name];
16200 * Clears a value from the state
16201 * @param {String} name The key name
16203 clear : function(name){
16204 delete this.state[name];
16205 this.fireEvent("statechange", this, name, null);
16209 * Sets the value for a key
16210 * @param {String} name The key name
16211 * @param {Mixed} value The value to set
16213 set : function(name, value){
16214 this.state[name] = value;
16215 this.fireEvent("statechange", this, name, value);
16219 * Decodes a string previously encoded with {@link #encodeValue}.
16220 * @param {String} value The value to decode
16221 * @return {Mixed} The decoded value
16223 decodeValue : function(cookie){
16224 var re = /^(a|n|d|b|s|o)\:(.*)$/;
16225 var matches = re.exec(unescape(cookie));
16226 if(!matches || !matches[1]) {
16227 return; // non state cookie
16229 var type = matches[1];
16230 var v = matches[2];
16233 return parseFloat(v);
16235 return new Date(Date.parse(v));
16240 var values = v.split("^");
16241 for(var i = 0, len = values.length; i < len; i++){
16242 all.push(this.decodeValue(values[i]));
16247 var values = v.split("^");
16248 for(var i = 0, len = values.length; i < len; i++){
16249 var kv = values[i].split("=");
16250 all[kv[0]] = this.decodeValue(kv[1]);
16259 * Encodes a value including type information. Decode with {@link #decodeValue}.
16260 * @param {Mixed} value The value to encode
16261 * @return {String} The encoded value
16263 encodeValue : function(v){
16265 if(typeof v == "number"){
16267 }else if(typeof v == "boolean"){
16268 enc = "b:" + (v ? "1" : "0");
16269 }else if(v instanceof Date){
16270 enc = "d:" + v.toGMTString();
16271 }else if(v instanceof Array){
16273 for(var i = 0, len = v.length; i < len; i++){
16274 flat += this.encodeValue(v[i]);
16280 }else if(typeof v == "object"){
16283 if(typeof v[key] != "function"){
16284 flat += key + "=" + this.encodeValue(v[key]) + "^";
16287 enc = "o:" + flat.substring(0, flat.length-1);
16291 return escape(enc);
16297 * Ext JS Library 1.1.1
16298 * Copyright(c) 2006-2007, Ext JS, LLC.
16300 * Originally Released Under LGPL - original licence link has changed is not relivant.
16303 * <script type="text/javascript">
16306 * @class Roo.state.Manager
16307 * This is the global state manager. By default all components that are "state aware" check this class
16308 * for state information if you don't pass them a custom state provider. In order for this class
16309 * to be useful, it must be initialized with a provider when your application initializes.
16311 // in your initialization function
16313 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
16315 // supposed you have a {@link Roo.BorderLayout}
16316 var layout = new Roo.BorderLayout(...);
16317 layout.restoreState();
16318 // or a {Roo.BasicDialog}
16319 var dialog = new Roo.BasicDialog(...);
16320 dialog.restoreState();
16324 Roo.state.Manager = function(){
16325 var provider = new Roo.state.Provider();
16329 * Configures the default state provider for your application
16330 * @param {Provider} stateProvider The state provider to set
16332 setProvider : function(stateProvider){
16333 provider = stateProvider;
16337 * Returns the current value for a key
16338 * @param {String} name The key name
16339 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
16340 * @return {Mixed} The state data
16342 get : function(key, defaultValue){
16343 return provider.get(key, defaultValue);
16347 * Sets the value for a key
16348 * @param {String} name The key name
16349 * @param {Mixed} value The state data
16351 set : function(key, value){
16352 provider.set(key, value);
16356 * Clears a value from the state
16357 * @param {String} name The key name
16359 clear : function(key){
16360 provider.clear(key);
16364 * Gets the currently configured state provider
16365 * @return {Provider} The state provider
16367 getProvider : function(){
16374 * Ext JS Library 1.1.1
16375 * Copyright(c) 2006-2007, Ext JS, LLC.
16377 * Originally Released Under LGPL - original licence link has changed is not relivant.
16380 * <script type="text/javascript">
16383 * @class Roo.state.CookieProvider
16384 * @extends Roo.state.Provider
16385 * The default Provider implementation which saves state via cookies.
16388 var cp = new Roo.state.CookieProvider({
16390 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
16391 domain: "roojs.com"
16393 Roo.state.Manager.setProvider(cp);
16395 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
16396 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
16397 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
16398 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
16399 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
16400 * domain the page is running on including the 'www' like 'www.roojs.com')
16401 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
16403 * Create a new CookieProvider
16404 * @param {Object} config The configuration object
16406 Roo.state.CookieProvider = function(config){
16407 Roo.state.CookieProvider.superclass.constructor.call(this);
16409 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
16410 this.domain = null;
16411 this.secure = false;
16412 Roo.apply(this, config);
16413 this.state = this.readCookies();
16416 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
16418 set : function(name, value){
16419 if(typeof value == "undefined" || value === null){
16423 this.setCookie(name, value);
16424 Roo.state.CookieProvider.superclass.set.call(this, name, value);
16428 clear : function(name){
16429 this.clearCookie(name);
16430 Roo.state.CookieProvider.superclass.clear.call(this, name);
16434 readCookies : function(){
16436 var c = document.cookie + ";";
16437 var re = /\s?(.*?)=(.*?);/g;
16439 while((matches = re.exec(c)) != null){
16440 var name = matches[1];
16441 var value = matches[2];
16442 if(name && name.substring(0,3) == "ys-"){
16443 cookies[name.substr(3)] = this.decodeValue(value);
16450 setCookie : function(name, value){
16451 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
16452 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
16453 ((this.path == null) ? "" : ("; path=" + this.path)) +
16454 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16455 ((this.secure == true) ? "; secure" : "");
16459 clearCookie : function(name){
16460 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
16461 ((this.path == null) ? "" : ("; path=" + this.path)) +
16462 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16463 ((this.secure == true) ? "; secure" : "");
16467 * Ext JS Library 1.1.1
16468 * Copyright(c) 2006-2007, Ext JS, LLC.
16470 * Originally Released Under LGPL - original licence link has changed is not relivant.
16473 * <script type="text/javascript">
16478 * @class Roo.ComponentMgr
16479 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
16482 Roo.ComponentMgr = function(){
16483 var all = new Roo.util.MixedCollection();
16487 * Registers a component.
16488 * @param {Roo.Component} c The component
16490 register : function(c){
16495 * Unregisters a component.
16496 * @param {Roo.Component} c The component
16498 unregister : function(c){
16503 * Returns a component by id
16504 * @param {String} id The component id
16506 get : function(id){
16507 return all.get(id);
16511 * Registers a function that will be called when a specified component is added to ComponentMgr
16512 * @param {String} id The component id
16513 * @param {Funtction} fn The callback function
16514 * @param {Object} scope The scope of the callback
16516 onAvailable : function(id, fn, scope){
16517 all.on("add", function(index, o){
16519 fn.call(scope || o, o);
16520 all.un("add", fn, scope);
16527 * Ext JS Library 1.1.1
16528 * Copyright(c) 2006-2007, Ext JS, LLC.
16530 * Originally Released Under LGPL - original licence link has changed is not relivant.
16533 * <script type="text/javascript">
16537 * @class Roo.Component
16538 * @extends Roo.util.Observable
16539 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
16540 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
16541 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
16542 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
16543 * All visual components (widgets) that require rendering into a layout should subclass Component.
16545 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
16546 * 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
16547 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
16549 Roo.Component = function(config){
16550 config = config || {};
16551 if(config.tagName || config.dom || typeof config == "string"){ // element object
16552 config = {el: config, id: config.id || config};
16554 this.initialConfig = config;
16556 Roo.apply(this, config);
16560 * Fires after the component is disabled.
16561 * @param {Roo.Component} this
16566 * Fires after the component is enabled.
16567 * @param {Roo.Component} this
16571 * @event beforeshow
16572 * Fires before the component is shown. Return false to stop the show.
16573 * @param {Roo.Component} this
16578 * Fires after the component is shown.
16579 * @param {Roo.Component} this
16583 * @event beforehide
16584 * Fires before the component is hidden. Return false to stop the hide.
16585 * @param {Roo.Component} this
16590 * Fires after the component is hidden.
16591 * @param {Roo.Component} this
16595 * @event beforerender
16596 * Fires before the component is rendered. Return false to stop the render.
16597 * @param {Roo.Component} this
16599 beforerender : true,
16602 * Fires after the component is rendered.
16603 * @param {Roo.Component} this
16607 * @event beforedestroy
16608 * Fires before the component is destroyed. Return false to stop the destroy.
16609 * @param {Roo.Component} this
16611 beforedestroy : true,
16614 * Fires after the component is destroyed.
16615 * @param {Roo.Component} this
16620 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
16622 Roo.ComponentMgr.register(this);
16623 Roo.Component.superclass.constructor.call(this);
16624 this.initComponent();
16625 if(this.renderTo){ // not supported by all components yet. use at your own risk!
16626 this.render(this.renderTo);
16627 delete this.renderTo;
16632 Roo.Component.AUTO_ID = 1000;
16634 Roo.extend(Roo.Component, Roo.util.Observable, {
16636 * @scope Roo.Component.prototype
16638 * true if this component is hidden. Read-only.
16643 * true if this component is disabled. Read-only.
16648 * true if this component has been rendered. Read-only.
16652 /** @cfg {String} disableClass
16653 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
16655 disabledClass : "x-item-disabled",
16656 /** @cfg {Boolean} allowDomMove
16657 * Whether the component can move the Dom node when rendering (defaults to true).
16659 allowDomMove : true,
16660 /** @cfg {String} hideMode (display|visibility)
16661 * How this component should hidden. Supported values are
16662 * "visibility" (css visibility), "offsets" (negative offset position) and
16663 * "display" (css display) - defaults to "display".
16665 hideMode: 'display',
16668 ctype : "Roo.Component",
16671 * @cfg {String} actionMode
16672 * which property holds the element that used for hide() / show() / disable() / enable()
16673 * default is 'el' for forms you probably want to set this to fieldEl
16678 getActionEl : function(){
16679 return this[this.actionMode];
16682 initComponent : Roo.emptyFn,
16684 * If this is a lazy rendering component, render it to its container element.
16685 * @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.
16687 render : function(container, position){
16693 if(this.fireEvent("beforerender", this) === false){
16697 if(!container && this.el){
16698 this.el = Roo.get(this.el);
16699 container = this.el.dom.parentNode;
16700 this.allowDomMove = false;
16702 this.container = Roo.get(container);
16703 this.rendered = true;
16704 if(position !== undefined){
16705 if(typeof position == 'number'){
16706 position = this.container.dom.childNodes[position];
16708 position = Roo.getDom(position);
16711 this.onRender(this.container, position || null);
16713 this.el.addClass(this.cls);
16717 this.el.applyStyles(this.style);
16720 this.fireEvent("render", this);
16721 this.afterRender(this.container);
16734 // default function is not really useful
16735 onRender : function(ct, position){
16737 this.el = Roo.get(this.el);
16738 if(this.allowDomMove !== false){
16739 ct.dom.insertBefore(this.el.dom, position);
16745 getAutoCreate : function(){
16746 var cfg = typeof this.autoCreate == "object" ?
16747 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
16748 if(this.id && !cfg.id){
16755 afterRender : Roo.emptyFn,
16758 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
16759 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
16761 destroy : function(){
16762 if(this.fireEvent("beforedestroy", this) !== false){
16763 this.purgeListeners();
16764 this.beforeDestroy();
16766 this.el.removeAllListeners();
16768 if(this.actionMode == "container"){
16769 this.container.remove();
16773 Roo.ComponentMgr.unregister(this);
16774 this.fireEvent("destroy", this);
16779 beforeDestroy : function(){
16784 onDestroy : function(){
16789 * Returns the underlying {@link Roo.Element}.
16790 * @return {Roo.Element} The element
16792 getEl : function(){
16797 * Returns the id of this component.
16800 getId : function(){
16805 * Try to focus this component.
16806 * @param {Boolean} selectText True to also select the text in this component (if applicable)
16807 * @return {Roo.Component} this
16809 focus : function(selectText){
16812 if(selectText === true){
16813 this.el.dom.select();
16828 * Disable this component.
16829 * @return {Roo.Component} this
16831 disable : function(){
16835 this.disabled = true;
16836 this.fireEvent("disable", this);
16841 onDisable : function(){
16842 this.getActionEl().addClass(this.disabledClass);
16843 this.el.dom.disabled = true;
16847 * Enable this component.
16848 * @return {Roo.Component} this
16850 enable : function(){
16854 this.disabled = false;
16855 this.fireEvent("enable", this);
16860 onEnable : function(){
16861 this.getActionEl().removeClass(this.disabledClass);
16862 this.el.dom.disabled = false;
16866 * Convenience function for setting disabled/enabled by boolean.
16867 * @param {Boolean} disabled
16869 setDisabled : function(disabled){
16870 this[disabled ? "disable" : "enable"]();
16874 * Show this component.
16875 * @return {Roo.Component} this
16878 if(this.fireEvent("beforeshow", this) !== false){
16879 this.hidden = false;
16883 this.fireEvent("show", this);
16889 onShow : function(){
16890 var ae = this.getActionEl();
16891 if(this.hideMode == 'visibility'){
16892 ae.dom.style.visibility = "visible";
16893 }else if(this.hideMode == 'offsets'){
16894 ae.removeClass('x-hidden');
16896 ae.dom.style.display = "";
16901 * Hide this component.
16902 * @return {Roo.Component} this
16905 if(this.fireEvent("beforehide", this) !== false){
16906 this.hidden = true;
16910 this.fireEvent("hide", this);
16916 onHide : function(){
16917 var ae = this.getActionEl();
16918 if(this.hideMode == 'visibility'){
16919 ae.dom.style.visibility = "hidden";
16920 }else if(this.hideMode == 'offsets'){
16921 ae.addClass('x-hidden');
16923 ae.dom.style.display = "none";
16928 * Convenience function to hide or show this component by boolean.
16929 * @param {Boolean} visible True to show, false to hide
16930 * @return {Roo.Component} this
16932 setVisible: function(visible){
16942 * Returns true if this component is visible.
16944 isVisible : function(){
16945 return this.getActionEl().isVisible();
16948 cloneConfig : function(overrides){
16949 overrides = overrides || {};
16950 var id = overrides.id || Roo.id();
16951 var cfg = Roo.applyIf(overrides, this.initialConfig);
16952 cfg.id = id; // prevent dup id
16953 return new this.constructor(cfg);
16957 * Ext JS Library 1.1.1
16958 * Copyright(c) 2006-2007, Ext JS, LLC.
16960 * Originally Released Under LGPL - original licence link has changed is not relivant.
16963 * <script type="text/javascript">
16967 * @class Roo.BoxComponent
16968 * @extends Roo.Component
16969 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
16970 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
16971 * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
16972 * layout containers.
16974 * @param {Roo.Element/String/Object} config The configuration options.
16976 Roo.BoxComponent = function(config){
16977 Roo.Component.call(this, config);
16981 * Fires after the component is resized.
16982 * @param {Roo.Component} this
16983 * @param {Number} adjWidth The box-adjusted width that was set
16984 * @param {Number} adjHeight The box-adjusted height that was set
16985 * @param {Number} rawWidth The width that was originally specified
16986 * @param {Number} rawHeight The height that was originally specified
16991 * Fires after the component is moved.
16992 * @param {Roo.Component} this
16993 * @param {Number} x The new x position
16994 * @param {Number} y The new y position
17000 Roo.extend(Roo.BoxComponent, Roo.Component, {
17001 // private, set in afterRender to signify that the component has been rendered
17003 // private, used to defer height settings to subclasses
17004 deferHeight: false,
17005 /** @cfg {Number} width
17006 * width (optional) size of component
17008 /** @cfg {Number} height
17009 * height (optional) size of component
17013 * Sets the width and height of the component. This method fires the resize event. This method can accept
17014 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
17015 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
17016 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
17017 * @return {Roo.BoxComponent} this
17019 setSize : function(w, h){
17020 // support for standard size objects
17021 if(typeof w == 'object'){
17026 if(!this.boxReady){
17032 // prevent recalcs when not needed
17033 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
17036 this.lastSize = {width: w, height: h};
17038 var adj = this.adjustSize(w, h);
17039 var aw = adj.width, ah = adj.height;
17040 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
17041 var rz = this.getResizeEl();
17042 if(!this.deferHeight && aw !== undefined && ah !== undefined){
17043 rz.setSize(aw, ah);
17044 }else if(!this.deferHeight && ah !== undefined){
17046 }else if(aw !== undefined){
17049 this.onResize(aw, ah, w, h);
17050 this.fireEvent('resize', this, aw, ah, w, h);
17056 * Gets the current size of the component's underlying element.
17057 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
17059 getSize : function(){
17060 return this.el.getSize();
17064 * Gets the current XY position of the component's underlying element.
17065 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
17066 * @return {Array} The XY position of the element (e.g., [100, 200])
17068 getPosition : function(local){
17069 if(local === true){
17070 return [this.el.getLeft(true), this.el.getTop(true)];
17072 return this.xy || this.el.getXY();
17076 * Gets the current box measurements of the component's underlying element.
17077 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
17078 * @returns {Object} box An object in the format {x, y, width, height}
17080 getBox : function(local){
17081 var s = this.el.getSize();
17083 s.x = this.el.getLeft(true);
17084 s.y = this.el.getTop(true);
17086 var xy = this.xy || this.el.getXY();
17094 * Sets the current box measurements of the component's underlying element.
17095 * @param {Object} box An object in the format {x, y, width, height}
17096 * @returns {Roo.BoxComponent} this
17098 updateBox : function(box){
17099 this.setSize(box.width, box.height);
17100 this.setPagePosition(box.x, box.y);
17105 getResizeEl : function(){
17106 return this.resizeEl || this.el;
17110 getPositionEl : function(){
17111 return this.positionEl || this.el;
17115 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
17116 * This method fires the move event.
17117 * @param {Number} left The new left
17118 * @param {Number} top The new top
17119 * @returns {Roo.BoxComponent} this
17121 setPosition : function(x, y){
17124 if(!this.boxReady){
17127 var adj = this.adjustPosition(x, y);
17128 var ax = adj.x, ay = adj.y;
17130 var el = this.getPositionEl();
17131 if(ax !== undefined || ay !== undefined){
17132 if(ax !== undefined && ay !== undefined){
17133 el.setLeftTop(ax, ay);
17134 }else if(ax !== undefined){
17136 }else if(ay !== undefined){
17139 this.onPosition(ax, ay);
17140 this.fireEvent('move', this, ax, ay);
17146 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
17147 * This method fires the move event.
17148 * @param {Number} x The new x position
17149 * @param {Number} y The new y position
17150 * @returns {Roo.BoxComponent} this
17152 setPagePosition : function(x, y){
17155 if(!this.boxReady){
17158 if(x === undefined || y === undefined){ // cannot translate undefined points
17161 var p = this.el.translatePoints(x, y);
17162 this.setPosition(p.left, p.top);
17167 onRender : function(ct, position){
17168 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
17170 this.resizeEl = Roo.get(this.resizeEl);
17172 if(this.positionEl){
17173 this.positionEl = Roo.get(this.positionEl);
17178 afterRender : function(){
17179 Roo.BoxComponent.superclass.afterRender.call(this);
17180 this.boxReady = true;
17181 this.setSize(this.width, this.height);
17182 if(this.x || this.y){
17183 this.setPosition(this.x, this.y);
17185 if(this.pageX || this.pageY){
17186 this.setPagePosition(this.pageX, this.pageY);
17191 * Force the component's size to recalculate based on the underlying element's current height and width.
17192 * @returns {Roo.BoxComponent} this
17194 syncSize : function(){
17195 delete this.lastSize;
17196 this.setSize(this.el.getWidth(), this.el.getHeight());
17201 * Called after the component is resized, this method is empty by default but can be implemented by any
17202 * subclass that needs to perform custom logic after a resize occurs.
17203 * @param {Number} adjWidth The box-adjusted width that was set
17204 * @param {Number} adjHeight The box-adjusted height that was set
17205 * @param {Number} rawWidth The width that was originally specified
17206 * @param {Number} rawHeight The height that was originally specified
17208 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
17213 * Called after the component is moved, this method is empty by default but can be implemented by any
17214 * subclass that needs to perform custom logic after a move occurs.
17215 * @param {Number} x The new x position
17216 * @param {Number} y The new y position
17218 onPosition : function(x, y){
17223 adjustSize : function(w, h){
17224 if(this.autoWidth){
17227 if(this.autoHeight){
17230 return {width : w, height: h};
17234 adjustPosition : function(x, y){
17235 return {x : x, y: y};
17239 * Ext JS Library 1.1.1
17240 * Copyright(c) 2006-2007, Ext JS, LLC.
17242 * Originally Released Under LGPL - original licence link has changed is not relivant.
17245 * <script type="text/javascript">
17250 * @extends Roo.Element
17251 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
17252 * automatic maintaining of shadow/shim positions.
17253 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
17254 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
17255 * you can pass a string with a CSS class name. False turns off the shadow.
17256 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
17257 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
17258 * @cfg {String} cls CSS class to add to the element
17259 * @cfg {Number} zindex Starting z-index (defaults to 11000)
17260 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
17262 * @param {Object} config An object with config options.
17263 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
17266 Roo.Layer = function(config, existingEl){
17267 config = config || {};
17268 var dh = Roo.DomHelper;
17269 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
17271 this.dom = Roo.getDom(existingEl);
17274 var o = config.dh || {tag: "div", cls: "x-layer"};
17275 this.dom = dh.append(pel, o);
17278 this.addClass(config.cls);
17280 this.constrain = config.constrain !== false;
17281 this.visibilityMode = Roo.Element.VISIBILITY;
17283 this.id = this.dom.id = config.id;
17285 this.id = Roo.id(this.dom);
17287 this.zindex = config.zindex || this.getZIndex();
17288 this.position("absolute", this.zindex);
17290 this.shadowOffset = config.shadowOffset || 4;
17291 this.shadow = new Roo.Shadow({
17292 offset : this.shadowOffset,
17293 mode : config.shadow
17296 this.shadowOffset = 0;
17298 this.useShim = config.shim !== false && Roo.useShims;
17299 this.useDisplay = config.useDisplay;
17303 var supr = Roo.Element.prototype;
17305 // shims are shared among layer to keep from having 100 iframes
17308 Roo.extend(Roo.Layer, Roo.Element, {
17310 getZIndex : function(){
17311 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
17314 getShim : function(){
17321 var shim = shims.shift();
17323 shim = this.createShim();
17324 shim.enableDisplayMode('block');
17325 shim.dom.style.display = 'none';
17326 shim.dom.style.visibility = 'visible';
17328 var pn = this.dom.parentNode;
17329 if(shim.dom.parentNode != pn){
17330 pn.insertBefore(shim.dom, this.dom);
17332 shim.setStyle('z-index', this.getZIndex()-2);
17337 hideShim : function(){
17339 this.shim.setDisplayed(false);
17340 shims.push(this.shim);
17345 disableShadow : function(){
17347 this.shadowDisabled = true;
17348 this.shadow.hide();
17349 this.lastShadowOffset = this.shadowOffset;
17350 this.shadowOffset = 0;
17354 enableShadow : function(show){
17356 this.shadowDisabled = false;
17357 this.shadowOffset = this.lastShadowOffset;
17358 delete this.lastShadowOffset;
17366 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
17367 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
17368 sync : function(doShow){
17369 var sw = this.shadow;
17370 if(!this.updating && this.isVisible() && (sw || this.useShim)){
17371 var sh = this.getShim();
17373 var w = this.getWidth(),
17374 h = this.getHeight();
17376 var l = this.getLeft(true),
17377 t = this.getTop(true);
17379 if(sw && !this.shadowDisabled){
17380 if(doShow && !sw.isVisible()){
17383 sw.realign(l, t, w, h);
17389 // fit the shim behind the shadow, so it is shimmed too
17390 var a = sw.adjusts, s = sh.dom.style;
17391 s.left = (Math.min(l, l+a.l))+"px";
17392 s.top = (Math.min(t, t+a.t))+"px";
17393 s.width = (w+a.w)+"px";
17394 s.height = (h+a.h)+"px";
17401 sh.setLeftTop(l, t);
17408 destroy : function(){
17411 this.shadow.hide();
17413 this.removeAllListeners();
17414 var pn = this.dom.parentNode;
17416 pn.removeChild(this.dom);
17418 Roo.Element.uncache(this.id);
17421 remove : function(){
17426 beginUpdate : function(){
17427 this.updating = true;
17431 endUpdate : function(){
17432 this.updating = false;
17437 hideUnders : function(negOffset){
17439 this.shadow.hide();
17445 constrainXY : function(){
17446 if(this.constrain){
17447 var vw = Roo.lib.Dom.getViewWidth(),
17448 vh = Roo.lib.Dom.getViewHeight();
17449 var s = Roo.get(document).getScroll();
17451 var xy = this.getXY();
17452 var x = xy[0], y = xy[1];
17453 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
17454 // only move it if it needs it
17456 // first validate right/bottom
17457 if((x + w) > vw+s.left){
17458 x = vw - w - this.shadowOffset;
17461 if((y + h) > vh+s.top){
17462 y = vh - h - this.shadowOffset;
17465 // then make sure top/left isn't negative
17476 var ay = this.avoidY;
17477 if(y <= ay && (y+h) >= ay){
17483 supr.setXY.call(this, xy);
17489 isVisible : function(){
17490 return this.visible;
17494 showAction : function(){
17495 this.visible = true; // track visibility to prevent getStyle calls
17496 if(this.useDisplay === true){
17497 this.setDisplayed("");
17498 }else if(this.lastXY){
17499 supr.setXY.call(this, this.lastXY);
17500 }else if(this.lastLT){
17501 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
17506 hideAction : function(){
17507 this.visible = false;
17508 if(this.useDisplay === true){
17509 this.setDisplayed(false);
17511 this.setLeftTop(-10000,-10000);
17515 // overridden Element method
17516 setVisible : function(v, a, d, c, e){
17521 var cb = function(){
17526 }.createDelegate(this);
17527 supr.setVisible.call(this, true, true, d, cb, e);
17530 this.hideUnders(true);
17539 }.createDelegate(this);
17541 supr.setVisible.call(this, v, a, d, cb, e);
17550 storeXY : function(xy){
17551 delete this.lastLT;
17555 storeLeftTop : function(left, top){
17556 delete this.lastXY;
17557 this.lastLT = [left, top];
17561 beforeFx : function(){
17562 this.beforeAction();
17563 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
17567 afterFx : function(){
17568 Roo.Layer.superclass.afterFx.apply(this, arguments);
17569 this.sync(this.isVisible());
17573 beforeAction : function(){
17574 if(!this.updating && this.shadow){
17575 this.shadow.hide();
17579 // overridden Element method
17580 setLeft : function(left){
17581 this.storeLeftTop(left, this.getTop(true));
17582 supr.setLeft.apply(this, arguments);
17586 setTop : function(top){
17587 this.storeLeftTop(this.getLeft(true), top);
17588 supr.setTop.apply(this, arguments);
17592 setLeftTop : function(left, top){
17593 this.storeLeftTop(left, top);
17594 supr.setLeftTop.apply(this, arguments);
17598 setXY : function(xy, a, d, c, e){
17600 this.beforeAction();
17602 var cb = this.createCB(c);
17603 supr.setXY.call(this, xy, a, d, cb, e);
17610 createCB : function(c){
17621 // overridden Element method
17622 setX : function(x, a, d, c, e){
17623 this.setXY([x, this.getY()], a, d, c, e);
17626 // overridden Element method
17627 setY : function(y, a, d, c, e){
17628 this.setXY([this.getX(), y], a, d, c, e);
17631 // overridden Element method
17632 setSize : function(w, h, a, d, c, e){
17633 this.beforeAction();
17634 var cb = this.createCB(c);
17635 supr.setSize.call(this, w, h, a, d, cb, e);
17641 // overridden Element method
17642 setWidth : function(w, a, d, c, e){
17643 this.beforeAction();
17644 var cb = this.createCB(c);
17645 supr.setWidth.call(this, w, a, d, cb, e);
17651 // overridden Element method
17652 setHeight : function(h, a, d, c, e){
17653 this.beforeAction();
17654 var cb = this.createCB(c);
17655 supr.setHeight.call(this, h, a, d, cb, e);
17661 // overridden Element method
17662 setBounds : function(x, y, w, h, a, d, c, e){
17663 this.beforeAction();
17664 var cb = this.createCB(c);
17666 this.storeXY([x, y]);
17667 supr.setXY.call(this, [x, y]);
17668 supr.setSize.call(this, w, h, a, d, cb, e);
17671 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
17677 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
17678 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
17679 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
17680 * @param {Number} zindex The new z-index to set
17681 * @return {this} The Layer
17683 setZIndex : function(zindex){
17684 this.zindex = zindex;
17685 this.setStyle("z-index", zindex + 2);
17687 this.shadow.setZIndex(zindex + 1);
17690 this.shim.setStyle("z-index", zindex);
17695 * Original code for Roojs - LGPL
17696 * <script type="text/javascript">
17700 * @class Roo.XComponent
17701 * A delayed Element creator...
17702 * Or a way to group chunks of interface together.
17703 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
17704 * used in conjunction with XComponent.build() it will create an instance of each element,
17705 * then call addxtype() to build the User interface.
17707 * Mypart.xyx = new Roo.XComponent({
17709 parent : 'Mypart.xyz', // empty == document.element.!!
17713 disabled : function() {}
17715 tree : function() { // return an tree of xtype declared components
17719 xtype : 'NestedLayoutPanel',
17726 * It can be used to build a big heiracy, with parent etc.
17727 * or you can just use this to render a single compoent to a dom element
17728 * MYPART.render(Roo.Element | String(id) | dom_element )
17735 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
17736 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
17738 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
17740 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
17741 * - if mulitple topModules exist, the last one is defined as the top module.
17745 * When the top level or multiple modules are to embedded into a existing HTML page,
17746 * the parent element can container '#id' of the element where the module will be drawn.
17750 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
17751 * it relies more on a include mechanism, where sub modules are included into an outer page.
17752 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
17754 * Bootstrap Roo Included elements
17756 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
17757 * hence confusing the component builder as it thinks there are multiple top level elements.
17759 * String Over-ride & Translations
17761 * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
17762 * and also the 'overlaying of string values - needed when different versions of the same application with different text content
17763 * are needed. @see Roo.XComponent.overlayString
17767 * @extends Roo.util.Observable
17769 * @param cfg {Object} configuration of component
17772 Roo.XComponent = function(cfg) {
17773 Roo.apply(this, cfg);
17777 * Fires when this the componnt is built
17778 * @param {Roo.XComponent} c the component
17783 this.region = this.region || 'center'; // default..
17784 Roo.XComponent.register(this);
17785 this.modules = false;
17786 this.el = false; // where the layout goes..
17790 Roo.extend(Roo.XComponent, Roo.util.Observable, {
17793 * The created element (with Roo.factory())
17794 * @type {Roo.Layout}
17800 * for BC - use el in new code
17801 * @type {Roo.Layout}
17807 * for BC - use el in new code
17808 * @type {Roo.Layout}
17813 * @cfg {Function|boolean} disabled
17814 * If this module is disabled by some rule, return true from the funtion
17819 * @cfg {String} parent
17820 * Name of parent element which it get xtype added to..
17825 * @cfg {String} order
17826 * Used to set the order in which elements are created (usefull for multiple tabs)
17831 * @cfg {String} name
17832 * String to display while loading.
17836 * @cfg {String} region
17837 * Region to render component to (defaults to center)
17842 * @cfg {Array} items
17843 * A single item array - the first element is the root of the tree..
17844 * It's done this way to stay compatible with the Xtype system...
17850 * The method that retuns the tree of parts that make up this compoennt
17857 * render element to dom or tree
17858 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
17861 render : function(el)
17865 var hp = this.parent ? 1 : 0;
17866 Roo.debug && Roo.log(this);
17868 var tree = this._tree ? this._tree() : this.tree();
17871 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
17872 // if parent is a '#.....' string, then let's use that..
17873 var ename = this.parent.substr(1);
17874 this.parent = false;
17875 Roo.debug && Roo.log(ename);
17877 case 'bootstrap-body':
17878 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
17879 // this is the BorderLayout standard?
17880 this.parent = { el : true };
17883 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
17884 // need to insert stuff...
17886 el : new Roo.bootstrap.layout.Border({
17887 el : document.body,
17893 tabPosition: 'top',
17894 //resizeTabs: true,
17895 alwaysShowTabs: true,
17905 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
17906 this.parent = { el : new Roo.bootstrap.Body() };
17907 Roo.debug && Roo.log("setting el to doc body");
17910 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
17914 this.parent = { el : true};
17917 el = Roo.get(ename);
17918 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
17919 this.parent = { el : true};
17926 if (!el && !this.parent) {
17927 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
17932 Roo.debug && Roo.log("EL:");
17933 Roo.debug && Roo.log(el);
17934 Roo.debug && Roo.log("this.parent.el:");
17935 Roo.debug && Roo.log(this.parent.el);
17938 // altertive root elements ??? - we need a better way to indicate these.
17939 var is_alt = Roo.XComponent.is_alt ||
17940 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
17941 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
17942 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
17946 if (!this.parent && is_alt) {
17947 //el = Roo.get(document.body);
17948 this.parent = { el : true };
17953 if (!this.parent) {
17955 Roo.debug && Roo.log("no parent - creating one");
17957 el = el ? Roo.get(el) : false;
17959 if (typeof(Roo.BorderLayout) == 'undefined' ) {
17962 el : new Roo.bootstrap.layout.Border({
17963 el: el || document.body,
17969 tabPosition: 'top',
17970 //resizeTabs: true,
17971 alwaysShowTabs: false,
17974 overflow: 'visible'
17980 // it's a top level one..
17982 el : new Roo.BorderLayout(el || document.body, {
17987 tabPosition: 'top',
17988 //resizeTabs: true,
17989 alwaysShowTabs: el && hp? false : true,
17990 hideTabs: el || !hp ? true : false,
17998 if (!this.parent.el) {
17999 // probably an old style ctor, which has been disabled.
18003 // The 'tree' method is '_tree now'
18005 tree.region = tree.region || this.region;
18006 var is_body = false;
18007 if (this.parent.el === true) {
18008 // bootstrap... - body..
18012 this.parent.el = Roo.factory(tree);
18016 this.el = this.parent.el.addxtype(tree, undefined, is_body);
18017 this.fireEvent('built', this);
18019 this.panel = this.el;
18020 this.layout = this.panel.layout;
18021 this.parentLayout = this.parent.layout || false;
18027 Roo.apply(Roo.XComponent, {
18029 * @property hideProgress
18030 * true to disable the building progress bar.. usefull on single page renders.
18033 hideProgress : false,
18035 * @property buildCompleted
18036 * True when the builder has completed building the interface.
18039 buildCompleted : false,
18042 * @property topModule
18043 * the upper most module - uses document.element as it's constructor.
18050 * @property modules
18051 * array of modules to be created by registration system.
18052 * @type {Array} of Roo.XComponent
18057 * @property elmodules
18058 * array of modules to be created by which use #ID
18059 * @type {Array} of Roo.XComponent
18066 * Is an alternative Root - normally used by bootstrap or other systems,
18067 * where the top element in the tree can wrap 'body'
18068 * @type {boolean} (default false)
18073 * @property build_from_html
18074 * Build elements from html - used by bootstrap HTML stuff
18075 * - this is cleared after build is completed
18076 * @type {boolean} (default false)
18079 build_from_html : false,
18081 * Register components to be built later.
18083 * This solves the following issues
18084 * - Building is not done on page load, but after an authentication process has occured.
18085 * - Interface elements are registered on page load
18086 * - Parent Interface elements may not be loaded before child, so this handles that..
18093 module : 'Pman.Tab.projectMgr',
18095 parent : 'Pman.layout',
18096 disabled : false, // or use a function..
18099 * * @param {Object} details about module
18101 register : function(obj) {
18103 Roo.XComponent.event.fireEvent('register', obj);
18104 switch(typeof(obj.disabled) ) {
18110 if ( obj.disabled() ) {
18116 if (obj.disabled || obj.region == '#disabled') {
18122 this.modules.push(obj);
18126 * convert a string to an object..
18127 * eg. 'AAA.BBB' -> finds AAA.BBB
18131 toObject : function(str)
18133 if (!str || typeof(str) == 'object') {
18136 if (str.substring(0,1) == '#') {
18140 var ar = str.split('.');
18145 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
18147 throw "Module not found : " + str;
18151 throw "Module not found : " + str;
18153 Roo.each(ar, function(e) {
18154 if (typeof(o[e]) == 'undefined') {
18155 throw "Module not found : " + str;
18166 * move modules into their correct place in the tree..
18169 preBuild : function ()
18172 Roo.each(this.modules , function (obj)
18174 Roo.XComponent.event.fireEvent('beforebuild', obj);
18176 var opar = obj.parent;
18178 obj.parent = this.toObject(opar);
18180 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
18185 Roo.debug && Roo.log("GOT top level module");
18186 Roo.debug && Roo.log(obj);
18187 obj.modules = new Roo.util.MixedCollection(false,
18188 function(o) { return o.order + '' }
18190 this.topModule = obj;
18193 // parent is a string (usually a dom element name..)
18194 if (typeof(obj.parent) == 'string') {
18195 this.elmodules.push(obj);
18198 if (obj.parent.constructor != Roo.XComponent) {
18199 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
18201 if (!obj.parent.modules) {
18202 obj.parent.modules = new Roo.util.MixedCollection(false,
18203 function(o) { return o.order + '' }
18206 if (obj.parent.disabled) {
18207 obj.disabled = true;
18209 obj.parent.modules.add(obj);
18214 * make a list of modules to build.
18215 * @return {Array} list of modules.
18218 buildOrder : function()
18221 var cmp = function(a,b) {
18222 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
18224 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
18225 throw "No top level modules to build";
18228 // make a flat list in order of modules to build.
18229 var mods = this.topModule ? [ this.topModule ] : [];
18232 // elmodules (is a list of DOM based modules )
18233 Roo.each(this.elmodules, function(e) {
18235 if (!this.topModule &&
18236 typeof(e.parent) == 'string' &&
18237 e.parent.substring(0,1) == '#' &&
18238 Roo.get(e.parent.substr(1))
18241 _this.topModule = e;
18247 // add modules to their parents..
18248 var addMod = function(m) {
18249 Roo.debug && Roo.log("build Order: add: " + m.name);
18252 if (m.modules && !m.disabled) {
18253 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
18254 m.modules.keySort('ASC', cmp );
18255 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
18257 m.modules.each(addMod);
18259 Roo.debug && Roo.log("build Order: no child modules");
18261 // not sure if this is used any more..
18263 m.finalize.name = m.name + " (clean up) ";
18264 mods.push(m.finalize);
18268 if (this.topModule && this.topModule.modules) {
18269 this.topModule.modules.keySort('ASC', cmp );
18270 this.topModule.modules.each(addMod);
18276 * Build the registered modules.
18277 * @param {Object} parent element.
18278 * @param {Function} optional method to call after module has been added.
18282 build : function(opts)
18285 if (typeof(opts) != 'undefined') {
18286 Roo.apply(this,opts);
18290 var mods = this.buildOrder();
18292 //this.allmods = mods;
18293 //Roo.debug && Roo.log(mods);
18295 if (!mods.length) { // should not happen
18296 throw "NO modules!!!";
18300 var msg = "Building Interface...";
18301 // flash it up as modal - so we store the mask!?
18302 if (!this.hideProgress && Roo.MessageBox) {
18303 Roo.MessageBox.show({ title: 'loading' });
18304 Roo.MessageBox.show({
18305 title: "Please wait...",
18315 var total = mods.length;
18318 var progressRun = function() {
18319 if (!mods.length) {
18320 Roo.debug && Roo.log('hide?');
18321 if (!this.hideProgress && Roo.MessageBox) {
18322 Roo.MessageBox.hide();
18324 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
18326 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
18332 var m = mods.shift();
18335 Roo.debug && Roo.log(m);
18336 // not sure if this is supported any more.. - modules that are are just function
18337 if (typeof(m) == 'function') {
18339 return progressRun.defer(10, _this);
18343 msg = "Building Interface " + (total - mods.length) +
18345 (m.name ? (' - ' + m.name) : '');
18346 Roo.debug && Roo.log(msg);
18347 if (!_this.hideProgress && Roo.MessageBox) {
18348 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
18352 // is the module disabled?
18353 var disabled = (typeof(m.disabled) == 'function') ?
18354 m.disabled.call(m.module.disabled) : m.disabled;
18358 return progressRun(); // we do not update the display!
18366 // it's 10 on top level, and 1 on others??? why...
18367 return progressRun.defer(10, _this);
18370 progressRun.defer(1, _this);
18376 * Overlay a set of modified strings onto a component
18377 * This is dependant on our builder exporting the strings and 'named strings' elements.
18379 * @param {Object} element to overlay on - eg. Pman.Dialog.Login
18380 * @param {Object} associative array of 'named' string and it's new value.
18383 overlayStrings : function( component, strings )
18385 if (typeof(component['_named_strings']) == 'undefined') {
18386 throw "ERROR: component does not have _named_strings";
18388 for ( var k in strings ) {
18389 var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
18390 if (md !== false) {
18391 component['_strings'][md] = strings[k];
18393 Roo.log('could not find named string: ' + k + ' in');
18394 Roo.log(component);
18409 * wrapper for event.on - aliased later..
18410 * Typically use to register a event handler for register:
18412 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
18421 Roo.XComponent.event = new Roo.util.Observable({
18425 * Fires when an Component is registered,
18426 * set the disable property on the Component to stop registration.
18427 * @param {Roo.XComponent} c the component being registerd.
18432 * @event beforebuild
18433 * Fires before each Component is built
18434 * can be used to apply permissions.
18435 * @param {Roo.XComponent} c the component being registerd.
18438 'beforebuild' : true,
18440 * @event buildcomplete
18441 * Fires on the top level element when all elements have been built
18442 * @param {Roo.XComponent} the top level component.
18444 'buildcomplete' : true
18449 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
18452 * marked - a markdown parser
18453 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
18454 * https://github.com/chjj/marked
18460 * Roo.Markdown - is a very crude wrapper around marked..
18464 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
18466 * Note: move the sample code to the bottom of this
18467 * file before uncommenting it.
18472 Roo.Markdown.toHtml = function(text) {
18474 var c = new Roo.Markdown.marked.setOptions({
18475 renderer: new Roo.Markdown.marked.Renderer(),
18486 text = text.replace(/\\\n/g,' ');
18487 return Roo.Markdown.marked(text);
18492 // Wraps all "globals" so that the only thing
18493 // exposed is makeHtml().
18499 * eval:var:unescape
18507 var escape = function (html, encode) {
18509 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
18510 .replace(/</g, '<')
18511 .replace(/>/g, '>')
18512 .replace(/"/g, '"')
18513 .replace(/'/g, ''');
18516 var unescape = function (html) {
18517 // explicitly match decimal, hex, and named HTML entities
18518 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
18519 n = n.toLowerCase();
18520 if (n === 'colon') { return ':'; }
18521 if (n.charAt(0) === '#') {
18522 return n.charAt(1) === 'x'
18523 ? String.fromCharCode(parseInt(n.substring(2), 16))
18524 : String.fromCharCode(+n.substring(1));
18530 var replace = function (regex, opt) {
18531 regex = regex.source;
18533 return function self(name, val) {
18534 if (!name) { return new RegExp(regex, opt); }
18535 val = val.source || val;
18536 val = val.replace(/(^|[^\[])\^/g, '$1');
18537 regex = regex.replace(name, val);
18546 var noop = function () {}
18552 var merge = function (obj) {
18557 for (; i < arguments.length; i++) {
18558 target = arguments[i];
18559 for (key in target) {
18560 if (Object.prototype.hasOwnProperty.call(target, key)) {
18561 obj[key] = target[key];
18571 * Block-Level Grammar
18579 code: /^( {4}[^\n]+\n*)+/,
18581 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
18582 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
18584 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
18585 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
18586 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
18587 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
18588 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
18590 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
18594 block.bullet = /(?:[*+-]|\d+\.)/;
18595 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
18596 block.item = replace(block.item, 'gm')
18597 (/bull/g, block.bullet)
18600 block.list = replace(block.list)
18601 (/bull/g, block.bullet)
18602 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
18603 ('def', '\\n+(?=' + block.def.source + ')')
18606 block.blockquote = replace(block.blockquote)
18610 block._tag = '(?!(?:'
18611 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
18612 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
18613 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
18615 block.html = replace(block.html)
18616 ('comment', /<!--[\s\S]*?-->/)
18617 ('closed', /<(tag)[\s\S]+?<\/\1>/)
18618 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
18619 (/tag/g, block._tag)
18622 block.paragraph = replace(block.paragraph)
18624 ('heading', block.heading)
18625 ('lheading', block.lheading)
18626 ('blockquote', block.blockquote)
18627 ('tag', '<' + block._tag)
18632 * Normal Block Grammar
18635 block.normal = merge({}, block);
18638 * GFM Block Grammar
18641 block.gfm = merge({}, block.normal, {
18642 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
18644 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
18647 block.gfm.paragraph = replace(block.paragraph)
18649 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
18650 + block.list.source.replace('\\1', '\\3') + '|')
18654 * GFM + Tables Block Grammar
18657 block.tables = merge({}, block.gfm, {
18658 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
18659 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
18666 var Lexer = function (options) {
18668 this.tokens.links = {};
18669 this.options = options || marked.defaults;
18670 this.rules = block.normal;
18672 if (this.options.gfm) {
18673 if (this.options.tables) {
18674 this.rules = block.tables;
18676 this.rules = block.gfm;
18682 * Expose Block Rules
18685 Lexer.rules = block;
18688 * Static Lex Method
18691 Lexer.lex = function(src, options) {
18692 var lexer = new Lexer(options);
18693 return lexer.lex(src);
18700 Lexer.prototype.lex = function(src) {
18702 .replace(/\r\n|\r/g, '\n')
18703 .replace(/\t/g, ' ')
18704 .replace(/\u00a0/g, ' ')
18705 .replace(/\u2424/g, '\n');
18707 return this.token(src, true);
18714 Lexer.prototype.token = function(src, top, bq) {
18715 var src = src.replace(/^ +$/gm, '')
18728 if (cap = this.rules.newline.exec(src)) {
18729 src = src.substring(cap[0].length);
18730 if (cap[0].length > 1) {
18738 if (cap = this.rules.code.exec(src)) {
18739 src = src.substring(cap[0].length);
18740 cap = cap[0].replace(/^ {4}/gm, '');
18743 text: !this.options.pedantic
18744 ? cap.replace(/\n+$/, '')
18751 if (cap = this.rules.fences.exec(src)) {
18752 src = src.substring(cap[0].length);
18762 if (cap = this.rules.heading.exec(src)) {
18763 src = src.substring(cap[0].length);
18766 depth: cap[1].length,
18772 // table no leading pipe (gfm)
18773 if (top && (cap = this.rules.nptable.exec(src))) {
18774 src = src.substring(cap[0].length);
18778 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18779 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18780 cells: cap[3].replace(/\n$/, '').split('\n')
18783 for (i = 0; i < item.align.length; i++) {
18784 if (/^ *-+: *$/.test(item.align[i])) {
18785 item.align[i] = 'right';
18786 } else if (/^ *:-+: *$/.test(item.align[i])) {
18787 item.align[i] = 'center';
18788 } else if (/^ *:-+ *$/.test(item.align[i])) {
18789 item.align[i] = 'left';
18791 item.align[i] = null;
18795 for (i = 0; i < item.cells.length; i++) {
18796 item.cells[i] = item.cells[i].split(/ *\| */);
18799 this.tokens.push(item);
18805 if (cap = this.rules.lheading.exec(src)) {
18806 src = src.substring(cap[0].length);
18809 depth: cap[2] === '=' ? 1 : 2,
18816 if (cap = this.rules.hr.exec(src)) {
18817 src = src.substring(cap[0].length);
18825 if (cap = this.rules.blockquote.exec(src)) {
18826 src = src.substring(cap[0].length);
18829 type: 'blockquote_start'
18832 cap = cap[0].replace(/^ *> ?/gm, '');
18834 // Pass `top` to keep the current
18835 // "toplevel" state. This is exactly
18836 // how markdown.pl works.
18837 this.token(cap, top, true);
18840 type: 'blockquote_end'
18847 if (cap = this.rules.list.exec(src)) {
18848 src = src.substring(cap[0].length);
18852 type: 'list_start',
18853 ordered: bull.length > 1
18856 // Get each top-level item.
18857 cap = cap[0].match(this.rules.item);
18863 for (; i < l; i++) {
18866 // Remove the list item's bullet
18867 // so it is seen as the next token.
18868 space = item.length;
18869 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
18871 // Outdent whatever the
18872 // list item contains. Hacky.
18873 if (~item.indexOf('\n ')) {
18874 space -= item.length;
18875 item = !this.options.pedantic
18876 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
18877 : item.replace(/^ {1,4}/gm, '');
18880 // Determine whether the next list item belongs here.
18881 // Backpedal if it does not belong in this list.
18882 if (this.options.smartLists && i !== l - 1) {
18883 b = block.bullet.exec(cap[i + 1])[0];
18884 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
18885 src = cap.slice(i + 1).join('\n') + src;
18890 // Determine whether item is loose or not.
18891 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
18892 // for discount behavior.
18893 loose = next || /\n\n(?!\s*$)/.test(item);
18895 next = item.charAt(item.length - 1) === '\n';
18896 if (!loose) { loose = next; }
18901 ? 'loose_item_start'
18902 : 'list_item_start'
18906 this.token(item, false, bq);
18909 type: 'list_item_end'
18921 if (cap = this.rules.html.exec(src)) {
18922 src = src.substring(cap[0].length);
18924 type: this.options.sanitize
18927 pre: !this.options.sanitizer
18928 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
18935 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
18936 src = src.substring(cap[0].length);
18937 this.tokens.links[cap[1].toLowerCase()] = {
18945 if (top && (cap = this.rules.table.exec(src))) {
18946 src = src.substring(cap[0].length);
18950 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18951 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18952 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
18955 for (i = 0; i < item.align.length; i++) {
18956 if (/^ *-+: *$/.test(item.align[i])) {
18957 item.align[i] = 'right';
18958 } else if (/^ *:-+: *$/.test(item.align[i])) {
18959 item.align[i] = 'center';
18960 } else if (/^ *:-+ *$/.test(item.align[i])) {
18961 item.align[i] = 'left';
18963 item.align[i] = null;
18967 for (i = 0; i < item.cells.length; i++) {
18968 item.cells[i] = item.cells[i]
18969 .replace(/^ *\| *| *\| *$/g, '')
18973 this.tokens.push(item);
18978 // top-level paragraph
18979 if (top && (cap = this.rules.paragraph.exec(src))) {
18980 src = src.substring(cap[0].length);
18983 text: cap[1].charAt(cap[1].length - 1) === '\n'
18984 ? cap[1].slice(0, -1)
18991 if (cap = this.rules.text.exec(src)) {
18992 // Top-level should never reach here.
18993 src = src.substring(cap[0].length);
19003 Error('Infinite loop on byte: ' + src.charCodeAt(0));
19007 return this.tokens;
19011 * Inline-Level Grammar
19015 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
19016 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
19018 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
19019 link: /^!?\[(inside)\]\(href\)/,
19020 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
19021 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
19022 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
19023 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
19024 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
19025 br: /^ {2,}\n(?!\s*$)/,
19027 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
19030 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
19031 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
19033 inline.link = replace(inline.link)
19034 ('inside', inline._inside)
19035 ('href', inline._href)
19038 inline.reflink = replace(inline.reflink)
19039 ('inside', inline._inside)
19043 * Normal Inline Grammar
19046 inline.normal = merge({}, inline);
19049 * Pedantic Inline Grammar
19052 inline.pedantic = merge({}, inline.normal, {
19053 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
19054 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
19058 * GFM Inline Grammar
19061 inline.gfm = merge({}, inline.normal, {
19062 escape: replace(inline.escape)('])', '~|])')(),
19063 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
19064 del: /^~~(?=\S)([\s\S]*?\S)~~/,
19065 text: replace(inline.text)
19067 ('|', '|https?://|')
19072 * GFM + Line Breaks Inline Grammar
19075 inline.breaks = merge({}, inline.gfm, {
19076 br: replace(inline.br)('{2,}', '*')(),
19077 text: replace(inline.gfm.text)('{2,}', '*')()
19081 * Inline Lexer & Compiler
19084 var InlineLexer = function (links, options) {
19085 this.options = options || marked.defaults;
19086 this.links = links;
19087 this.rules = inline.normal;
19088 this.renderer = this.options.renderer || new Renderer;
19089 this.renderer.options = this.options;
19093 Error('Tokens array requires a `links` property.');
19096 if (this.options.gfm) {
19097 if (this.options.breaks) {
19098 this.rules = inline.breaks;
19100 this.rules = inline.gfm;
19102 } else if (this.options.pedantic) {
19103 this.rules = inline.pedantic;
19108 * Expose Inline Rules
19111 InlineLexer.rules = inline;
19114 * Static Lexing/Compiling Method
19117 InlineLexer.output = function(src, links, options) {
19118 var inline = new InlineLexer(links, options);
19119 return inline.output(src);
19126 InlineLexer.prototype.output = function(src) {
19135 if (cap = this.rules.escape.exec(src)) {
19136 src = src.substring(cap[0].length);
19142 if (cap = this.rules.autolink.exec(src)) {
19143 src = src.substring(cap[0].length);
19144 if (cap[2] === '@') {
19145 text = cap[1].charAt(6) === ':'
19146 ? this.mangle(cap[1].substring(7))
19147 : this.mangle(cap[1]);
19148 href = this.mangle('mailto:') + text;
19150 text = escape(cap[1]);
19153 out += this.renderer.link(href, null, text);
19158 if (!this.inLink && (cap = this.rules.url.exec(src))) {
19159 src = src.substring(cap[0].length);
19160 text = escape(cap[1]);
19162 out += this.renderer.link(href, null, text);
19167 if (cap = this.rules.tag.exec(src)) {
19168 if (!this.inLink && /^<a /i.test(cap[0])) {
19169 this.inLink = true;
19170 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
19171 this.inLink = false;
19173 src = src.substring(cap[0].length);
19174 out += this.options.sanitize
19175 ? this.options.sanitizer
19176 ? this.options.sanitizer(cap[0])
19183 if (cap = this.rules.link.exec(src)) {
19184 src = src.substring(cap[0].length);
19185 this.inLink = true;
19186 out += this.outputLink(cap, {
19190 this.inLink = false;
19195 if ((cap = this.rules.reflink.exec(src))
19196 || (cap = this.rules.nolink.exec(src))) {
19197 src = src.substring(cap[0].length);
19198 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
19199 link = this.links[link.toLowerCase()];
19200 if (!link || !link.href) {
19201 out += cap[0].charAt(0);
19202 src = cap[0].substring(1) + src;
19205 this.inLink = true;
19206 out += this.outputLink(cap, link);
19207 this.inLink = false;
19212 if (cap = this.rules.strong.exec(src)) {
19213 src = src.substring(cap[0].length);
19214 out += this.renderer.strong(this.output(cap[2] || cap[1]));
19219 if (cap = this.rules.em.exec(src)) {
19220 src = src.substring(cap[0].length);
19221 out += this.renderer.em(this.output(cap[2] || cap[1]));
19226 if (cap = this.rules.code.exec(src)) {
19227 src = src.substring(cap[0].length);
19228 out += this.renderer.codespan(escape(cap[2], true));
19233 if (cap = this.rules.br.exec(src)) {
19234 src = src.substring(cap[0].length);
19235 out += this.renderer.br();
19240 if (cap = this.rules.del.exec(src)) {
19241 src = src.substring(cap[0].length);
19242 out += this.renderer.del(this.output(cap[1]));
19247 if (cap = this.rules.text.exec(src)) {
19248 src = src.substring(cap[0].length);
19249 out += this.renderer.text(escape(this.smartypants(cap[0])));
19255 Error('Infinite loop on byte: ' + src.charCodeAt(0));
19266 InlineLexer.prototype.outputLink = function(cap, link) {
19267 var href = escape(link.href)
19268 , title = link.title ? escape(link.title) : null;
19270 return cap[0].charAt(0) !== '!'
19271 ? this.renderer.link(href, title, this.output(cap[1]))
19272 : this.renderer.image(href, title, escape(cap[1]));
19276 * Smartypants Transformations
19279 InlineLexer.prototype.smartypants = function(text) {
19280 if (!this.options.smartypants) { return text; }
19283 .replace(/---/g, '\u2014')
19285 .replace(/--/g, '\u2013')
19287 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
19288 // closing singles & apostrophes
19289 .replace(/'/g, '\u2019')
19291 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
19293 .replace(/"/g, '\u201d')
19295 .replace(/\.{3}/g, '\u2026');
19302 InlineLexer.prototype.mangle = function(text) {
19303 if (!this.options.mangle) { return text; }
19309 for (; i < l; i++) {
19310 ch = text.charCodeAt(i);
19311 if (Math.random() > 0.5) {
19312 ch = 'x' + ch.toString(16);
19314 out += '&#' + ch + ';';
19325 * eval:var:Renderer
19328 var Renderer = function (options) {
19329 this.options = options || {};
19332 Renderer.prototype.code = function(code, lang, escaped) {
19333 if (this.options.highlight) {
19334 var out = this.options.highlight(code, lang);
19335 if (out != null && out !== code) {
19340 // hack!!! - it's already escapeD?
19345 return '<pre><code>'
19346 + (escaped ? code : escape(code, true))
19347 + '\n</code></pre>';
19350 return '<pre><code class="'
19351 + this.options.langPrefix
19352 + escape(lang, true)
19354 + (escaped ? code : escape(code, true))
19355 + '\n</code></pre>\n';
19358 Renderer.prototype.blockquote = function(quote) {
19359 return '<blockquote>\n' + quote + '</blockquote>\n';
19362 Renderer.prototype.html = function(html) {
19366 Renderer.prototype.heading = function(text, level, raw) {
19370 + this.options.headerPrefix
19371 + raw.toLowerCase().replace(/[^\w]+/g, '-')
19379 Renderer.prototype.hr = function() {
19380 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
19383 Renderer.prototype.list = function(body, ordered) {
19384 var type = ordered ? 'ol' : 'ul';
19385 return '<' + type + '>\n' + body + '</' + type + '>\n';
19388 Renderer.prototype.listitem = function(text) {
19389 return '<li>' + text + '</li>\n';
19392 Renderer.prototype.paragraph = function(text) {
19393 return '<p>' + text + '</p>\n';
19396 Renderer.prototype.table = function(header, body) {
19397 return '<table class="table table-striped">\n'
19407 Renderer.prototype.tablerow = function(content) {
19408 return '<tr>\n' + content + '</tr>\n';
19411 Renderer.prototype.tablecell = function(content, flags) {
19412 var type = flags.header ? 'th' : 'td';
19413 var tag = flags.align
19414 ? '<' + type + ' style="text-align:' + flags.align + '">'
19415 : '<' + type + '>';
19416 return tag + content + '</' + type + '>\n';
19419 // span level renderer
19420 Renderer.prototype.strong = function(text) {
19421 return '<strong>' + text + '</strong>';
19424 Renderer.prototype.em = function(text) {
19425 return '<em>' + text + '</em>';
19428 Renderer.prototype.codespan = function(text) {
19429 return '<code>' + text + '</code>';
19432 Renderer.prototype.br = function() {
19433 return this.options.xhtml ? '<br/>' : '<br>';
19436 Renderer.prototype.del = function(text) {
19437 return '<del>' + text + '</del>';
19440 Renderer.prototype.link = function(href, title, text) {
19441 if (this.options.sanitize) {
19443 var prot = decodeURIComponent(unescape(href))
19444 .replace(/[^\w:]/g, '')
19449 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
19453 var out = '<a href="' + href + '"';
19455 out += ' title="' + title + '"';
19457 out += '>' + text + '</a>';
19461 Renderer.prototype.image = function(href, title, text) {
19462 var out = '<img src="' + href + '" alt="' + text + '"';
19464 out += ' title="' + title + '"';
19466 out += this.options.xhtml ? '/>' : '>';
19470 Renderer.prototype.text = function(text) {
19475 * Parsing & Compiling
19481 var Parser= function (options) {
19484 this.options = options || marked.defaults;
19485 this.options.renderer = this.options.renderer || new Renderer;
19486 this.renderer = this.options.renderer;
19487 this.renderer.options = this.options;
19491 * Static Parse Method
19494 Parser.parse = function(src, options, renderer) {
19495 var parser = new Parser(options, renderer);
19496 return parser.parse(src);
19503 Parser.prototype.parse = function(src) {
19504 this.inline = new InlineLexer(src.links, this.options, this.renderer);
19505 this.tokens = src.reverse();
19508 while (this.next()) {
19519 Parser.prototype.next = function() {
19520 return this.token = this.tokens.pop();
19524 * Preview Next Token
19527 Parser.prototype.peek = function() {
19528 return this.tokens[this.tokens.length - 1] || 0;
19532 * Parse Text Tokens
19535 Parser.prototype.parseText = function() {
19536 var body = this.token.text;
19538 while (this.peek().type === 'text') {
19539 body += '\n' + this.next().text;
19542 return this.inline.output(body);
19546 * Parse Current Token
19549 Parser.prototype.tok = function() {
19550 switch (this.token.type) {
19555 return this.renderer.hr();
19558 return this.renderer.heading(
19559 this.inline.output(this.token.text),
19564 return this.renderer.code(this.token.text,
19566 this.token.escaped);
19579 for (i = 0; i < this.token.header.length; i++) {
19580 flags = { header: true, align: this.token.align[i] };
19581 cell += this.renderer.tablecell(
19582 this.inline.output(this.token.header[i]),
19583 { header: true, align: this.token.align[i] }
19586 header += this.renderer.tablerow(cell);
19588 for (i = 0; i < this.token.cells.length; i++) {
19589 row = this.token.cells[i];
19592 for (j = 0; j < row.length; j++) {
19593 cell += this.renderer.tablecell(
19594 this.inline.output(row[j]),
19595 { header: false, align: this.token.align[j] }
19599 body += this.renderer.tablerow(cell);
19601 return this.renderer.table(header, body);
19603 case 'blockquote_start': {
19606 while (this.next().type !== 'blockquote_end') {
19607 body += this.tok();
19610 return this.renderer.blockquote(body);
19612 case 'list_start': {
19614 , ordered = this.token.ordered;
19616 while (this.next().type !== 'list_end') {
19617 body += this.tok();
19620 return this.renderer.list(body, ordered);
19622 case 'list_item_start': {
19625 while (this.next().type !== 'list_item_end') {
19626 body += this.token.type === 'text'
19631 return this.renderer.listitem(body);
19633 case 'loose_item_start': {
19636 while (this.next().type !== 'list_item_end') {
19637 body += this.tok();
19640 return this.renderer.listitem(body);
19643 var html = !this.token.pre && !this.options.pedantic
19644 ? this.inline.output(this.token.text)
19646 return this.renderer.html(html);
19648 case 'paragraph': {
19649 return this.renderer.paragraph(this.inline.output(this.token.text));
19652 return this.renderer.paragraph(this.parseText());
19664 var marked = function (src, opt, callback) {
19665 if (callback || typeof opt === 'function') {
19671 opt = merge({}, marked.defaults, opt || {});
19673 var highlight = opt.highlight
19679 tokens = Lexer.lex(src, opt)
19681 return callback(e);
19684 pending = tokens.length;
19688 var done = function(err) {
19690 opt.highlight = highlight;
19691 return callback(err);
19697 out = Parser.parse(tokens, opt);
19702 opt.highlight = highlight;
19706 : callback(null, out);
19709 if (!highlight || highlight.length < 3) {
19713 delete opt.highlight;
19715 if (!pending) { return done(); }
19717 for (; i < tokens.length; i++) {
19719 if (token.type !== 'code') {
19720 return --pending || done();
19722 return highlight(token.text, token.lang, function(err, code) {
19723 if (err) { return done(err); }
19724 if (code == null || code === token.text) {
19725 return --pending || done();
19728 token.escaped = true;
19729 --pending || done();
19737 if (opt) { opt = merge({}, marked.defaults, opt); }
19738 return Parser.parse(Lexer.lex(src, opt), opt);
19740 e.message += '\nPlease report this to https://github.com/chjj/marked.';
19741 if ((opt || marked.defaults).silent) {
19742 return '<p>An error occured:</p><pre>'
19743 + escape(e.message + '', true)
19755 marked.setOptions = function(opt) {
19756 merge(marked.defaults, opt);
19760 marked.defaults = {
19771 langPrefix: 'lang-',
19772 smartypants: false,
19774 renderer: new Renderer,
19782 marked.Parser = Parser;
19783 marked.parser = Parser.parse;
19785 marked.Renderer = Renderer;
19787 marked.Lexer = Lexer;
19788 marked.lexer = Lexer.lex;
19790 marked.InlineLexer = InlineLexer;
19791 marked.inlineLexer = InlineLexer.output;
19793 marked.parse = marked;
19795 Roo.Markdown.marked = marked;
19799 * Ext JS Library 1.1.1
19800 * Copyright(c) 2006-2007, Ext JS, LLC.
19802 * Originally Released Under LGPL - original licence link has changed is not relivant.
19805 * <script type="text/javascript">
19811 * These classes are derivatives of the similarly named classes in the YUI Library.
19812 * The original license:
19813 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
19814 * Code licensed under the BSD License:
19815 * http://developer.yahoo.net/yui/license.txt
19820 var Event=Roo.EventManager;
19821 var Dom=Roo.lib.Dom;
19824 * @class Roo.dd.DragDrop
19825 * @extends Roo.util.Observable
19826 * Defines the interface and base operation of items that that can be
19827 * dragged or can be drop targets. It was designed to be extended, overriding
19828 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
19829 * Up to three html elements can be associated with a DragDrop instance:
19831 * <li>linked element: the element that is passed into the constructor.
19832 * This is the element which defines the boundaries for interaction with
19833 * other DragDrop objects.</li>
19834 * <li>handle element(s): The drag operation only occurs if the element that
19835 * was clicked matches a handle element. By default this is the linked
19836 * element, but there are times that you will want only a portion of the
19837 * linked element to initiate the drag operation, and the setHandleElId()
19838 * method provides a way to define this.</li>
19839 * <li>drag element: this represents the element that would be moved along
19840 * with the cursor during a drag operation. By default, this is the linked
19841 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
19842 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
19845 * This class should not be instantiated until the onload event to ensure that
19846 * the associated elements are available.
19847 * The following would define a DragDrop obj that would interact with any
19848 * other DragDrop obj in the "group1" group:
19850 * dd = new Roo.dd.DragDrop("div1", "group1");
19852 * Since none of the event handlers have been implemented, nothing would
19853 * actually happen if you were to run the code above. Normally you would
19854 * override this class or one of the default implementations, but you can
19855 * also override the methods you want on an instance of the class...
19857 * dd.onDragDrop = function(e, id) {
19858 * alert("dd was dropped on " + id);
19862 * @param {String} id of the element that is linked to this instance
19863 * @param {String} sGroup the group of related DragDrop objects
19864 * @param {object} config an object containing configurable attributes
19865 * Valid properties for DragDrop:
19866 * padding, isTarget, maintainOffset, primaryButtonOnly
19868 Roo.dd.DragDrop = function(id, sGroup, config) {
19870 this.init(id, sGroup, config);
19875 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
19878 * The id of the element associated with this object. This is what we
19879 * refer to as the "linked element" because the size and position of
19880 * this element is used to determine when the drag and drop objects have
19888 * Configuration attributes passed into the constructor
19895 * The id of the element that will be dragged. By default this is same
19896 * as the linked element , but could be changed to another element. Ex:
19898 * @property dragElId
19905 * the id of the element that initiates the drag operation. By default
19906 * this is the linked element, but could be changed to be a child of this
19907 * element. This lets us do things like only starting the drag when the
19908 * header element within the linked html element is clicked.
19909 * @property handleElId
19916 * An associative array of HTML tags that will be ignored if clicked.
19917 * @property invalidHandleTypes
19918 * @type {string: string}
19920 invalidHandleTypes: null,
19923 * An associative array of ids for elements that will be ignored if clicked
19924 * @property invalidHandleIds
19925 * @type {string: string}
19927 invalidHandleIds: null,
19930 * An indexted array of css class names for elements that will be ignored
19932 * @property invalidHandleClasses
19935 invalidHandleClasses: null,
19938 * The linked element's absolute X position at the time the drag was
19940 * @property startPageX
19947 * The linked element's absolute X position at the time the drag was
19949 * @property startPageY
19956 * The group defines a logical collection of DragDrop objects that are
19957 * related. Instances only get events when interacting with other
19958 * DragDrop object in the same group. This lets us define multiple
19959 * groups using a single DragDrop subclass if we want.
19961 * @type {string: string}
19966 * Individual drag/drop instances can be locked. This will prevent
19967 * onmousedown start drag.
19975 * Lock this instance
19978 lock: function() { this.locked = true; },
19981 * Unlock this instace
19984 unlock: function() { this.locked = false; },
19987 * By default, all insances can be a drop target. This can be disabled by
19988 * setting isTarget to false.
19995 * The padding configured for this drag and drop object for calculating
19996 * the drop zone intersection with this object.
20003 * Cached reference to the linked element
20004 * @property _domRef
20010 * Internal typeof flag
20011 * @property __ygDragDrop
20014 __ygDragDrop: true,
20017 * Set to true when horizontal contraints are applied
20018 * @property constrainX
20025 * Set to true when vertical contraints are applied
20026 * @property constrainY
20033 * The left constraint
20041 * The right constraint
20049 * The up constraint
20058 * The down constraint
20066 * Maintain offsets when we resetconstraints. Set to true when you want
20067 * the position of the element relative to its parent to stay the same
20068 * when the page changes
20070 * @property maintainOffset
20073 maintainOffset: false,
20076 * Array of pixel locations the element will snap to if we specified a
20077 * horizontal graduation/interval. This array is generated automatically
20078 * when you define a tick interval.
20085 * Array of pixel locations the element will snap to if we specified a
20086 * vertical graduation/interval. This array is generated automatically
20087 * when you define a tick interval.
20094 * By default the drag and drop instance will only respond to the primary
20095 * button click (left button for a right-handed mouse). Set to true to
20096 * allow drag and drop to start with any mouse click that is propogated
20098 * @property primaryButtonOnly
20101 primaryButtonOnly: true,
20104 * The availabe property is false until the linked dom element is accessible.
20105 * @property available
20111 * By default, drags can only be initiated if the mousedown occurs in the
20112 * region the linked element is. This is done in part to work around a
20113 * bug in some browsers that mis-report the mousedown if the previous
20114 * mouseup happened outside of the window. This property is set to true
20115 * if outer handles are defined.
20117 * @property hasOuterHandles
20121 hasOuterHandles: false,
20124 * Code that executes immediately before the startDrag event
20125 * @method b4StartDrag
20128 b4StartDrag: function(x, y) { },
20131 * Abstract method called after a drag/drop object is clicked
20132 * and the drag or mousedown time thresholds have beeen met.
20133 * @method startDrag
20134 * @param {int} X click location
20135 * @param {int} Y click location
20137 startDrag: function(x, y) { /* override this */ },
20140 * Code that executes immediately before the onDrag event
20144 b4Drag: function(e) { },
20147 * Abstract method called during the onMouseMove event while dragging an
20150 * @param {Event} e the mousemove event
20152 onDrag: function(e) { /* override this */ },
20155 * Abstract method called when this element fist begins hovering over
20156 * another DragDrop obj
20157 * @method onDragEnter
20158 * @param {Event} e the mousemove event
20159 * @param {String|DragDrop[]} id In POINT mode, the element
20160 * id this is hovering over. In INTERSECT mode, an array of one or more
20161 * dragdrop items being hovered over.
20163 onDragEnter: function(e, id) { /* override this */ },
20166 * Code that executes immediately before the onDragOver event
20167 * @method b4DragOver
20170 b4DragOver: function(e) { },
20173 * Abstract method called when this element is hovering over another
20175 * @method onDragOver
20176 * @param {Event} e the mousemove event
20177 * @param {String|DragDrop[]} id In POINT mode, the element
20178 * id this is hovering over. In INTERSECT mode, an array of dd items
20179 * being hovered over.
20181 onDragOver: function(e, id) { /* override this */ },
20184 * Code that executes immediately before the onDragOut event
20185 * @method b4DragOut
20188 b4DragOut: function(e) { },
20191 * Abstract method called when we are no longer hovering over an element
20192 * @method onDragOut
20193 * @param {Event} e the mousemove event
20194 * @param {String|DragDrop[]} id In POINT mode, the element
20195 * id this was hovering over. In INTERSECT mode, an array of dd items
20196 * that the mouse is no longer over.
20198 onDragOut: function(e, id) { /* override this */ },
20201 * Code that executes immediately before the onDragDrop event
20202 * @method b4DragDrop
20205 b4DragDrop: function(e) { },
20208 * Abstract method called when this item is dropped on another DragDrop
20210 * @method onDragDrop
20211 * @param {Event} e the mouseup event
20212 * @param {String|DragDrop[]} id In POINT mode, the element
20213 * id this was dropped on. In INTERSECT mode, an array of dd items this
20216 onDragDrop: function(e, id) { /* override this */ },
20219 * Abstract method called when this item is dropped on an area with no
20221 * @method onInvalidDrop
20222 * @param {Event} e the mouseup event
20224 onInvalidDrop: function(e) { /* override this */ },
20227 * Code that executes immediately before the endDrag event
20228 * @method b4EndDrag
20231 b4EndDrag: function(e) { },
20234 * Fired when we are done dragging the object
20236 * @param {Event} e the mouseup event
20238 endDrag: function(e) { /* override this */ },
20241 * Code executed immediately before the onMouseDown event
20242 * @method b4MouseDown
20243 * @param {Event} e the mousedown event
20246 b4MouseDown: function(e) { },
20249 * Event handler that fires when a drag/drop obj gets a mousedown
20250 * @method onMouseDown
20251 * @param {Event} e the mousedown event
20253 onMouseDown: function(e) { /* override this */ },
20256 * Event handler that fires when a drag/drop obj gets a mouseup
20257 * @method onMouseUp
20258 * @param {Event} e the mouseup event
20260 onMouseUp: function(e) { /* override this */ },
20263 * Override the onAvailable method to do what is needed after the initial
20264 * position was determined.
20265 * @method onAvailable
20267 onAvailable: function () {
20271 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
20274 defaultPadding : {left:0, right:0, top:0, bottom:0},
20277 * Initializes the drag drop object's constraints to restrict movement to a certain element.
20281 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
20282 { dragElId: "existingProxyDiv" });
20283 dd.startDrag = function(){
20284 this.constrainTo("parent-id");
20287 * Or you can initalize it using the {@link Roo.Element} object:
20289 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
20290 startDrag : function(){
20291 this.constrainTo("parent-id");
20295 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
20296 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
20297 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
20298 * an object containing the sides to pad. For example: {right:10, bottom:10}
20299 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
20301 constrainTo : function(constrainTo, pad, inContent){
20302 if(typeof pad == "number"){
20303 pad = {left: pad, right:pad, top:pad, bottom:pad};
20305 pad = pad || this.defaultPadding;
20306 var b = Roo.get(this.getEl()).getBox();
20307 var ce = Roo.get(constrainTo);
20308 var s = ce.getScroll();
20309 var c, cd = ce.dom;
20310 if(cd == document.body){
20311 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
20314 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
20318 var topSpace = b.y - c.y;
20319 var leftSpace = b.x - c.x;
20321 this.resetConstraints();
20322 this.setXConstraint(leftSpace - (pad.left||0), // left
20323 c.width - leftSpace - b.width - (pad.right||0) //right
20325 this.setYConstraint(topSpace - (pad.top||0), //top
20326 c.height - topSpace - b.height - (pad.bottom||0) //bottom
20331 * Returns a reference to the linked element
20333 * @return {HTMLElement} the html element
20335 getEl: function() {
20336 if (!this._domRef) {
20337 this._domRef = Roo.getDom(this.id);
20340 return this._domRef;
20344 * Returns a reference to the actual element to drag. By default this is
20345 * the same as the html element, but it can be assigned to another
20346 * element. An example of this can be found in Roo.dd.DDProxy
20347 * @method getDragEl
20348 * @return {HTMLElement} the html element
20350 getDragEl: function() {
20351 return Roo.getDom(this.dragElId);
20355 * Sets up the DragDrop object. Must be called in the constructor of any
20356 * Roo.dd.DragDrop subclass
20358 * @param id the id of the linked element
20359 * @param {String} sGroup the group of related items
20360 * @param {object} config configuration attributes
20362 init: function(id, sGroup, config) {
20363 this.initTarget(id, sGroup, config);
20364 if (!Roo.isTouch) {
20365 Event.on(this.id, "mousedown", this.handleMouseDown, this);
20367 Event.on(this.id, "touchstart", this.handleMouseDown, this);
20368 // Event.on(this.id, "selectstart", Event.preventDefault);
20372 * Initializes Targeting functionality only... the object does not
20373 * get a mousedown handler.
20374 * @method initTarget
20375 * @param id the id of the linked element
20376 * @param {String} sGroup the group of related items
20377 * @param {object} config configuration attributes
20379 initTarget: function(id, sGroup, config) {
20381 // configuration attributes
20382 this.config = config || {};
20384 // create a local reference to the drag and drop manager
20385 this.DDM = Roo.dd.DDM;
20386 // initialize the groups array
20389 // assume that we have an element reference instead of an id if the
20390 // parameter is not a string
20391 if (typeof id !== "string") {
20398 // add to an interaction group
20399 this.addToGroup((sGroup) ? sGroup : "default");
20401 // We don't want to register this as the handle with the manager
20402 // so we just set the id rather than calling the setter.
20403 this.handleElId = id;
20405 // the linked element is the element that gets dragged by default
20406 this.setDragElId(id);
20408 // by default, clicked anchors will not start drag operations.
20409 this.invalidHandleTypes = { A: "A" };
20410 this.invalidHandleIds = {};
20411 this.invalidHandleClasses = [];
20413 this.applyConfig();
20415 this.handleOnAvailable();
20419 * Applies the configuration parameters that were passed into the constructor.
20420 * This is supposed to happen at each level through the inheritance chain. So
20421 * a DDProxy implentation will execute apply config on DDProxy, DD, and
20422 * DragDrop in order to get all of the parameters that are available in
20424 * @method applyConfig
20426 applyConfig: function() {
20428 // configurable properties:
20429 // padding, isTarget, maintainOffset, primaryButtonOnly
20430 this.padding = this.config.padding || [0, 0, 0, 0];
20431 this.isTarget = (this.config.isTarget !== false);
20432 this.maintainOffset = (this.config.maintainOffset);
20433 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
20438 * Executed when the linked element is available
20439 * @method handleOnAvailable
20442 handleOnAvailable: function() {
20443 this.available = true;
20444 this.resetConstraints();
20445 this.onAvailable();
20449 * Configures the padding for the target zone in px. Effectively expands
20450 * (or reduces) the virtual object size for targeting calculations.
20451 * Supports css-style shorthand; if only one parameter is passed, all sides
20452 * will have that padding, and if only two are passed, the top and bottom
20453 * will have the first param, the left and right the second.
20454 * @method setPadding
20455 * @param {int} iTop Top pad
20456 * @param {int} iRight Right pad
20457 * @param {int} iBot Bot pad
20458 * @param {int} iLeft Left pad
20460 setPadding: function(iTop, iRight, iBot, iLeft) {
20461 // this.padding = [iLeft, iRight, iTop, iBot];
20462 if (!iRight && 0 !== iRight) {
20463 this.padding = [iTop, iTop, iTop, iTop];
20464 } else if (!iBot && 0 !== iBot) {
20465 this.padding = [iTop, iRight, iTop, iRight];
20467 this.padding = [iTop, iRight, iBot, iLeft];
20472 * Stores the initial placement of the linked element.
20473 * @method setInitialPosition
20474 * @param {int} diffX the X offset, default 0
20475 * @param {int} diffY the Y offset, default 0
20477 setInitPosition: function(diffX, diffY) {
20478 var el = this.getEl();
20480 if (!this.DDM.verifyEl(el)) {
20484 var dx = diffX || 0;
20485 var dy = diffY || 0;
20487 var p = Dom.getXY( el );
20489 this.initPageX = p[0] - dx;
20490 this.initPageY = p[1] - dy;
20492 this.lastPageX = p[0];
20493 this.lastPageY = p[1];
20496 this.setStartPosition(p);
20500 * Sets the start position of the element. This is set when the obj
20501 * is initialized, the reset when a drag is started.
20502 * @method setStartPosition
20503 * @param pos current position (from previous lookup)
20506 setStartPosition: function(pos) {
20507 var p = pos || Dom.getXY( this.getEl() );
20508 this.deltaSetXY = null;
20510 this.startPageX = p[0];
20511 this.startPageY = p[1];
20515 * Add this instance to a group of related drag/drop objects. All
20516 * instances belong to at least one group, and can belong to as many
20517 * groups as needed.
20518 * @method addToGroup
20519 * @param sGroup {string} the name of the group
20521 addToGroup: function(sGroup) {
20522 this.groups[sGroup] = true;
20523 this.DDM.regDragDrop(this, sGroup);
20527 * Remove's this instance from the supplied interaction group
20528 * @method removeFromGroup
20529 * @param {string} sGroup The group to drop
20531 removeFromGroup: function(sGroup) {
20532 if (this.groups[sGroup]) {
20533 delete this.groups[sGroup];
20536 this.DDM.removeDDFromGroup(this, sGroup);
20540 * Allows you to specify that an element other than the linked element
20541 * will be moved with the cursor during a drag
20542 * @method setDragElId
20543 * @param id {string} the id of the element that will be used to initiate the drag
20545 setDragElId: function(id) {
20546 this.dragElId = id;
20550 * Allows you to specify a child of the linked element that should be
20551 * used to initiate the drag operation. An example of this would be if
20552 * you have a content div with text and links. Clicking anywhere in the
20553 * content area would normally start the drag operation. Use this method
20554 * to specify that an element inside of the content div is the element
20555 * that starts the drag operation.
20556 * @method setHandleElId
20557 * @param id {string} the id of the element that will be used to
20558 * initiate the drag.
20560 setHandleElId: function(id) {
20561 if (typeof id !== "string") {
20564 this.handleElId = id;
20565 this.DDM.regHandle(this.id, id);
20569 * Allows you to set an element outside of the linked element as a drag
20571 * @method setOuterHandleElId
20572 * @param id the id of the element that will be used to initiate the drag
20574 setOuterHandleElId: function(id) {
20575 if (typeof id !== "string") {
20578 Event.on(id, "mousedown",
20579 this.handleMouseDown, this);
20580 this.setHandleElId(id);
20582 this.hasOuterHandles = true;
20586 * Remove all drag and drop hooks for this element
20589 unreg: function() {
20590 Event.un(this.id, "mousedown",
20591 this.handleMouseDown);
20592 Event.un(this.id, "touchstart",
20593 this.handleMouseDown);
20594 this._domRef = null;
20595 this.DDM._remove(this);
20598 destroy : function(){
20603 * Returns true if this instance is locked, or the drag drop mgr is locked
20604 * (meaning that all drag/drop is disabled on the page.)
20606 * @return {boolean} true if this obj or all drag/drop is locked, else
20609 isLocked: function() {
20610 return (this.DDM.isLocked() || this.locked);
20614 * Fired when this object is clicked
20615 * @method handleMouseDown
20617 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
20620 handleMouseDown: function(e, oDD){
20622 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
20623 //Roo.log('not touch/ button !=0');
20626 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
20627 return; // double touch..
20631 if (this.isLocked()) {
20632 //Roo.log('locked');
20636 this.DDM.refreshCache(this.groups);
20637 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
20638 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
20639 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
20640 //Roo.log('no outer handes or not over target');
20643 // Roo.log('check validator');
20644 if (this.clickValidator(e)) {
20645 // Roo.log('validate success');
20646 // set the initial element position
20647 this.setStartPosition();
20650 this.b4MouseDown(e);
20651 this.onMouseDown(e);
20653 this.DDM.handleMouseDown(e, this);
20655 this.DDM.stopEvent(e);
20663 clickValidator: function(e) {
20664 var target = e.getTarget();
20665 return ( this.isValidHandleChild(target) &&
20666 (this.id == this.handleElId ||
20667 this.DDM.handleWasClicked(target, this.id)) );
20671 * Allows you to specify a tag name that should not start a drag operation
20672 * when clicked. This is designed to facilitate embedding links within a
20673 * drag handle that do something other than start the drag.
20674 * @method addInvalidHandleType
20675 * @param {string} tagName the type of element to exclude
20677 addInvalidHandleType: function(tagName) {
20678 var type = tagName.toUpperCase();
20679 this.invalidHandleTypes[type] = type;
20683 * Lets you to specify an element id for a child of a drag handle
20684 * that should not initiate a drag
20685 * @method addInvalidHandleId
20686 * @param {string} id the element id of the element you wish to ignore
20688 addInvalidHandleId: function(id) {
20689 if (typeof id !== "string") {
20692 this.invalidHandleIds[id] = id;
20696 * Lets you specify a css class of elements that will not initiate a drag
20697 * @method addInvalidHandleClass
20698 * @param {string} cssClass the class of the elements you wish to ignore
20700 addInvalidHandleClass: function(cssClass) {
20701 this.invalidHandleClasses.push(cssClass);
20705 * Unsets an excluded tag name set by addInvalidHandleType
20706 * @method removeInvalidHandleType
20707 * @param {string} tagName the type of element to unexclude
20709 removeInvalidHandleType: function(tagName) {
20710 var type = tagName.toUpperCase();
20711 // this.invalidHandleTypes[type] = null;
20712 delete this.invalidHandleTypes[type];
20716 * Unsets an invalid handle id
20717 * @method removeInvalidHandleId
20718 * @param {string} id the id of the element to re-enable
20720 removeInvalidHandleId: function(id) {
20721 if (typeof id !== "string") {
20724 delete this.invalidHandleIds[id];
20728 * Unsets an invalid css class
20729 * @method removeInvalidHandleClass
20730 * @param {string} cssClass the class of the element(s) you wish to
20733 removeInvalidHandleClass: function(cssClass) {
20734 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
20735 if (this.invalidHandleClasses[i] == cssClass) {
20736 delete this.invalidHandleClasses[i];
20742 * Checks the tag exclusion list to see if this click should be ignored
20743 * @method isValidHandleChild
20744 * @param {HTMLElement} node the HTMLElement to evaluate
20745 * @return {boolean} true if this is a valid tag type, false if not
20747 isValidHandleChild: function(node) {
20750 // var n = (node.nodeName == "#text") ? node.parentNode : node;
20753 nodeName = node.nodeName.toUpperCase();
20755 nodeName = node.nodeName;
20757 valid = valid && !this.invalidHandleTypes[nodeName];
20758 valid = valid && !this.invalidHandleIds[node.id];
20760 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
20761 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
20770 * Create the array of horizontal tick marks if an interval was specified
20771 * in setXConstraint().
20772 * @method setXTicks
20775 setXTicks: function(iStartX, iTickSize) {
20777 this.xTickSize = iTickSize;
20781 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
20783 this.xTicks[this.xTicks.length] = i;
20788 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
20790 this.xTicks[this.xTicks.length] = i;
20795 this.xTicks.sort(this.DDM.numericSort) ;
20799 * Create the array of vertical tick marks if an interval was specified in
20800 * setYConstraint().
20801 * @method setYTicks
20804 setYTicks: function(iStartY, iTickSize) {
20806 this.yTickSize = iTickSize;
20810 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
20812 this.yTicks[this.yTicks.length] = i;
20817 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
20819 this.yTicks[this.yTicks.length] = i;
20824 this.yTicks.sort(this.DDM.numericSort) ;
20828 * By default, the element can be dragged any place on the screen. Use
20829 * this method to limit the horizontal travel of the element. Pass in
20830 * 0,0 for the parameters if you want to lock the drag to the y axis.
20831 * @method setXConstraint
20832 * @param {int} iLeft the number of pixels the element can move to the left
20833 * @param {int} iRight the number of pixels the element can move to the
20835 * @param {int} iTickSize optional parameter for specifying that the
20837 * should move iTickSize pixels at a time.
20839 setXConstraint: function(iLeft, iRight, iTickSize) {
20840 this.leftConstraint = iLeft;
20841 this.rightConstraint = iRight;
20843 this.minX = this.initPageX - iLeft;
20844 this.maxX = this.initPageX + iRight;
20845 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
20847 this.constrainX = true;
20851 * Clears any constraints applied to this instance. Also clears ticks
20852 * since they can't exist independent of a constraint at this time.
20853 * @method clearConstraints
20855 clearConstraints: function() {
20856 this.constrainX = false;
20857 this.constrainY = false;
20862 * Clears any tick interval defined for this instance
20863 * @method clearTicks
20865 clearTicks: function() {
20866 this.xTicks = null;
20867 this.yTicks = null;
20868 this.xTickSize = 0;
20869 this.yTickSize = 0;
20873 * By default, the element can be dragged any place on the screen. Set
20874 * this to limit the vertical travel of the element. Pass in 0,0 for the
20875 * parameters if you want to lock the drag to the x axis.
20876 * @method setYConstraint
20877 * @param {int} iUp the number of pixels the element can move up
20878 * @param {int} iDown the number of pixels the element can move down
20879 * @param {int} iTickSize optional parameter for specifying that the
20880 * element should move iTickSize pixels at a time.
20882 setYConstraint: function(iUp, iDown, iTickSize) {
20883 this.topConstraint = iUp;
20884 this.bottomConstraint = iDown;
20886 this.minY = this.initPageY - iUp;
20887 this.maxY = this.initPageY + iDown;
20888 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
20890 this.constrainY = true;
20895 * resetConstraints must be called if you manually reposition a dd element.
20896 * @method resetConstraints
20897 * @param {boolean} maintainOffset
20899 resetConstraints: function() {
20902 // Maintain offsets if necessary
20903 if (this.initPageX || this.initPageX === 0) {
20904 // figure out how much this thing has moved
20905 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
20906 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
20908 this.setInitPosition(dx, dy);
20910 // This is the first time we have detected the element's position
20912 this.setInitPosition();
20915 if (this.constrainX) {
20916 this.setXConstraint( this.leftConstraint,
20917 this.rightConstraint,
20921 if (this.constrainY) {
20922 this.setYConstraint( this.topConstraint,
20923 this.bottomConstraint,
20929 * Normally the drag element is moved pixel by pixel, but we can specify
20930 * that it move a number of pixels at a time. This method resolves the
20931 * location when we have it set up like this.
20933 * @param {int} val where we want to place the object
20934 * @param {int[]} tickArray sorted array of valid points
20935 * @return {int} the closest tick
20938 getTick: function(val, tickArray) {
20941 // If tick interval is not defined, it is effectively 1 pixel,
20942 // so we return the value passed to us.
20944 } else if (tickArray[0] >= val) {
20945 // The value is lower than the first tick, so we return the first
20947 return tickArray[0];
20949 for (var i=0, len=tickArray.length; i<len; ++i) {
20951 if (tickArray[next] && tickArray[next] >= val) {
20952 var diff1 = val - tickArray[i];
20953 var diff2 = tickArray[next] - val;
20954 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
20958 // The value is larger than the last tick, so we return the last
20960 return tickArray[tickArray.length - 1];
20967 * @return {string} string representation of the dd obj
20969 toString: function() {
20970 return ("DragDrop " + this.id);
20978 * Ext JS Library 1.1.1
20979 * Copyright(c) 2006-2007, Ext JS, LLC.
20981 * Originally Released Under LGPL - original licence link has changed is not relivant.
20984 * <script type="text/javascript">
20989 * The drag and drop utility provides a framework for building drag and drop
20990 * applications. In addition to enabling drag and drop for specific elements,
20991 * the drag and drop elements are tracked by the manager class, and the
20992 * interactions between the various elements are tracked during the drag and
20993 * the implementing code is notified about these important moments.
20996 // Only load the library once. Rewriting the manager class would orphan
20997 // existing drag and drop instances.
20998 if (!Roo.dd.DragDropMgr) {
21001 * @class Roo.dd.DragDropMgr
21002 * DragDropMgr is a singleton that tracks the element interaction for
21003 * all DragDrop items in the window. Generally, you will not call
21004 * this class directly, but it does have helper methods that could
21005 * be useful in your DragDrop implementations.
21008 Roo.dd.DragDropMgr = function() {
21010 var Event = Roo.EventManager;
21015 * Two dimensional Array of registered DragDrop objects. The first
21016 * dimension is the DragDrop item group, the second the DragDrop
21019 * @type {string: string}
21026 * Array of element ids defined as drag handles. Used to determine
21027 * if the element that generated the mousedown event is actually the
21028 * handle and not the html element itself.
21029 * @property handleIds
21030 * @type {string: string}
21037 * the DragDrop object that is currently being dragged
21038 * @property dragCurrent
21046 * the DragDrop object(s) that are being hovered over
21047 * @property dragOvers
21055 * the X distance between the cursor and the object being dragged
21064 * the Y distance between the cursor and the object being dragged
21073 * Flag to determine if we should prevent the default behavior of the
21074 * events we define. By default this is true, but this can be set to
21075 * false if you need the default behavior (not recommended)
21076 * @property preventDefault
21080 preventDefault: true,
21083 * Flag to determine if we should stop the propagation of the events
21084 * we generate. This is true by default but you may want to set it to
21085 * false if the html element contains other features that require the
21087 * @property stopPropagation
21091 stopPropagation: true,
21094 * Internal flag that is set to true when drag and drop has been
21096 * @property initialized
21103 * All drag and drop can be disabled.
21111 * Called the first time an element is registered.
21117 this.initialized = true;
21121 * In point mode, drag and drop interaction is defined by the
21122 * location of the cursor during the drag/drop
21130 * In intersect mode, drag and drop interactio nis defined by the
21131 * overlap of two or more drag and drop objects.
21132 * @property INTERSECT
21139 * The current drag and drop mode. Default: POINT
21147 * Runs method on all drag and drop objects
21148 * @method _execOnAll
21152 _execOnAll: function(sMethod, args) {
21153 for (var i in this.ids) {
21154 for (var j in this.ids[i]) {
21155 var oDD = this.ids[i][j];
21156 if (! this.isTypeOfDD(oDD)) {
21159 oDD[sMethod].apply(oDD, args);
21165 * Drag and drop initialization. Sets up the global event handlers
21170 _onLoad: function() {
21174 if (!Roo.isTouch) {
21175 Event.on(document, "mouseup", this.handleMouseUp, this, true);
21176 Event.on(document, "mousemove", this.handleMouseMove, this, true);
21178 Event.on(document, "touchend", this.handleMouseUp, this, true);
21179 Event.on(document, "touchmove", this.handleMouseMove, this, true);
21181 Event.on(window, "unload", this._onUnload, this, true);
21182 Event.on(window, "resize", this._onResize, this, true);
21183 // Event.on(window, "mouseout", this._test);
21188 * Reset constraints on all drag and drop objs
21189 * @method _onResize
21193 _onResize: function(e) {
21194 this._execOnAll("resetConstraints", []);
21198 * Lock all drag and drop functionality
21202 lock: function() { this.locked = true; },
21205 * Unlock all drag and drop functionality
21209 unlock: function() { this.locked = false; },
21212 * Is drag and drop locked?
21214 * @return {boolean} True if drag and drop is locked, false otherwise.
21217 isLocked: function() { return this.locked; },
21220 * Location cache that is set for all drag drop objects when a drag is
21221 * initiated, cleared when the drag is finished.
21222 * @property locationCache
21229 * Set useCache to false if you want to force object the lookup of each
21230 * drag and drop linked element constantly during a drag.
21231 * @property useCache
21238 * The number of pixels that the mouse needs to move after the
21239 * mousedown before the drag is initiated. Default=3;
21240 * @property clickPixelThresh
21244 clickPixelThresh: 3,
21247 * The number of milliseconds after the mousedown event to initiate the
21248 * drag if we don't get a mouseup event. Default=1000
21249 * @property clickTimeThresh
21253 clickTimeThresh: 350,
21256 * Flag that indicates that either the drag pixel threshold or the
21257 * mousdown time threshold has been met
21258 * @property dragThreshMet
21263 dragThreshMet: false,
21266 * Timeout used for the click time threshold
21267 * @property clickTimeout
21272 clickTimeout: null,
21275 * The X position of the mousedown event stored for later use when a
21276 * drag threshold is met.
21285 * The Y position of the mousedown event stored for later use when a
21286 * drag threshold is met.
21295 * Each DragDrop instance must be registered with the DragDropMgr.
21296 * This is executed in DragDrop.init()
21297 * @method regDragDrop
21298 * @param {DragDrop} oDD the DragDrop object to register
21299 * @param {String} sGroup the name of the group this element belongs to
21302 regDragDrop: function(oDD, sGroup) {
21303 if (!this.initialized) { this.init(); }
21305 if (!this.ids[sGroup]) {
21306 this.ids[sGroup] = {};
21308 this.ids[sGroup][oDD.id] = oDD;
21312 * Removes the supplied dd instance from the supplied group. Executed
21313 * by DragDrop.removeFromGroup, so don't call this function directly.
21314 * @method removeDDFromGroup
21318 removeDDFromGroup: function(oDD, sGroup) {
21319 if (!this.ids[sGroup]) {
21320 this.ids[sGroup] = {};
21323 var obj = this.ids[sGroup];
21324 if (obj && obj[oDD.id]) {
21325 delete obj[oDD.id];
21330 * Unregisters a drag and drop item. This is executed in
21331 * DragDrop.unreg, use that method instead of calling this directly.
21336 _remove: function(oDD) {
21337 for (var g in oDD.groups) {
21338 if (g && this.ids[g][oDD.id]) {
21339 delete this.ids[g][oDD.id];
21342 delete this.handleIds[oDD.id];
21346 * Each DragDrop handle element must be registered. This is done
21347 * automatically when executing DragDrop.setHandleElId()
21348 * @method regHandle
21349 * @param {String} sDDId the DragDrop id this element is a handle for
21350 * @param {String} sHandleId the id of the element that is the drag
21354 regHandle: function(sDDId, sHandleId) {
21355 if (!this.handleIds[sDDId]) {
21356 this.handleIds[sDDId] = {};
21358 this.handleIds[sDDId][sHandleId] = sHandleId;
21362 * Utility function to determine if a given element has been
21363 * registered as a drag drop item.
21364 * @method isDragDrop
21365 * @param {String} id the element id to check
21366 * @return {boolean} true if this element is a DragDrop item,
21370 isDragDrop: function(id) {
21371 return ( this.getDDById(id) ) ? true : false;
21375 * Returns the drag and drop instances that are in all groups the
21376 * passed in instance belongs to.
21377 * @method getRelated
21378 * @param {DragDrop} p_oDD the obj to get related data for
21379 * @param {boolean} bTargetsOnly if true, only return targetable objs
21380 * @return {DragDrop[]} the related instances
21383 getRelated: function(p_oDD, bTargetsOnly) {
21385 for (var i in p_oDD.groups) {
21386 for (j in this.ids[i]) {
21387 var dd = this.ids[i][j];
21388 if (! this.isTypeOfDD(dd)) {
21391 if (!bTargetsOnly || dd.isTarget) {
21392 oDDs[oDDs.length] = dd;
21401 * Returns true if the specified dd target is a legal target for
21402 * the specifice drag obj
21403 * @method isLegalTarget
21404 * @param {DragDrop} the drag obj
21405 * @param {DragDrop} the target
21406 * @return {boolean} true if the target is a legal target for the
21410 isLegalTarget: function (oDD, oTargetDD) {
21411 var targets = this.getRelated(oDD, true);
21412 for (var i=0, len=targets.length;i<len;++i) {
21413 if (targets[i].id == oTargetDD.id) {
21422 * My goal is to be able to transparently determine if an object is
21423 * typeof DragDrop, and the exact subclass of DragDrop. typeof
21424 * returns "object", oDD.constructor.toString() always returns
21425 * "DragDrop" and not the name of the subclass. So for now it just
21426 * evaluates a well-known variable in DragDrop.
21427 * @method isTypeOfDD
21428 * @param {Object} the object to evaluate
21429 * @return {boolean} true if typeof oDD = DragDrop
21432 isTypeOfDD: function (oDD) {
21433 return (oDD && oDD.__ygDragDrop);
21437 * Utility function to determine if a given element has been
21438 * registered as a drag drop handle for the given Drag Drop object.
21440 * @param {String} id the element id to check
21441 * @return {boolean} true if this element is a DragDrop handle, false
21445 isHandle: function(sDDId, sHandleId) {
21446 return ( this.handleIds[sDDId] &&
21447 this.handleIds[sDDId][sHandleId] );
21451 * Returns the DragDrop instance for a given id
21452 * @method getDDById
21453 * @param {String} id the id of the DragDrop object
21454 * @return {DragDrop} the drag drop object, null if it is not found
21457 getDDById: function(id) {
21458 for (var i in this.ids) {
21459 if (this.ids[i][id]) {
21460 return this.ids[i][id];
21467 * Fired after a registered DragDrop object gets the mousedown event.
21468 * Sets up the events required to track the object being dragged
21469 * @method handleMouseDown
21470 * @param {Event} e the event
21471 * @param oDD the DragDrop object being dragged
21475 handleMouseDown: function(e, oDD) {
21477 Roo.QuickTips.disable();
21479 this.currentTarget = e.getTarget();
21481 this.dragCurrent = oDD;
21483 var el = oDD.getEl();
21485 // track start position
21486 this.startX = e.getPageX();
21487 this.startY = e.getPageY();
21489 this.deltaX = this.startX - el.offsetLeft;
21490 this.deltaY = this.startY - el.offsetTop;
21492 this.dragThreshMet = false;
21494 this.clickTimeout = setTimeout(
21496 var DDM = Roo.dd.DDM;
21497 DDM.startDrag(DDM.startX, DDM.startY);
21499 this.clickTimeThresh );
21503 * Fired when either the drag pixel threshol or the mousedown hold
21504 * time threshold has been met.
21505 * @method startDrag
21506 * @param x {int} the X position of the original mousedown
21507 * @param y {int} the Y position of the original mousedown
21510 startDrag: function(x, y) {
21511 clearTimeout(this.clickTimeout);
21512 if (this.dragCurrent) {
21513 this.dragCurrent.b4StartDrag(x, y);
21514 this.dragCurrent.startDrag(x, y);
21516 this.dragThreshMet = true;
21520 * Internal function to handle the mouseup event. Will be invoked
21521 * from the context of the document.
21522 * @method handleMouseUp
21523 * @param {Event} e the event
21527 handleMouseUp: function(e) {
21530 Roo.QuickTips.enable();
21532 if (! this.dragCurrent) {
21536 clearTimeout(this.clickTimeout);
21538 if (this.dragThreshMet) {
21539 this.fireEvents(e, true);
21549 * Utility to stop event propagation and event default, if these
21550 * features are turned on.
21551 * @method stopEvent
21552 * @param {Event} e the event as returned by this.getEvent()
21555 stopEvent: function(e){
21556 if(this.stopPropagation) {
21557 e.stopPropagation();
21560 if (this.preventDefault) {
21561 e.preventDefault();
21566 * Internal function to clean up event handlers after the drag
21567 * operation is complete
21569 * @param {Event} e the event
21573 stopDrag: function(e) {
21574 // Fire the drag end event for the item that was dragged
21575 if (this.dragCurrent) {
21576 if (this.dragThreshMet) {
21577 this.dragCurrent.b4EndDrag(e);
21578 this.dragCurrent.endDrag(e);
21581 this.dragCurrent.onMouseUp(e);
21584 this.dragCurrent = null;
21585 this.dragOvers = {};
21589 * Internal function to handle the mousemove event. Will be invoked
21590 * from the context of the html element.
21592 * @TODO figure out what we can do about mouse events lost when the
21593 * user drags objects beyond the window boundary. Currently we can
21594 * detect this in internet explorer by verifying that the mouse is
21595 * down during the mousemove event. Firefox doesn't give us the
21596 * button state on the mousemove event.
21597 * @method handleMouseMove
21598 * @param {Event} e the event
21602 handleMouseMove: function(e) {
21603 if (! this.dragCurrent) {
21607 // var button = e.which || e.button;
21609 // check for IE mouseup outside of page boundary
21610 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
21612 return this.handleMouseUp(e);
21615 if (!this.dragThreshMet) {
21616 var diffX = Math.abs(this.startX - e.getPageX());
21617 var diffY = Math.abs(this.startY - e.getPageY());
21618 if (diffX > this.clickPixelThresh ||
21619 diffY > this.clickPixelThresh) {
21620 this.startDrag(this.startX, this.startY);
21624 if (this.dragThreshMet) {
21625 this.dragCurrent.b4Drag(e);
21626 this.dragCurrent.onDrag(e);
21627 if(!this.dragCurrent.moveOnly){
21628 this.fireEvents(e, false);
21638 * Iterates over all of the DragDrop elements to find ones we are
21639 * hovering over or dropping on
21640 * @method fireEvents
21641 * @param {Event} e the event
21642 * @param {boolean} isDrop is this a drop op or a mouseover op?
21646 fireEvents: function(e, isDrop) {
21647 var dc = this.dragCurrent;
21649 // If the user did the mouse up outside of the window, we could
21650 // get here even though we have ended the drag.
21651 if (!dc || dc.isLocked()) {
21655 var pt = e.getPoint();
21657 // cache the previous dragOver array
21663 var enterEvts = [];
21665 // Check to see if the object(s) we were hovering over is no longer
21666 // being hovered over so we can fire the onDragOut event
21667 for (var i in this.dragOvers) {
21669 var ddo = this.dragOvers[i];
21671 if (! this.isTypeOfDD(ddo)) {
21675 if (! this.isOverTarget(pt, ddo, this.mode)) {
21676 outEvts.push( ddo );
21679 oldOvers[i] = true;
21680 delete this.dragOvers[i];
21683 for (var sGroup in dc.groups) {
21685 if ("string" != typeof sGroup) {
21689 for (i in this.ids[sGroup]) {
21690 var oDD = this.ids[sGroup][i];
21691 if (! this.isTypeOfDD(oDD)) {
21695 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
21696 if (this.isOverTarget(pt, oDD, this.mode)) {
21697 // look for drop interactions
21699 dropEvts.push( oDD );
21700 // look for drag enter and drag over interactions
21703 // initial drag over: dragEnter fires
21704 if (!oldOvers[oDD.id]) {
21705 enterEvts.push( oDD );
21706 // subsequent drag overs: dragOver fires
21708 overEvts.push( oDD );
21711 this.dragOvers[oDD.id] = oDD;
21719 if (outEvts.length) {
21720 dc.b4DragOut(e, outEvts);
21721 dc.onDragOut(e, outEvts);
21724 if (enterEvts.length) {
21725 dc.onDragEnter(e, enterEvts);
21728 if (overEvts.length) {
21729 dc.b4DragOver(e, overEvts);
21730 dc.onDragOver(e, overEvts);
21733 if (dropEvts.length) {
21734 dc.b4DragDrop(e, dropEvts);
21735 dc.onDragDrop(e, dropEvts);
21739 // fire dragout events
21741 for (i=0, len=outEvts.length; i<len; ++i) {
21742 dc.b4DragOut(e, outEvts[i].id);
21743 dc.onDragOut(e, outEvts[i].id);
21746 // fire enter events
21747 for (i=0,len=enterEvts.length; i<len; ++i) {
21748 // dc.b4DragEnter(e, oDD.id);
21749 dc.onDragEnter(e, enterEvts[i].id);
21752 // fire over events
21753 for (i=0,len=overEvts.length; i<len; ++i) {
21754 dc.b4DragOver(e, overEvts[i].id);
21755 dc.onDragOver(e, overEvts[i].id);
21758 // fire drop events
21759 for (i=0, len=dropEvts.length; i<len; ++i) {
21760 dc.b4DragDrop(e, dropEvts[i].id);
21761 dc.onDragDrop(e, dropEvts[i].id);
21766 // notify about a drop that did not find a target
21767 if (isDrop && !dropEvts.length) {
21768 dc.onInvalidDrop(e);
21774 * Helper function for getting the best match from the list of drag
21775 * and drop objects returned by the drag and drop events when we are
21776 * in INTERSECT mode. It returns either the first object that the
21777 * cursor is over, or the object that has the greatest overlap with
21778 * the dragged element.
21779 * @method getBestMatch
21780 * @param {DragDrop[]} dds The array of drag and drop objects
21782 * @return {DragDrop} The best single match
21785 getBestMatch: function(dds) {
21787 // Return null if the input is not what we expect
21788 //if (!dds || !dds.length || dds.length == 0) {
21790 // If there is only one item, it wins
21791 //} else if (dds.length == 1) {
21793 var len = dds.length;
21798 // Loop through the targeted items
21799 for (var i=0; i<len; ++i) {
21801 // If the cursor is over the object, it wins. If the
21802 // cursor is over multiple matches, the first one we come
21804 if (dd.cursorIsOver) {
21807 // Otherwise the object with the most overlap wins
21810 winner.overlap.getArea() < dd.overlap.getArea()) {
21821 * Refreshes the cache of the top-left and bottom-right points of the
21822 * drag and drop objects in the specified group(s). This is in the
21823 * format that is stored in the drag and drop instance, so typical
21826 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
21830 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
21832 * @TODO this really should be an indexed array. Alternatively this
21833 * method could accept both.
21834 * @method refreshCache
21835 * @param {Object} groups an associative array of groups to refresh
21838 refreshCache: function(groups) {
21839 for (var sGroup in groups) {
21840 if ("string" != typeof sGroup) {
21843 for (var i in this.ids[sGroup]) {
21844 var oDD = this.ids[sGroup][i];
21846 if (this.isTypeOfDD(oDD)) {
21847 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
21848 var loc = this.getLocation(oDD);
21850 this.locationCache[oDD.id] = loc;
21852 delete this.locationCache[oDD.id];
21853 // this will unregister the drag and drop object if
21854 // the element is not in a usable state
21863 * This checks to make sure an element exists and is in the DOM. The
21864 * main purpose is to handle cases where innerHTML is used to remove
21865 * drag and drop objects from the DOM. IE provides an 'unspecified
21866 * error' when trying to access the offsetParent of such an element
21868 * @param {HTMLElement} el the element to check
21869 * @return {boolean} true if the element looks usable
21872 verifyEl: function(el) {
21877 parent = el.offsetParent;
21880 parent = el.offsetParent;
21891 * Returns a Region object containing the drag and drop element's position
21892 * and size, including the padding configured for it
21893 * @method getLocation
21894 * @param {DragDrop} oDD the drag and drop object to get the
21896 * @return {Roo.lib.Region} a Region object representing the total area
21897 * the element occupies, including any padding
21898 * the instance is configured for.
21901 getLocation: function(oDD) {
21902 if (! this.isTypeOfDD(oDD)) {
21906 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
21909 pos= Roo.lib.Dom.getXY(el);
21917 x2 = x1 + el.offsetWidth;
21919 y2 = y1 + el.offsetHeight;
21921 t = y1 - oDD.padding[0];
21922 r = x2 + oDD.padding[1];
21923 b = y2 + oDD.padding[2];
21924 l = x1 - oDD.padding[3];
21926 return new Roo.lib.Region( t, r, b, l );
21930 * Checks the cursor location to see if it over the target
21931 * @method isOverTarget
21932 * @param {Roo.lib.Point} pt The point to evaluate
21933 * @param {DragDrop} oTarget the DragDrop object we are inspecting
21934 * @return {boolean} true if the mouse is over the target
21938 isOverTarget: function(pt, oTarget, intersect) {
21939 // use cache if available
21940 var loc = this.locationCache[oTarget.id];
21941 if (!loc || !this.useCache) {
21942 loc = this.getLocation(oTarget);
21943 this.locationCache[oTarget.id] = loc;
21951 oTarget.cursorIsOver = loc.contains( pt );
21953 // DragDrop is using this as a sanity check for the initial mousedown
21954 // in this case we are done. In POINT mode, if the drag obj has no
21955 // contraints, we are also done. Otherwise we need to evaluate the
21956 // location of the target as related to the actual location of the
21957 // dragged element.
21958 var dc = this.dragCurrent;
21959 if (!dc || !dc.getTargetCoord ||
21960 (!intersect && !dc.constrainX && !dc.constrainY)) {
21961 return oTarget.cursorIsOver;
21964 oTarget.overlap = null;
21966 // Get the current location of the drag element, this is the
21967 // location of the mouse event less the delta that represents
21968 // where the original mousedown happened on the element. We
21969 // need to consider constraints and ticks as well.
21970 var pos = dc.getTargetCoord(pt.x, pt.y);
21972 var el = dc.getDragEl();
21973 var curRegion = new Roo.lib.Region( pos.y,
21974 pos.x + el.offsetWidth,
21975 pos.y + el.offsetHeight,
21978 var overlap = curRegion.intersect(loc);
21981 oTarget.overlap = overlap;
21982 return (intersect) ? true : oTarget.cursorIsOver;
21989 * unload event handler
21990 * @method _onUnload
21994 _onUnload: function(e, me) {
21995 Roo.dd.DragDropMgr.unregAll();
21999 * Cleans up the drag and drop events and objects.
22004 unregAll: function() {
22006 if (this.dragCurrent) {
22008 this.dragCurrent = null;
22011 this._execOnAll("unreg", []);
22013 for (i in this.elementCache) {
22014 delete this.elementCache[i];
22017 this.elementCache = {};
22022 * A cache of DOM elements
22023 * @property elementCache
22030 * Get the wrapper for the DOM element specified
22031 * @method getElWrapper
22032 * @param {String} id the id of the element to get
22033 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
22035 * @deprecated This wrapper isn't that useful
22038 getElWrapper: function(id) {
22039 var oWrapper = this.elementCache[id];
22040 if (!oWrapper || !oWrapper.el) {
22041 oWrapper = this.elementCache[id] =
22042 new this.ElementWrapper(Roo.getDom(id));
22048 * Returns the actual DOM element
22049 * @method getElement
22050 * @param {String} id the id of the elment to get
22051 * @return {Object} The element
22052 * @deprecated use Roo.getDom instead
22055 getElement: function(id) {
22056 return Roo.getDom(id);
22060 * Returns the style property for the DOM element (i.e.,
22061 * document.getElById(id).style)
22063 * @param {String} id the id of the elment to get
22064 * @return {Object} The style property of the element
22065 * @deprecated use Roo.getDom instead
22068 getCss: function(id) {
22069 var el = Roo.getDom(id);
22070 return (el) ? el.style : null;
22074 * Inner class for cached elements
22075 * @class DragDropMgr.ElementWrapper
22080 ElementWrapper: function(el) {
22085 this.el = el || null;
22090 this.id = this.el && el.id;
22092 * A reference to the style property
22095 this.css = this.el && el.style;
22099 * Returns the X position of an html element
22101 * @param el the element for which to get the position
22102 * @return {int} the X coordinate
22104 * @deprecated use Roo.lib.Dom.getX instead
22107 getPosX: function(el) {
22108 return Roo.lib.Dom.getX(el);
22112 * Returns the Y position of an html element
22114 * @param el the element for which to get the position
22115 * @return {int} the Y coordinate
22116 * @deprecated use Roo.lib.Dom.getY instead
22119 getPosY: function(el) {
22120 return Roo.lib.Dom.getY(el);
22124 * Swap two nodes. In IE, we use the native method, for others we
22125 * emulate the IE behavior
22127 * @param n1 the first node to swap
22128 * @param n2 the other node to swap
22131 swapNode: function(n1, n2) {
22135 var p = n2.parentNode;
22136 var s = n2.nextSibling;
22139 p.insertBefore(n1, n2);
22140 } else if (n2 == n1.nextSibling) {
22141 p.insertBefore(n2, n1);
22143 n1.parentNode.replaceChild(n2, n1);
22144 p.insertBefore(n1, s);
22150 * Returns the current scroll position
22151 * @method getScroll
22155 getScroll: function () {
22156 var t, l, dde=document.documentElement, db=document.body;
22157 if (dde && (dde.scrollTop || dde.scrollLeft)) {
22159 l = dde.scrollLeft;
22166 return { top: t, left: l };
22170 * Returns the specified element style property
22172 * @param {HTMLElement} el the element
22173 * @param {string} styleProp the style property
22174 * @return {string} The value of the style property
22175 * @deprecated use Roo.lib.Dom.getStyle
22178 getStyle: function(el, styleProp) {
22179 return Roo.fly(el).getStyle(styleProp);
22183 * Gets the scrollTop
22184 * @method getScrollTop
22185 * @return {int} the document's scrollTop
22188 getScrollTop: function () { return this.getScroll().top; },
22191 * Gets the scrollLeft
22192 * @method getScrollLeft
22193 * @return {int} the document's scrollTop
22196 getScrollLeft: function () { return this.getScroll().left; },
22199 * Sets the x/y position of an element to the location of the
22202 * @param {HTMLElement} moveEl The element to move
22203 * @param {HTMLElement} targetEl The position reference element
22206 moveToEl: function (moveEl, targetEl) {
22207 var aCoord = Roo.lib.Dom.getXY(targetEl);
22208 Roo.lib.Dom.setXY(moveEl, aCoord);
22212 * Numeric array sort function
22213 * @method numericSort
22216 numericSort: function(a, b) { return (a - b); },
22220 * @property _timeoutCount
22227 * Trying to make the load order less important. Without this we get
22228 * an error if this file is loaded before the Event Utility.
22229 * @method _addListeners
22233 _addListeners: function() {
22234 var DDM = Roo.dd.DDM;
22235 if ( Roo.lib.Event && document ) {
22238 if (DDM._timeoutCount > 2000) {
22240 setTimeout(DDM._addListeners, 10);
22241 if (document && document.body) {
22242 DDM._timeoutCount += 1;
22249 * Recursively searches the immediate parent and all child nodes for
22250 * the handle element in order to determine wheter or not it was
22252 * @method handleWasClicked
22253 * @param node the html element to inspect
22256 handleWasClicked: function(node, id) {
22257 if (this.isHandle(id, node.id)) {
22260 // check to see if this is a text node child of the one we want
22261 var p = node.parentNode;
22264 if (this.isHandle(id, p.id)) {
22279 // shorter alias, save a few bytes
22280 Roo.dd.DDM = Roo.dd.DragDropMgr;
22281 Roo.dd.DDM._addListeners();
22285 * Ext JS Library 1.1.1
22286 * Copyright(c) 2006-2007, Ext JS, LLC.
22288 * Originally Released Under LGPL - original licence link has changed is not relivant.
22291 * <script type="text/javascript">
22296 * A DragDrop implementation where the linked element follows the
22297 * mouse cursor during a drag.
22298 * @extends Roo.dd.DragDrop
22300 * @param {String} id the id of the linked element
22301 * @param {String} sGroup the group of related DragDrop items
22302 * @param {object} config an object containing configurable attributes
22303 * Valid properties for DD:
22306 Roo.dd.DD = function(id, sGroup, config) {
22308 this.init(id, sGroup, config);
22312 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
22315 * When set to true, the utility automatically tries to scroll the browser
22316 * window wehn a drag and drop element is dragged near the viewport boundary.
22317 * Defaults to true.
22324 * Sets the pointer offset to the distance between the linked element's top
22325 * left corner and the location the element was clicked
22326 * @method autoOffset
22327 * @param {int} iPageX the X coordinate of the click
22328 * @param {int} iPageY the Y coordinate of the click
22330 autoOffset: function(iPageX, iPageY) {
22331 var x = iPageX - this.startPageX;
22332 var y = iPageY - this.startPageY;
22333 this.setDelta(x, y);
22337 * Sets the pointer offset. You can call this directly to force the
22338 * offset to be in a particular location (e.g., pass in 0,0 to set it
22339 * to the center of the object)
22341 * @param {int} iDeltaX the distance from the left
22342 * @param {int} iDeltaY the distance from the top
22344 setDelta: function(iDeltaX, iDeltaY) {
22345 this.deltaX = iDeltaX;
22346 this.deltaY = iDeltaY;
22350 * Sets the drag element to the location of the mousedown or click event,
22351 * maintaining the cursor location relative to the location on the element
22352 * that was clicked. Override this if you want to place the element in a
22353 * location other than where the cursor is.
22354 * @method setDragElPos
22355 * @param {int} iPageX the X coordinate of the mousedown or drag event
22356 * @param {int} iPageY the Y coordinate of the mousedown or drag event
22358 setDragElPos: function(iPageX, iPageY) {
22359 // the first time we do this, we are going to check to make sure
22360 // the element has css positioning
22362 var el = this.getDragEl();
22363 this.alignElWithMouse(el, iPageX, iPageY);
22367 * Sets the element to the location of the mousedown or click event,
22368 * maintaining the cursor location relative to the location on the element
22369 * that was clicked. Override this if you want to place the element in a
22370 * location other than where the cursor is.
22371 * @method alignElWithMouse
22372 * @param {HTMLElement} el the element to move
22373 * @param {int} iPageX the X coordinate of the mousedown or drag event
22374 * @param {int} iPageY the Y coordinate of the mousedown or drag event
22376 alignElWithMouse: function(el, iPageX, iPageY) {
22377 var oCoord = this.getTargetCoord(iPageX, iPageY);
22378 var fly = el.dom ? el : Roo.fly(el);
22379 if (!this.deltaSetXY) {
22380 var aCoord = [oCoord.x, oCoord.y];
22382 var newLeft = fly.getLeft(true);
22383 var newTop = fly.getTop(true);
22384 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
22386 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
22389 this.cachePosition(oCoord.x, oCoord.y);
22390 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
22395 * Saves the most recent position so that we can reset the constraints and
22396 * tick marks on-demand. We need to know this so that we can calculate the
22397 * number of pixels the element is offset from its original position.
22398 * @method cachePosition
22399 * @param iPageX the current x position (optional, this just makes it so we
22400 * don't have to look it up again)
22401 * @param iPageY the current y position (optional, this just makes it so we
22402 * don't have to look it up again)
22404 cachePosition: function(iPageX, iPageY) {
22406 this.lastPageX = iPageX;
22407 this.lastPageY = iPageY;
22409 var aCoord = Roo.lib.Dom.getXY(this.getEl());
22410 this.lastPageX = aCoord[0];
22411 this.lastPageY = aCoord[1];
22416 * Auto-scroll the window if the dragged object has been moved beyond the
22417 * visible window boundary.
22418 * @method autoScroll
22419 * @param {int} x the drag element's x position
22420 * @param {int} y the drag element's y position
22421 * @param {int} h the height of the drag element
22422 * @param {int} w the width of the drag element
22425 autoScroll: function(x, y, h, w) {
22428 // The client height
22429 var clientH = Roo.lib.Dom.getViewWidth();
22431 // The client width
22432 var clientW = Roo.lib.Dom.getViewHeight();
22434 // The amt scrolled down
22435 var st = this.DDM.getScrollTop();
22437 // The amt scrolled right
22438 var sl = this.DDM.getScrollLeft();
22440 // Location of the bottom of the element
22443 // Location of the right of the element
22446 // The distance from the cursor to the bottom of the visible area,
22447 // adjusted so that we don't scroll if the cursor is beyond the
22448 // element drag constraints
22449 var toBot = (clientH + st - y - this.deltaY);
22451 // The distance from the cursor to the right of the visible area
22452 var toRight = (clientW + sl - x - this.deltaX);
22455 // How close to the edge the cursor must be before we scroll
22456 // var thresh = (document.all) ? 100 : 40;
22459 // How many pixels to scroll per autoscroll op. This helps to reduce
22460 // clunky scrolling. IE is more sensitive about this ... it needs this
22461 // value to be higher.
22462 var scrAmt = (document.all) ? 80 : 30;
22464 // Scroll down if we are near the bottom of the visible page and the
22465 // obj extends below the crease
22466 if ( bot > clientH && toBot < thresh ) {
22467 window.scrollTo(sl, st + scrAmt);
22470 // Scroll up if the window is scrolled down and the top of the object
22471 // goes above the top border
22472 if ( y < st && st > 0 && y - st < thresh ) {
22473 window.scrollTo(sl, st - scrAmt);
22476 // Scroll right if the obj is beyond the right border and the cursor is
22477 // near the border.
22478 if ( right > clientW && toRight < thresh ) {
22479 window.scrollTo(sl + scrAmt, st);
22482 // Scroll left if the window has been scrolled to the right and the obj
22483 // extends past the left border
22484 if ( x < sl && sl > 0 && x - sl < thresh ) {
22485 window.scrollTo(sl - scrAmt, st);
22491 * Finds the location the element should be placed if we want to move
22492 * it to where the mouse location less the click offset would place us.
22493 * @method getTargetCoord
22494 * @param {int} iPageX the X coordinate of the click
22495 * @param {int} iPageY the Y coordinate of the click
22496 * @return an object that contains the coordinates (Object.x and Object.y)
22499 getTargetCoord: function(iPageX, iPageY) {
22502 var x = iPageX - this.deltaX;
22503 var y = iPageY - this.deltaY;
22505 if (this.constrainX) {
22506 if (x < this.minX) { x = this.minX; }
22507 if (x > this.maxX) { x = this.maxX; }
22510 if (this.constrainY) {
22511 if (y < this.minY) { y = this.minY; }
22512 if (y > this.maxY) { y = this.maxY; }
22515 x = this.getTick(x, this.xTicks);
22516 y = this.getTick(y, this.yTicks);
22523 * Sets up config options specific to this class. Overrides
22524 * Roo.dd.DragDrop, but all versions of this method through the
22525 * inheritance chain are called
22527 applyConfig: function() {
22528 Roo.dd.DD.superclass.applyConfig.call(this);
22529 this.scroll = (this.config.scroll !== false);
22533 * Event that fires prior to the onMouseDown event. Overrides
22536 b4MouseDown: function(e) {
22537 // this.resetConstraints();
22538 this.autoOffset(e.getPageX(),
22543 * Event that fires prior to the onDrag event. Overrides
22546 b4Drag: function(e) {
22547 this.setDragElPos(e.getPageX(),
22551 toString: function() {
22552 return ("DD " + this.id);
22555 //////////////////////////////////////////////////////////////////////////
22556 // Debugging ygDragDrop events that can be overridden
22557 //////////////////////////////////////////////////////////////////////////
22559 startDrag: function(x, y) {
22562 onDrag: function(e) {
22565 onDragEnter: function(e, id) {
22568 onDragOver: function(e, id) {
22571 onDragOut: function(e, id) {
22574 onDragDrop: function(e, id) {
22577 endDrag: function(e) {
22584 * Ext JS Library 1.1.1
22585 * Copyright(c) 2006-2007, Ext JS, LLC.
22587 * Originally Released Under LGPL - original licence link has changed is not relivant.
22590 * <script type="text/javascript">
22594 * @class Roo.dd.DDProxy
22595 * A DragDrop implementation that inserts an empty, bordered div into
22596 * the document that follows the cursor during drag operations. At the time of
22597 * the click, the frame div is resized to the dimensions of the linked html
22598 * element, and moved to the exact location of the linked element.
22600 * References to the "frame" element refer to the single proxy element that
22601 * was created to be dragged in place of all DDProxy elements on the
22604 * @extends Roo.dd.DD
22606 * @param {String} id the id of the linked html element
22607 * @param {String} sGroup the group of related DragDrop objects
22608 * @param {object} config an object containing configurable attributes
22609 * Valid properties for DDProxy in addition to those in DragDrop:
22610 * resizeFrame, centerFrame, dragElId
22612 Roo.dd.DDProxy = function(id, sGroup, config) {
22614 this.init(id, sGroup, config);
22620 * The default drag frame div id
22621 * @property Roo.dd.DDProxy.dragElId
22625 Roo.dd.DDProxy.dragElId = "ygddfdiv";
22627 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
22630 * By default we resize the drag frame to be the same size as the element
22631 * we want to drag (this is to get the frame effect). We can turn it off
22632 * if we want a different behavior.
22633 * @property resizeFrame
22639 * By default the frame is positioned exactly where the drag element is, so
22640 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
22641 * you do not have constraints on the obj is to have the drag frame centered
22642 * around the cursor. Set centerFrame to true for this effect.
22643 * @property centerFrame
22646 centerFrame: false,
22649 * Creates the proxy element if it does not yet exist
22650 * @method createFrame
22652 createFrame: function() {
22654 var body = document.body;
22656 if (!body || !body.firstChild) {
22657 setTimeout( function() { self.createFrame(); }, 50 );
22661 var div = this.getDragEl();
22664 div = document.createElement("div");
22665 div.id = this.dragElId;
22668 s.position = "absolute";
22669 s.visibility = "hidden";
22671 s.border = "2px solid #aaa";
22674 // appendChild can blow up IE if invoked prior to the window load event
22675 // while rendering a table. It is possible there are other scenarios
22676 // that would cause this to happen as well.
22677 body.insertBefore(div, body.firstChild);
22682 * Initialization for the drag frame element. Must be called in the
22683 * constructor of all subclasses
22684 * @method initFrame
22686 initFrame: function() {
22687 this.createFrame();
22690 applyConfig: function() {
22691 Roo.dd.DDProxy.superclass.applyConfig.call(this);
22693 this.resizeFrame = (this.config.resizeFrame !== false);
22694 this.centerFrame = (this.config.centerFrame);
22695 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
22699 * Resizes the drag frame to the dimensions of the clicked object, positions
22700 * it over the object, and finally displays it
22701 * @method showFrame
22702 * @param {int} iPageX X click position
22703 * @param {int} iPageY Y click position
22706 showFrame: function(iPageX, iPageY) {
22707 var el = this.getEl();
22708 var dragEl = this.getDragEl();
22709 var s = dragEl.style;
22711 this._resizeProxy();
22713 if (this.centerFrame) {
22714 this.setDelta( Math.round(parseInt(s.width, 10)/2),
22715 Math.round(parseInt(s.height, 10)/2) );
22718 this.setDragElPos(iPageX, iPageY);
22720 Roo.fly(dragEl).show();
22724 * The proxy is automatically resized to the dimensions of the linked
22725 * element when a drag is initiated, unless resizeFrame is set to false
22726 * @method _resizeProxy
22729 _resizeProxy: function() {
22730 if (this.resizeFrame) {
22731 var el = this.getEl();
22732 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
22736 // overrides Roo.dd.DragDrop
22737 b4MouseDown: function(e) {
22738 var x = e.getPageX();
22739 var y = e.getPageY();
22740 this.autoOffset(x, y);
22741 this.setDragElPos(x, y);
22744 // overrides Roo.dd.DragDrop
22745 b4StartDrag: function(x, y) {
22746 // show the drag frame
22747 this.showFrame(x, y);
22750 // overrides Roo.dd.DragDrop
22751 b4EndDrag: function(e) {
22752 Roo.fly(this.getDragEl()).hide();
22755 // overrides Roo.dd.DragDrop
22756 // By default we try to move the element to the last location of the frame.
22757 // This is so that the default behavior mirrors that of Roo.dd.DD.
22758 endDrag: function(e) {
22760 var lel = this.getEl();
22761 var del = this.getDragEl();
22763 // Show the drag frame briefly so we can get its position
22764 del.style.visibility = "";
22767 // Hide the linked element before the move to get around a Safari
22769 lel.style.visibility = "hidden";
22770 Roo.dd.DDM.moveToEl(lel, del);
22771 del.style.visibility = "hidden";
22772 lel.style.visibility = "";
22777 beforeMove : function(){
22781 afterDrag : function(){
22785 toString: function() {
22786 return ("DDProxy " + this.id);
22792 * Ext JS Library 1.1.1
22793 * Copyright(c) 2006-2007, Ext JS, LLC.
22795 * Originally Released Under LGPL - original licence link has changed is not relivant.
22798 * <script type="text/javascript">
22802 * @class Roo.dd.DDTarget
22803 * A DragDrop implementation that does not move, but can be a drop
22804 * target. You would get the same result by simply omitting implementation
22805 * for the event callbacks, but this way we reduce the processing cost of the
22806 * event listener and the callbacks.
22807 * @extends Roo.dd.DragDrop
22809 * @param {String} id the id of the element that is a drop target
22810 * @param {String} sGroup the group of related DragDrop objects
22811 * @param {object} config an object containing configurable attributes
22812 * Valid properties for DDTarget in addition to those in
22816 Roo.dd.DDTarget = function(id, sGroup, config) {
22818 this.initTarget(id, sGroup, config);
22820 if (config && (config.listeners || config.events)) {
22821 Roo.dd.DragDrop.superclass.constructor.call(this, {
22822 listeners : config.listeners || {},
22823 events : config.events || {}
22828 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
22829 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
22830 toString: function() {
22831 return ("DDTarget " + this.id);
22836 * Ext JS Library 1.1.1
22837 * Copyright(c) 2006-2007, Ext JS, LLC.
22839 * Originally Released Under LGPL - original licence link has changed is not relivant.
22842 * <script type="text/javascript">
22847 * @class Roo.dd.ScrollManager
22848 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
22849 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
22852 Roo.dd.ScrollManager = function(){
22853 var ddm = Roo.dd.DragDropMgr;
22860 var onStop = function(e){
22865 var triggerRefresh = function(){
22866 if(ddm.dragCurrent){
22867 ddm.refreshCache(ddm.dragCurrent.groups);
22871 var doScroll = function(){
22872 if(ddm.dragCurrent){
22873 var dds = Roo.dd.ScrollManager;
22875 if(proc.el.scroll(proc.dir, dds.increment)){
22879 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
22884 var clearProc = function(){
22886 clearInterval(proc.id);
22893 var startProc = function(el, dir){
22894 Roo.log('scroll startproc');
22898 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
22901 var onFire = function(e, isDrop){
22903 if(isDrop || !ddm.dragCurrent){ return; }
22904 var dds = Roo.dd.ScrollManager;
22905 if(!dragEl || dragEl != ddm.dragCurrent){
22906 dragEl = ddm.dragCurrent;
22907 // refresh regions on drag start
22908 dds.refreshCache();
22911 var xy = Roo.lib.Event.getXY(e);
22912 var pt = new Roo.lib.Point(xy[0], xy[1]);
22913 for(var id in els){
22914 var el = els[id], r = el._region;
22915 if(r && r.contains(pt) && el.isScrollable()){
22916 if(r.bottom - pt.y <= dds.thresh){
22918 startProc(el, "down");
22921 }else if(r.right - pt.x <= dds.thresh){
22923 startProc(el, "left");
22926 }else if(pt.y - r.top <= dds.thresh){
22928 startProc(el, "up");
22931 }else if(pt.x - r.left <= dds.thresh){
22933 startProc(el, "right");
22942 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
22943 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
22947 * Registers new overflow element(s) to auto scroll
22948 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
22950 register : function(el){
22951 if(el instanceof Array){
22952 for(var i = 0, len = el.length; i < len; i++) {
22953 this.register(el[i]);
22959 Roo.dd.ScrollManager.els = els;
22963 * Unregisters overflow element(s) so they are no longer scrolled
22964 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
22966 unregister : function(el){
22967 if(el instanceof Array){
22968 for(var i = 0, len = el.length; i < len; i++) {
22969 this.unregister(el[i]);
22978 * The number of pixels from the edge of a container the pointer needs to be to
22979 * trigger scrolling (defaults to 25)
22985 * The number of pixels to scroll in each scroll increment (defaults to 50)
22991 * The frequency of scrolls in milliseconds (defaults to 500)
22997 * True to animate the scroll (defaults to true)
23003 * The animation duration in seconds -
23004 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
23010 * Manually trigger a cache refresh.
23012 refreshCache : function(){
23013 for(var id in els){
23014 if(typeof els[id] == 'object'){ // for people extending the object prototype
23015 els[id]._region = els[id].getRegion();
23022 * Ext JS Library 1.1.1
23023 * Copyright(c) 2006-2007, Ext JS, LLC.
23025 * Originally Released Under LGPL - original licence link has changed is not relivant.
23028 * <script type="text/javascript">
23033 * @class Roo.dd.Registry
23034 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
23035 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
23038 Roo.dd.Registry = function(){
23041 var autoIdSeed = 0;
23043 var getId = function(el, autogen){
23044 if(typeof el == "string"){
23048 if(!id && autogen !== false){
23049 id = "roodd-" + (++autoIdSeed);
23057 * Register a drag drop element
23058 * @param {String|HTMLElement} element The id or DOM node to register
23059 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
23060 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
23061 * knows how to interpret, plus there are some specific properties known to the Registry that should be
23062 * populated in the data object (if applicable):
23064 Value Description<br />
23065 --------- ------------------------------------------<br />
23066 handles Array of DOM nodes that trigger dragging<br />
23067 for the element being registered<br />
23068 isHandle True if the element passed in triggers<br />
23069 dragging itself, else false
23072 register : function(el, data){
23074 if(typeof el == "string"){
23075 el = document.getElementById(el);
23078 elements[getId(el)] = data;
23079 if(data.isHandle !== false){
23080 handles[data.ddel.id] = data;
23083 var hs = data.handles;
23084 for(var i = 0, len = hs.length; i < len; i++){
23085 handles[getId(hs[i])] = data;
23091 * Unregister a drag drop element
23092 * @param {String|HTMLElement} element The id or DOM node to unregister
23094 unregister : function(el){
23095 var id = getId(el, false);
23096 var data = elements[id];
23098 delete elements[id];
23100 var hs = data.handles;
23101 for(var i = 0, len = hs.length; i < len; i++){
23102 delete handles[getId(hs[i], false)];
23109 * Returns the handle registered for a DOM Node by id
23110 * @param {String|HTMLElement} id The DOM node or id to look up
23111 * @return {Object} handle The custom handle data
23113 getHandle : function(id){
23114 if(typeof id != "string"){ // must be element?
23117 return handles[id];
23121 * Returns the handle that is registered for the DOM node that is the target of the event
23122 * @param {Event} e The event
23123 * @return {Object} handle The custom handle data
23125 getHandleFromEvent : function(e){
23126 var t = Roo.lib.Event.getTarget(e);
23127 return t ? handles[t.id] : null;
23131 * Returns a custom data object that is registered for a DOM node by id
23132 * @param {String|HTMLElement} id The DOM node or id to look up
23133 * @return {Object} data The custom data
23135 getTarget : function(id){
23136 if(typeof id != "string"){ // must be element?
23139 return elements[id];
23143 * Returns a custom data object that is registered for the DOM node that is the target of the event
23144 * @param {Event} e The event
23145 * @return {Object} data The custom data
23147 getTargetFromEvent : function(e){
23148 var t = Roo.lib.Event.getTarget(e);
23149 return t ? elements[t.id] || handles[t.id] : null;
23154 * Ext JS Library 1.1.1
23155 * Copyright(c) 2006-2007, Ext JS, LLC.
23157 * Originally Released Under LGPL - original licence link has changed is not relivant.
23160 * <script type="text/javascript">
23165 * @class Roo.dd.StatusProxy
23166 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
23167 * default drag proxy used by all Roo.dd components.
23169 * @param {Object} config
23171 Roo.dd.StatusProxy = function(config){
23172 Roo.apply(this, config);
23173 this.id = this.id || Roo.id();
23174 this.el = new Roo.Layer({
23176 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
23177 {tag: "div", cls: "x-dd-drop-icon"},
23178 {tag: "div", cls: "x-dd-drag-ghost"}
23181 shadow: !config || config.shadow !== false
23183 this.ghost = Roo.get(this.el.dom.childNodes[1]);
23184 this.dropStatus = this.dropNotAllowed;
23187 Roo.dd.StatusProxy.prototype = {
23189 * @cfg {String} dropAllowed
23190 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
23192 dropAllowed : "x-dd-drop-ok",
23194 * @cfg {String} dropNotAllowed
23195 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
23197 dropNotAllowed : "x-dd-drop-nodrop",
23200 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
23201 * over the current target element.
23202 * @param {String} cssClass The css class for the new drop status indicator image
23204 setStatus : function(cssClass){
23205 cssClass = cssClass || this.dropNotAllowed;
23206 if(this.dropStatus != cssClass){
23207 this.el.replaceClass(this.dropStatus, cssClass);
23208 this.dropStatus = cssClass;
23213 * Resets the status indicator to the default dropNotAllowed value
23214 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
23216 reset : function(clearGhost){
23217 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
23218 this.dropStatus = this.dropNotAllowed;
23220 this.ghost.update("");
23225 * Updates the contents of the ghost element
23226 * @param {String} html The html that will replace the current innerHTML of the ghost element
23228 update : function(html){
23229 if(typeof html == "string"){
23230 this.ghost.update(html);
23232 this.ghost.update("");
23233 html.style.margin = "0";
23234 this.ghost.dom.appendChild(html);
23236 // ensure float = none set?? cant remember why though.
23237 var el = this.ghost.dom.firstChild;
23239 Roo.fly(el).setStyle('float', 'none');
23244 * Returns the underlying proxy {@link Roo.Layer}
23245 * @return {Roo.Layer} el
23247 getEl : function(){
23252 * Returns the ghost element
23253 * @return {Roo.Element} el
23255 getGhost : function(){
23261 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
23263 hide : function(clear){
23271 * Stops the repair animation if it's currently running
23274 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
23280 * Displays this proxy
23287 * Force the Layer to sync its shadow and shim positions to the element
23294 * Causes the proxy to return to its position of origin via an animation. Should be called after an
23295 * invalid drop operation by the item being dragged.
23296 * @param {Array} xy The XY position of the element ([x, y])
23297 * @param {Function} callback The function to call after the repair is complete
23298 * @param {Object} scope The scope in which to execute the callback
23300 repair : function(xy, callback, scope){
23301 this.callback = callback;
23302 this.scope = scope;
23303 if(xy && this.animRepair !== false){
23304 this.el.addClass("x-dd-drag-repair");
23305 this.el.hideUnders(true);
23306 this.anim = this.el.shift({
23307 duration: this.repairDuration || .5,
23311 callback: this.afterRepair,
23315 this.afterRepair();
23320 afterRepair : function(){
23322 if(typeof this.callback == "function"){
23323 this.callback.call(this.scope || this);
23325 this.callback = null;
23330 * Ext JS Library 1.1.1
23331 * Copyright(c) 2006-2007, Ext JS, LLC.
23333 * Originally Released Under LGPL - original licence link has changed is not relivant.
23336 * <script type="text/javascript">
23340 * @class Roo.dd.DragSource
23341 * @extends Roo.dd.DDProxy
23342 * A simple class that provides the basic implementation needed to make any element draggable.
23344 * @param {String/HTMLElement/Element} el The container element
23345 * @param {Object} config
23347 Roo.dd.DragSource = function(el, config){
23348 this.el = Roo.get(el);
23349 this.dragData = {};
23351 Roo.apply(this, config);
23354 this.proxy = new Roo.dd.StatusProxy();
23357 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
23358 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
23360 this.dragging = false;
23363 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
23365 * @cfg {String} dropAllowed
23366 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23368 dropAllowed : "x-dd-drop-ok",
23370 * @cfg {String} dropNotAllowed
23371 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23373 dropNotAllowed : "x-dd-drop-nodrop",
23376 * Returns the data object associated with this drag source
23377 * @return {Object} data An object containing arbitrary data
23379 getDragData : function(e){
23380 return this.dragData;
23384 onDragEnter : function(e, id){
23385 var target = Roo.dd.DragDropMgr.getDDById(id);
23386 this.cachedTarget = target;
23387 if(this.beforeDragEnter(target, e, id) !== false){
23388 if(target.isNotifyTarget){
23389 var status = target.notifyEnter(this, e, this.dragData);
23390 this.proxy.setStatus(status);
23392 this.proxy.setStatus(this.dropAllowed);
23395 if(this.afterDragEnter){
23397 * An empty function by default, but provided so that you can perform a custom action
23398 * when the dragged item enters the drop target by providing an implementation.
23399 * @param {Roo.dd.DragDrop} target The drop target
23400 * @param {Event} e The event object
23401 * @param {String} id The id of the dragged element
23402 * @method afterDragEnter
23404 this.afterDragEnter(target, e, id);
23410 * An empty function by default, but provided so that you can perform a custom action
23411 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
23412 * @param {Roo.dd.DragDrop} target The drop target
23413 * @param {Event} e The event object
23414 * @param {String} id The id of the dragged element
23415 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23417 beforeDragEnter : function(target, e, id){
23422 alignElWithMouse: function() {
23423 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
23428 onDragOver : function(e, id){
23429 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23430 if(this.beforeDragOver(target, e, id) !== false){
23431 if(target.isNotifyTarget){
23432 var status = target.notifyOver(this, e, this.dragData);
23433 this.proxy.setStatus(status);
23436 if(this.afterDragOver){
23438 * An empty function by default, but provided so that you can perform a custom action
23439 * while the dragged item is over the drop target by providing an implementation.
23440 * @param {Roo.dd.DragDrop} target The drop target
23441 * @param {Event} e The event object
23442 * @param {String} id The id of the dragged element
23443 * @method afterDragOver
23445 this.afterDragOver(target, e, id);
23451 * An empty function by default, but provided so that you can perform a custom action
23452 * while the dragged item is over the drop target and optionally cancel the onDragOver.
23453 * @param {Roo.dd.DragDrop} target The drop target
23454 * @param {Event} e The event object
23455 * @param {String} id The id of the dragged element
23456 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23458 beforeDragOver : function(target, e, id){
23463 onDragOut : function(e, id){
23464 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23465 if(this.beforeDragOut(target, e, id) !== false){
23466 if(target.isNotifyTarget){
23467 target.notifyOut(this, e, this.dragData);
23469 this.proxy.reset();
23470 if(this.afterDragOut){
23472 * An empty function by default, but provided so that you can perform a custom action
23473 * after the dragged item is dragged out of the target without dropping.
23474 * @param {Roo.dd.DragDrop} target The drop target
23475 * @param {Event} e The event object
23476 * @param {String} id The id of the dragged element
23477 * @method afterDragOut
23479 this.afterDragOut(target, e, id);
23482 this.cachedTarget = null;
23486 * An empty function by default, but provided so that you can perform a custom action before the dragged
23487 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
23488 * @param {Roo.dd.DragDrop} target The drop target
23489 * @param {Event} e The event object
23490 * @param {String} id The id of the dragged element
23491 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23493 beforeDragOut : function(target, e, id){
23498 onDragDrop : function(e, id){
23499 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23500 if(this.beforeDragDrop(target, e, id) !== false){
23501 if(target.isNotifyTarget){
23502 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
23503 this.onValidDrop(target, e, id);
23505 this.onInvalidDrop(target, e, id);
23508 this.onValidDrop(target, e, id);
23511 if(this.afterDragDrop){
23513 * An empty function by default, but provided so that you can perform a custom action
23514 * after a valid drag drop has occurred by providing an implementation.
23515 * @param {Roo.dd.DragDrop} target The drop target
23516 * @param {Event} e The event object
23517 * @param {String} id The id of the dropped element
23518 * @method afterDragDrop
23520 this.afterDragDrop(target, e, id);
23523 delete this.cachedTarget;
23527 * An empty function by default, but provided so that you can perform a custom action before the dragged
23528 * item is dropped onto the target and optionally cancel the onDragDrop.
23529 * @param {Roo.dd.DragDrop} target The drop target
23530 * @param {Event} e The event object
23531 * @param {String} id The id of the dragged element
23532 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
23534 beforeDragDrop : function(target, e, id){
23539 onValidDrop : function(target, e, id){
23541 if(this.afterValidDrop){
23543 * An empty function by default, but provided so that you can perform a custom action
23544 * after a valid drop has occurred by providing an implementation.
23545 * @param {Object} target The target DD
23546 * @param {Event} e The event object
23547 * @param {String} id The id of the dropped element
23548 * @method afterInvalidDrop
23550 this.afterValidDrop(target, e, id);
23555 getRepairXY : function(e, data){
23556 return this.el.getXY();
23560 onInvalidDrop : function(target, e, id){
23561 this.beforeInvalidDrop(target, e, id);
23562 if(this.cachedTarget){
23563 if(this.cachedTarget.isNotifyTarget){
23564 this.cachedTarget.notifyOut(this, e, this.dragData);
23566 this.cacheTarget = null;
23568 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
23570 if(this.afterInvalidDrop){
23572 * An empty function by default, but provided so that you can perform a custom action
23573 * after an invalid drop has occurred by providing an implementation.
23574 * @param {Event} e The event object
23575 * @param {String} id The id of the dropped element
23576 * @method afterInvalidDrop
23578 this.afterInvalidDrop(e, id);
23583 afterRepair : function(){
23585 this.el.highlight(this.hlColor || "c3daf9");
23587 this.dragging = false;
23591 * An empty function by default, but provided so that you can perform a custom action after an invalid
23592 * drop has occurred.
23593 * @param {Roo.dd.DragDrop} target The drop target
23594 * @param {Event} e The event object
23595 * @param {String} id The id of the dragged element
23596 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
23598 beforeInvalidDrop : function(target, e, id){
23603 handleMouseDown : function(e){
23604 if(this.dragging) {
23607 var data = this.getDragData(e);
23608 if(data && this.onBeforeDrag(data, e) !== false){
23609 this.dragData = data;
23611 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
23616 * An empty function by default, but provided so that you can perform a custom action before the initial
23617 * drag event begins and optionally cancel it.
23618 * @param {Object} data An object containing arbitrary data to be shared with drop targets
23619 * @param {Event} e The event object
23620 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23622 onBeforeDrag : function(data, e){
23627 * An empty function by default, but provided so that you can perform a custom action once the initial
23628 * drag event has begun. The drag cannot be canceled from this function.
23629 * @param {Number} x The x position of the click on the dragged object
23630 * @param {Number} y The y position of the click on the dragged object
23632 onStartDrag : Roo.emptyFn,
23634 // private - YUI override
23635 startDrag : function(x, y){
23636 this.proxy.reset();
23637 this.dragging = true;
23638 this.proxy.update("");
23639 this.onInitDrag(x, y);
23644 onInitDrag : function(x, y){
23645 var clone = this.el.dom.cloneNode(true);
23646 clone.id = Roo.id(); // prevent duplicate ids
23647 this.proxy.update(clone);
23648 this.onStartDrag(x, y);
23653 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
23654 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
23656 getProxy : function(){
23661 * Hides the drag source's {@link Roo.dd.StatusProxy}
23663 hideProxy : function(){
23665 this.proxy.reset(true);
23666 this.dragging = false;
23670 triggerCacheRefresh : function(){
23671 Roo.dd.DDM.refreshCache(this.groups);
23674 // private - override to prevent hiding
23675 b4EndDrag: function(e) {
23678 // private - override to prevent moving
23679 endDrag : function(e){
23680 this.onEndDrag(this.dragData, e);
23684 onEndDrag : function(data, e){
23687 // private - pin to cursor
23688 autoOffset : function(x, y) {
23689 this.setDelta(-12, -20);
23693 * Ext JS Library 1.1.1
23694 * Copyright(c) 2006-2007, Ext JS, LLC.
23696 * Originally Released Under LGPL - original licence link has changed is not relivant.
23699 * <script type="text/javascript">
23704 * @class Roo.dd.DropTarget
23705 * @extends Roo.dd.DDTarget
23706 * A simple class that provides the basic implementation needed to make any element a drop target that can have
23707 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
23709 * @param {String/HTMLElement/Element} el The container element
23710 * @param {Object} config
23712 Roo.dd.DropTarget = function(el, config){
23713 this.el = Roo.get(el);
23715 var listeners = false; ;
23716 if (config && config.listeners) {
23717 listeners= config.listeners;
23718 delete config.listeners;
23720 Roo.apply(this, config);
23722 if(this.containerScroll){
23723 Roo.dd.ScrollManager.register(this.el);
23727 * @scope Roo.dd.DropTarget
23732 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
23733 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
23734 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
23736 * IMPORTANT : it should set this.valid to true|false
23738 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23739 * @param {Event} e The event
23740 * @param {Object} data An object containing arbitrary data supplied by the drag source
23746 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
23747 * This method will be called on every mouse movement while the drag source is over the drop target.
23748 * This default implementation simply returns the dropAllowed config value.
23750 * IMPORTANT : it should set this.valid to true|false
23752 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23753 * @param {Event} e The event
23754 * @param {Object} data An object containing arbitrary data supplied by the drag source
23760 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
23761 * out of the target without dropping. This default implementation simply removes the CSS class specified by
23762 * overClass (if any) from the drop element.
23765 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23766 * @param {Event} e The event
23767 * @param {Object} data An object containing arbitrary data supplied by the drag source
23773 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
23774 * been dropped on it. This method has no default implementation and returns false, so you must provide an
23775 * implementation that does something to process the drop event and returns true so that the drag source's
23776 * repair action does not run.
23778 * IMPORTANT : it should set this.success
23780 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23781 * @param {Event} e The event
23782 * @param {Object} data An object containing arbitrary data supplied by the drag source
23788 Roo.dd.DropTarget.superclass.constructor.call( this,
23790 this.ddGroup || this.group,
23793 listeners : listeners || {}
23801 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
23803 * @cfg {String} overClass
23804 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
23807 * @cfg {String} ddGroup
23808 * The drag drop group to handle drop events for
23812 * @cfg {String} dropAllowed
23813 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23815 dropAllowed : "x-dd-drop-ok",
23817 * @cfg {String} dropNotAllowed
23818 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23820 dropNotAllowed : "x-dd-drop-nodrop",
23822 * @cfg {boolean} success
23823 * set this after drop listener..
23827 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
23828 * if the drop point is valid for over/enter..
23835 isNotifyTarget : true,
23840 notifyEnter : function(dd, e, data)
23843 this.fireEvent('enter', dd, e, data);
23844 if(this.overClass){
23845 this.el.addClass(this.overClass);
23847 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23848 this.valid ? this.dropAllowed : this.dropNotAllowed
23855 notifyOver : function(dd, e, data)
23858 this.fireEvent('over', dd, e, data);
23859 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23860 this.valid ? this.dropAllowed : this.dropNotAllowed
23867 notifyOut : function(dd, e, data)
23869 this.fireEvent('out', dd, e, data);
23870 if(this.overClass){
23871 this.el.removeClass(this.overClass);
23878 notifyDrop : function(dd, e, data)
23880 this.success = false;
23881 this.fireEvent('drop', dd, e, data);
23882 return this.success;
23886 * Ext JS Library 1.1.1
23887 * Copyright(c) 2006-2007, Ext JS, LLC.
23889 * Originally Released Under LGPL - original licence link has changed is not relivant.
23892 * <script type="text/javascript">
23897 * @class Roo.dd.DragZone
23898 * @extends Roo.dd.DragSource
23899 * This class provides a container DD instance that proxies for multiple child node sources.<br />
23900 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
23902 * @param {String/HTMLElement/Element} el The container element
23903 * @param {Object} config
23905 Roo.dd.DragZone = function(el, config){
23906 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
23907 if(this.containerScroll){
23908 Roo.dd.ScrollManager.register(this.el);
23912 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
23914 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
23915 * for auto scrolling during drag operations.
23918 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
23919 * method after a failed drop (defaults to "c3daf9" - light blue)
23923 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
23924 * for a valid target to drag based on the mouse down. Override this method
23925 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
23926 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
23927 * @param {EventObject} e The mouse down event
23928 * @return {Object} The dragData
23930 getDragData : function(e){
23931 return Roo.dd.Registry.getHandleFromEvent(e);
23935 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
23936 * this.dragData.ddel
23937 * @param {Number} x The x position of the click on the dragged object
23938 * @param {Number} y The y position of the click on the dragged object
23939 * @return {Boolean} true to continue the drag, false to cancel
23941 onInitDrag : function(x, y){
23942 this.proxy.update(this.dragData.ddel.cloneNode(true));
23943 this.onStartDrag(x, y);
23948 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
23950 afterRepair : function(){
23952 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
23954 this.dragging = false;
23958 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
23959 * the XY of this.dragData.ddel
23960 * @param {EventObject} e The mouse up event
23961 * @return {Array} The xy location (e.g. [100, 200])
23963 getRepairXY : function(e){
23964 return Roo.Element.fly(this.dragData.ddel).getXY();
23968 * Ext JS Library 1.1.1
23969 * Copyright(c) 2006-2007, Ext JS, LLC.
23971 * Originally Released Under LGPL - original licence link has changed is not relivant.
23974 * <script type="text/javascript">
23977 * @class Roo.dd.DropZone
23978 * @extends Roo.dd.DropTarget
23979 * This class provides a container DD instance that proxies for multiple child node targets.<br />
23980 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
23982 * @param {String/HTMLElement/Element} el The container element
23983 * @param {Object} config
23985 Roo.dd.DropZone = function(el, config){
23986 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
23989 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
23991 * Returns a custom data object associated with the DOM node that is the target of the event. By default
23992 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
23993 * provide your own custom lookup.
23994 * @param {Event} e The event
23995 * @return {Object} data The custom data
23997 getTargetFromEvent : function(e){
23998 return Roo.dd.Registry.getTargetFromEvent(e);
24002 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
24003 * that it has registered. This method has no default implementation and should be overridden to provide
24004 * node-specific processing if necessary.
24005 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24006 * {@link #getTargetFromEvent} for this node)
24007 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24008 * @param {Event} e The event
24009 * @param {Object} data An object containing arbitrary data supplied by the drag source
24011 onNodeEnter : function(n, dd, e, data){
24016 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
24017 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
24018 * overridden to provide the proper feedback.
24019 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24020 * {@link #getTargetFromEvent} for this node)
24021 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24022 * @param {Event} e The event
24023 * @param {Object} data An object containing arbitrary data supplied by the drag source
24024 * @return {String} status The CSS class that communicates the drop status back to the source so that the
24025 * underlying {@link Roo.dd.StatusProxy} can be updated
24027 onNodeOver : function(n, dd, e, data){
24028 return this.dropAllowed;
24032 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
24033 * the drop node without dropping. This method has no default implementation and should be overridden to provide
24034 * node-specific processing if necessary.
24035 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24036 * {@link #getTargetFromEvent} for this node)
24037 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24038 * @param {Event} e The event
24039 * @param {Object} data An object containing arbitrary data supplied by the drag source
24041 onNodeOut : function(n, dd, e, data){
24046 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
24047 * the drop node. The default implementation returns false, so it should be overridden to provide the
24048 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
24049 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24050 * {@link #getTargetFromEvent} for this node)
24051 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24052 * @param {Event} e The event
24053 * @param {Object} data An object containing arbitrary data supplied by the drag source
24054 * @return {Boolean} True if the drop was valid, else false
24056 onNodeDrop : function(n, dd, e, data){
24061 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
24062 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
24063 * it should be overridden to provide the proper feedback if necessary.
24064 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24065 * @param {Event} e The event
24066 * @param {Object} data An object containing arbitrary data supplied by the drag source
24067 * @return {String} status The CSS class that communicates the drop status back to the source so that the
24068 * underlying {@link Roo.dd.StatusProxy} can be updated
24070 onContainerOver : function(dd, e, data){
24071 return this.dropNotAllowed;
24075 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
24076 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
24077 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
24078 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
24079 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24080 * @param {Event} e The event
24081 * @param {Object} data An object containing arbitrary data supplied by the drag source
24082 * @return {Boolean} True if the drop was valid, else false
24084 onContainerDrop : function(dd, e, data){
24089 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
24090 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
24091 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
24092 * you should override this method and provide a custom implementation.
24093 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24094 * @param {Event} e The event
24095 * @param {Object} data An object containing arbitrary data supplied by the drag source
24096 * @return {String} status The CSS class that communicates the drop status back to the source so that the
24097 * underlying {@link Roo.dd.StatusProxy} can be updated
24099 notifyEnter : function(dd, e, data){
24100 return this.dropNotAllowed;
24104 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
24105 * This method will be called on every mouse movement while the drag source is over the drop zone.
24106 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
24107 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
24108 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
24109 * registered node, it will call {@link #onContainerOver}.
24110 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24111 * @param {Event} e The event
24112 * @param {Object} data An object containing arbitrary data supplied by the drag source
24113 * @return {String} status The CSS class that communicates the drop status back to the source so that the
24114 * underlying {@link Roo.dd.StatusProxy} can be updated
24116 notifyOver : function(dd, e, data){
24117 var n = this.getTargetFromEvent(e);
24118 if(!n){ // not over valid drop target
24119 if(this.lastOverNode){
24120 this.onNodeOut(this.lastOverNode, dd, e, data);
24121 this.lastOverNode = null;
24123 return this.onContainerOver(dd, e, data);
24125 if(this.lastOverNode != n){
24126 if(this.lastOverNode){
24127 this.onNodeOut(this.lastOverNode, dd, e, data);
24129 this.onNodeEnter(n, dd, e, data);
24130 this.lastOverNode = n;
24132 return this.onNodeOver(n, dd, e, data);
24136 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
24137 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
24138 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
24139 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24140 * @param {Event} e The event
24141 * @param {Object} data An object containing arbitrary data supplied by the drag zone
24143 notifyOut : function(dd, e, data){
24144 if(this.lastOverNode){
24145 this.onNodeOut(this.lastOverNode, dd, e, data);
24146 this.lastOverNode = null;
24151 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
24152 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
24153 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
24154 * otherwise it will call {@link #onContainerDrop}.
24155 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24156 * @param {Event} e The event
24157 * @param {Object} data An object containing arbitrary data supplied by the drag source
24158 * @return {Boolean} True if the drop was valid, else false
24160 notifyDrop : function(dd, e, data){
24161 if(this.lastOverNode){
24162 this.onNodeOut(this.lastOverNode, dd, e, data);
24163 this.lastOverNode = null;
24165 var n = this.getTargetFromEvent(e);
24167 this.onNodeDrop(n, dd, e, data) :
24168 this.onContainerDrop(dd, e, data);
24172 triggerCacheRefresh : function(){
24173 Roo.dd.DDM.refreshCache(this.groups);
24177 * Ext JS Library 1.1.1
24178 * Copyright(c) 2006-2007, Ext JS, LLC.
24180 * Originally Released Under LGPL - original licence link has changed is not relivant.
24183 * <script type="text/javascript">
24188 * @class Roo.data.SortTypes
24190 * Defines the default sorting (casting?) comparison functions used when sorting data.
24192 Roo.data.SortTypes = {
24194 * Default sort that does nothing
24195 * @param {Mixed} s The value being converted
24196 * @return {Mixed} The comparison value
24198 none : function(s){
24203 * The regular expression used to strip tags
24207 stripTagsRE : /<\/?[^>]+>/gi,
24210 * Strips all HTML tags to sort on text only
24211 * @param {Mixed} s The value being converted
24212 * @return {String} The comparison value
24214 asText : function(s){
24215 return String(s).replace(this.stripTagsRE, "");
24219 * Strips all HTML tags to sort on text only - Case insensitive
24220 * @param {Mixed} s The value being converted
24221 * @return {String} The comparison value
24223 asUCText : function(s){
24224 return String(s).toUpperCase().replace(this.stripTagsRE, "");
24228 * Case insensitive string
24229 * @param {Mixed} s The value being converted
24230 * @return {String} The comparison value
24232 asUCString : function(s) {
24233 return String(s).toUpperCase();
24238 * @param {Mixed} s The value being converted
24239 * @return {Number} The comparison value
24241 asDate : function(s) {
24245 if(s instanceof Date){
24246 return s.getTime();
24248 return Date.parse(String(s));
24253 * @param {Mixed} s The value being converted
24254 * @return {Float} The comparison value
24256 asFloat : function(s) {
24257 var val = parseFloat(String(s).replace(/,/g, ""));
24266 * @param {Mixed} s The value being converted
24267 * @return {Number} The comparison value
24269 asInt : function(s) {
24270 var val = parseInt(String(s).replace(/,/g, ""));
24278 * Ext JS Library 1.1.1
24279 * Copyright(c) 2006-2007, Ext JS, LLC.
24281 * Originally Released Under LGPL - original licence link has changed is not relivant.
24284 * <script type="text/javascript">
24288 * @class Roo.data.Record
24289 * Instances of this class encapsulate both record <em>definition</em> information, and record
24290 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
24291 * to access Records cached in an {@link Roo.data.Store} object.<br>
24293 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
24294 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
24297 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
24299 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
24300 * {@link #create}. The parameters are the same.
24301 * @param {Array} data An associative Array of data values keyed by the field name.
24302 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
24303 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
24304 * not specified an integer id is generated.
24306 Roo.data.Record = function(data, id){
24307 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
24312 * Generate a constructor for a specific record layout.
24313 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
24314 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
24315 * Each field definition object may contain the following properties: <ul>
24316 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
24317 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
24318 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
24319 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
24320 * is being used, then this is a string containing the javascript expression to reference the data relative to
24321 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
24322 * to the data item relative to the record element. If the mapping expression is the same as the field name,
24323 * this may be omitted.</p></li>
24324 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
24325 * <ul><li>auto (Default, implies no conversion)</li>
24330 * <li>date</li></ul></p></li>
24331 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
24332 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
24333 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
24334 * by the Reader into an object that will be stored in the Record. It is passed the
24335 * following parameters:<ul>
24336 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
24338 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
24340 * <br>usage:<br><pre><code>
24341 var TopicRecord = Roo.data.Record.create(
24342 {name: 'title', mapping: 'topic_title'},
24343 {name: 'author', mapping: 'username'},
24344 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
24345 {name: 'lastPost', mapping: 'post_time', type: 'date'},
24346 {name: 'lastPoster', mapping: 'user2'},
24347 {name: 'excerpt', mapping: 'post_text'}
24350 var myNewRecord = new TopicRecord({
24351 title: 'Do my job please',
24354 lastPost: new Date(),
24355 lastPoster: 'Animal',
24356 excerpt: 'No way dude!'
24358 myStore.add(myNewRecord);
24363 Roo.data.Record.create = function(o){
24364 var f = function(){
24365 f.superclass.constructor.apply(this, arguments);
24367 Roo.extend(f, Roo.data.Record);
24368 var p = f.prototype;
24369 p.fields = new Roo.util.MixedCollection(false, function(field){
24372 for(var i = 0, len = o.length; i < len; i++){
24373 p.fields.add(new Roo.data.Field(o[i]));
24375 f.getField = function(name){
24376 return p.fields.get(name);
24381 Roo.data.Record.AUTO_ID = 1000;
24382 Roo.data.Record.EDIT = 'edit';
24383 Roo.data.Record.REJECT = 'reject';
24384 Roo.data.Record.COMMIT = 'commit';
24386 Roo.data.Record.prototype = {
24388 * Readonly flag - true if this record has been modified.
24397 join : function(store){
24398 this.store = store;
24402 * Set the named field to the specified value.
24403 * @param {String} name The name of the field to set.
24404 * @param {Object} value The value to set the field to.
24406 set : function(name, value){
24407 if(this.data[name] == value){
24411 if(!this.modified){
24412 this.modified = {};
24414 if(typeof this.modified[name] == 'undefined'){
24415 this.modified[name] = this.data[name];
24417 this.data[name] = value;
24418 if(!this.editing && this.store){
24419 this.store.afterEdit(this);
24424 * Get the value of the named field.
24425 * @param {String} name The name of the field to get the value of.
24426 * @return {Object} The value of the field.
24428 get : function(name){
24429 return this.data[name];
24433 beginEdit : function(){
24434 this.editing = true;
24435 this.modified = {};
24439 cancelEdit : function(){
24440 this.editing = false;
24441 delete this.modified;
24445 endEdit : function(){
24446 this.editing = false;
24447 if(this.dirty && this.store){
24448 this.store.afterEdit(this);
24453 * Usually called by the {@link Roo.data.Store} which owns the Record.
24454 * Rejects all changes made to the Record since either creation, or the last commit operation.
24455 * Modified fields are reverted to their original values.
24457 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
24458 * of reject operations.
24460 reject : function(){
24461 var m = this.modified;
24463 if(typeof m[n] != "function"){
24464 this.data[n] = m[n];
24467 this.dirty = false;
24468 delete this.modified;
24469 this.editing = false;
24471 this.store.afterReject(this);
24476 * Usually called by the {@link Roo.data.Store} which owns the Record.
24477 * Commits all changes made to the Record since either creation, or the last commit operation.
24479 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
24480 * of commit operations.
24482 commit : function(){
24483 this.dirty = false;
24484 delete this.modified;
24485 this.editing = false;
24487 this.store.afterCommit(this);
24492 hasError : function(){
24493 return this.error != null;
24497 clearError : function(){
24502 * Creates a copy of this record.
24503 * @param {String} id (optional) A new record id if you don't want to use this record's id
24506 copy : function(newId) {
24507 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
24511 * Ext JS Library 1.1.1
24512 * Copyright(c) 2006-2007, Ext JS, LLC.
24514 * Originally Released Under LGPL - original licence link has changed is not relivant.
24517 * <script type="text/javascript">
24523 * @class Roo.data.Store
24524 * @extends Roo.util.Observable
24525 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
24526 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
24528 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
24529 * has no knowledge of the format of the data returned by the Proxy.<br>
24531 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
24532 * instances from the data object. These records are cached and made available through accessor functions.
24534 * Creates a new Store.
24535 * @param {Object} config A config object containing the objects needed for the Store to access data,
24536 * and read the data into Records.
24538 Roo.data.Store = function(config){
24539 this.data = new Roo.util.MixedCollection(false);
24540 this.data.getKey = function(o){
24543 this.baseParams = {};
24545 this.paramNames = {
24550 "multisort" : "_multisort"
24553 if(config && config.data){
24554 this.inlineData = config.data;
24555 delete config.data;
24558 Roo.apply(this, config);
24560 if(this.reader){ // reader passed
24561 this.reader = Roo.factory(this.reader, Roo.data);
24562 this.reader.xmodule = this.xmodule || false;
24563 if(!this.recordType){
24564 this.recordType = this.reader.recordType;
24566 if(this.reader.onMetaChange){
24567 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
24571 if(this.recordType){
24572 this.fields = this.recordType.prototype.fields;
24574 this.modified = [];
24578 * @event datachanged
24579 * Fires when the data cache has changed, and a widget which is using this Store
24580 * as a Record cache should refresh its view.
24581 * @param {Store} this
24583 datachanged : true,
24585 * @event metachange
24586 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
24587 * @param {Store} this
24588 * @param {Object} meta The JSON metadata
24593 * Fires when Records have been added to the Store
24594 * @param {Store} this
24595 * @param {Roo.data.Record[]} records The array of Records added
24596 * @param {Number} index The index at which the record(s) were added
24601 * Fires when a Record has been removed from the Store
24602 * @param {Store} this
24603 * @param {Roo.data.Record} record The Record that was removed
24604 * @param {Number} index The index at which the record was removed
24609 * Fires when a Record has been updated
24610 * @param {Store} this
24611 * @param {Roo.data.Record} record The Record that was updated
24612 * @param {String} operation The update operation being performed. Value may be one of:
24614 Roo.data.Record.EDIT
24615 Roo.data.Record.REJECT
24616 Roo.data.Record.COMMIT
24622 * Fires when the data cache has been cleared.
24623 * @param {Store} this
24627 * @event beforeload
24628 * Fires before a request is made for a new data object. If the beforeload handler returns false
24629 * the load action will be canceled.
24630 * @param {Store} this
24631 * @param {Object} options The loading options that were specified (see {@link #load} for details)
24635 * @event beforeloadadd
24636 * Fires after a new set of Records has been loaded.
24637 * @param {Store} this
24638 * @param {Roo.data.Record[]} records The Records that were loaded
24639 * @param {Object} options The loading options that were specified (see {@link #load} for details)
24641 beforeloadadd : true,
24644 * Fires after a new set of Records has been loaded, before they are added to the store.
24645 * @param {Store} this
24646 * @param {Roo.data.Record[]} records The Records that were loaded
24647 * @param {Object} options The loading options that were specified (see {@link #load} for details)
24648 * @params {Object} return from reader
24652 * @event loadexception
24653 * Fires if an exception occurs in the Proxy during loading.
24654 * Called with the signature of the Proxy's "loadexception" event.
24655 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
24658 * @param {Object} return from JsonData.reader() - success, totalRecords, records
24659 * @param {Object} load options
24660 * @param {Object} jsonData from your request (normally this contains the Exception)
24662 loadexception : true
24666 this.proxy = Roo.factory(this.proxy, Roo.data);
24667 this.proxy.xmodule = this.xmodule || false;
24668 this.relayEvents(this.proxy, ["loadexception"]);
24670 this.sortToggle = {};
24671 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
24673 Roo.data.Store.superclass.constructor.call(this);
24675 if(this.inlineData){
24676 this.loadData(this.inlineData);
24677 delete this.inlineData;
24681 Roo.extend(Roo.data.Store, Roo.util.Observable, {
24683 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
24684 * without a remote query - used by combo/forms at present.
24688 * @cfg {Roo.data.DataProxy} proxy [required] The Proxy object which provides access to a data object.
24691 * @cfg {Array} data Inline data to be loaded when the store is initialized.
24694 * @cfg {Roo.data.DataReader} reader [required] The Reader object which processes the data object and returns
24695 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
24698 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
24699 * on any HTTP request
24702 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
24705 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
24709 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
24710 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
24712 remoteSort : false,
24715 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
24716 * loaded or when a record is removed. (defaults to false).
24718 pruneModifiedRecords : false,
24721 lastOptions : null,
24724 * Add Records to the Store and fires the add event.
24725 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
24727 add : function(records){
24728 records = [].concat(records);
24729 for(var i = 0, len = records.length; i < len; i++){
24730 records[i].join(this);
24732 var index = this.data.length;
24733 this.data.addAll(records);
24734 this.fireEvent("add", this, records, index);
24738 * Remove a Record from the Store and fires the remove event.
24739 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
24741 remove : function(record){
24742 var index = this.data.indexOf(record);
24743 this.data.removeAt(index);
24745 if(this.pruneModifiedRecords){
24746 this.modified.remove(record);
24748 this.fireEvent("remove", this, record, index);
24752 * Remove all Records from the Store and fires the clear event.
24754 removeAll : function(){
24756 if(this.pruneModifiedRecords){
24757 this.modified = [];
24759 this.fireEvent("clear", this);
24763 * Inserts Records to the Store at the given index and fires the add event.
24764 * @param {Number} index The start index at which to insert the passed Records.
24765 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
24767 insert : function(index, records){
24768 records = [].concat(records);
24769 for(var i = 0, len = records.length; i < len; i++){
24770 this.data.insert(index, records[i]);
24771 records[i].join(this);
24773 this.fireEvent("add", this, records, index);
24777 * Get the index within the cache of the passed Record.
24778 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
24779 * @return {Number} The index of the passed Record. Returns -1 if not found.
24781 indexOf : function(record){
24782 return this.data.indexOf(record);
24786 * Get the index within the cache of the Record with the passed id.
24787 * @param {String} id The id of the Record to find.
24788 * @return {Number} The index of the Record. Returns -1 if not found.
24790 indexOfId : function(id){
24791 return this.data.indexOfKey(id);
24795 * Get the Record with the specified id.
24796 * @param {String} id The id of the Record to find.
24797 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
24799 getById : function(id){
24800 return this.data.key(id);
24804 * Get the Record at the specified index.
24805 * @param {Number} index The index of the Record to find.
24806 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
24808 getAt : function(index){
24809 return this.data.itemAt(index);
24813 * Returns a range of Records between specified indices.
24814 * @param {Number} startIndex (optional) The starting index (defaults to 0)
24815 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
24816 * @return {Roo.data.Record[]} An array of Records
24818 getRange : function(start, end){
24819 return this.data.getRange(start, end);
24823 storeOptions : function(o){
24824 o = Roo.apply({}, o);
24827 this.lastOptions = o;
24831 * Loads the Record cache from the configured Proxy using the configured Reader.
24833 * If using remote paging, then the first load call must specify the <em>start</em>
24834 * and <em>limit</em> properties in the options.params property to establish the initial
24835 * position within the dataset, and the number of Records to cache on each read from the Proxy.
24837 * <strong>It is important to note that for remote data sources, loading is asynchronous,
24838 * and this call will return before the new data has been loaded. Perform any post-processing
24839 * in a callback function, or in a "load" event handler.</strong>
24841 * @param {Object} options An object containing properties which control loading options:<ul>
24842 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
24843 * <li>params.data {Object} if you are using a MemoryProxy / JsonReader, use this as the data to load stuff..
24846 data : data, // array of key=>value data like JsonReader
24847 total : data.length,
24853 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
24854 * passed the following arguments:<ul>
24855 * <li>r : Roo.data.Record[]</li>
24856 * <li>options: Options object from the load call</li>
24857 * <li>success: Boolean success indicator</li></ul></li>
24858 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
24859 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
24862 load : function(options){
24863 options = options || {};
24864 if(this.fireEvent("beforeload", this, options) !== false){
24865 this.storeOptions(options);
24866 var p = Roo.apply(options.params || {}, this.baseParams);
24867 // if meta was not loaded from remote source.. try requesting it.
24868 if (!this.reader.metaFromRemote) {
24869 p._requestMeta = 1;
24871 if(this.sortInfo && this.remoteSort){
24872 var pn = this.paramNames;
24873 p[pn["sort"]] = this.sortInfo.field;
24874 p[pn["dir"]] = this.sortInfo.direction;
24876 if (this.multiSort) {
24877 var pn = this.paramNames;
24878 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
24881 this.proxy.load(p, this.reader, this.loadRecords, this, options);
24886 * Reloads the Record cache from the configured Proxy using the configured Reader and
24887 * the options from the last load operation performed.
24888 * @param {Object} options (optional) An object containing properties which may override the options
24889 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
24890 * the most recently used options are reused).
24892 reload : function(options){
24893 this.load(Roo.applyIf(options||{}, this.lastOptions));
24897 // Called as a callback by the Reader during a load operation.
24898 loadRecords : function(o, options, success){
24901 if(success !== false){
24902 this.fireEvent("load", this, [], options, o);
24904 if(options.callback){
24905 options.callback.call(options.scope || this, [], options, false);
24909 // if data returned failure - throw an exception.
24910 if (o.success === false) {
24911 // show a message if no listener is registered.
24912 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
24913 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
24915 // loadmask wil be hooked into this..
24916 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
24919 var r = o.records, t = o.totalRecords || r.length;
24921 this.fireEvent("beforeloadadd", this, r, options, o);
24923 if(!options || options.add !== true){
24924 if(this.pruneModifiedRecords){
24925 this.modified = [];
24927 for(var i = 0, len = r.length; i < len; i++){
24931 this.data = this.snapshot;
24932 delete this.snapshot;
24935 this.data.addAll(r);
24936 this.totalLength = t;
24938 this.fireEvent("datachanged", this);
24940 this.totalLength = Math.max(t, this.data.length+r.length);
24944 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
24946 var e = new Roo.data.Record({});
24948 e.set(this.parent.displayField, this.parent.emptyTitle);
24949 e.set(this.parent.valueField, '');
24954 this.fireEvent("load", this, r, options, o);
24955 if(options.callback){
24956 options.callback.call(options.scope || this, r, options, true);
24962 * Loads data from a passed data block. A Reader which understands the format of the data
24963 * must have been configured in the constructor.
24964 * @param {Object} data The data block from which to read the Records. The format of the data expected
24965 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
24966 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
24968 loadData : function(o, append){
24969 var r = this.reader.readRecords(o);
24970 this.loadRecords(r, {add: append}, true);
24974 * using 'cn' the nested child reader read the child array into it's child stores.
24975 * @param {Object} rec The record with a 'children array
24977 loadDataFromChildren : function(rec)
24979 this.loadData(this.reader.toLoadData(rec));
24984 * Gets the number of cached records.
24986 * <em>If using paging, this may not be the total size of the dataset. If the data object
24987 * used by the Reader contains the dataset size, then the getTotalCount() function returns
24988 * the data set size</em>
24990 getCount : function(){
24991 return this.data.length || 0;
24995 * Gets the total number of records in the dataset as returned by the server.
24997 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
24998 * the dataset size</em>
25000 getTotalCount : function(){
25001 return this.totalLength || 0;
25005 * Returns the sort state of the Store as an object with two properties:
25007 field {String} The name of the field by which the Records are sorted
25008 direction {String} The sort order, "ASC" or "DESC"
25011 getSortState : function(){
25012 return this.sortInfo;
25016 applySort : function(){
25017 if(this.sortInfo && !this.remoteSort){
25018 var s = this.sortInfo, f = s.field;
25019 var st = this.fields.get(f).sortType;
25020 var fn = function(r1, r2){
25021 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
25022 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
25024 this.data.sort(s.direction, fn);
25025 if(this.snapshot && this.snapshot != this.data){
25026 this.snapshot.sort(s.direction, fn);
25032 * Sets the default sort column and order to be used by the next load operation.
25033 * @param {String} fieldName The name of the field to sort by.
25034 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
25036 setDefaultSort : function(field, dir){
25037 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
25041 * Sort the Records.
25042 * If remote sorting is used, the sort is performed on the server, and the cache is
25043 * reloaded. If local sorting is used, the cache is sorted internally.
25044 * @param {String} fieldName The name of the field to sort by.
25045 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
25047 sort : function(fieldName, dir){
25048 var f = this.fields.get(fieldName);
25050 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
25052 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
25053 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
25058 this.sortToggle[f.name] = dir;
25059 this.sortInfo = {field: f.name, direction: dir};
25060 if(!this.remoteSort){
25062 this.fireEvent("datachanged", this);
25064 this.load(this.lastOptions);
25069 * Calls the specified function for each of the Records in the cache.
25070 * @param {Function} fn The function to call. The Record is passed as the first parameter.
25071 * Returning <em>false</em> aborts and exits the iteration.
25072 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
25074 each : function(fn, scope){
25075 this.data.each(fn, scope);
25079 * Gets all records modified since the last commit. Modified records are persisted across load operations
25080 * (e.g., during paging).
25081 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
25083 getModifiedRecords : function(){
25084 return this.modified;
25088 createFilterFn : function(property, value, anyMatch){
25089 if(!value.exec){ // not a regex
25090 value = String(value);
25091 if(value.length == 0){
25094 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
25096 return function(r){
25097 return value.test(r.data[property]);
25102 * Sums the value of <i>property</i> for each record between start and end and returns the result.
25103 * @param {String} property A field on your records
25104 * @param {Number} start The record index to start at (defaults to 0)
25105 * @param {Number} end The last record index to include (defaults to length - 1)
25106 * @return {Number} The sum
25108 sum : function(property, start, end){
25109 var rs = this.data.items, v = 0;
25110 start = start || 0;
25111 end = (end || end === 0) ? end : rs.length-1;
25113 for(var i = start; i <= end; i++){
25114 v += (rs[i].data[property] || 0);
25120 * Filter the records by a specified property.
25121 * @param {String} field A field on your records
25122 * @param {String/RegExp} value Either a string that the field
25123 * should start with or a RegExp to test against the field
25124 * @param {Boolean} anyMatch True to match any part not just the beginning
25126 filter : function(property, value, anyMatch){
25127 var fn = this.createFilterFn(property, value, anyMatch);
25128 return fn ? this.filterBy(fn) : this.clearFilter();
25132 * Filter by a function. The specified function will be called with each
25133 * record in this data source. If the function returns true the record is included,
25134 * otherwise it is filtered.
25135 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
25136 * @param {Object} scope (optional) The scope of the function (defaults to this)
25138 filterBy : function(fn, scope){
25139 this.snapshot = this.snapshot || this.data;
25140 this.data = this.queryBy(fn, scope||this);
25141 this.fireEvent("datachanged", this);
25145 * Query the records by a specified property.
25146 * @param {String} field A field on your records
25147 * @param {String/RegExp} value Either a string that the field
25148 * should start with or a RegExp to test against the field
25149 * @param {Boolean} anyMatch True to match any part not just the beginning
25150 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
25152 query : function(property, value, anyMatch){
25153 var fn = this.createFilterFn(property, value, anyMatch);
25154 return fn ? this.queryBy(fn) : this.data.clone();
25158 * Query by a function. The specified function will be called with each
25159 * record in this data source. If the function returns true the record is included
25161 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
25162 * @param {Object} scope (optional) The scope of the function (defaults to this)
25163 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
25165 queryBy : function(fn, scope){
25166 var data = this.snapshot || this.data;
25167 return data.filterBy(fn, scope||this);
25171 * Collects unique values for a particular dataIndex from this store.
25172 * @param {String} dataIndex The property to collect
25173 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
25174 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
25175 * @return {Array} An array of the unique values
25177 collect : function(dataIndex, allowNull, bypassFilter){
25178 var d = (bypassFilter === true && this.snapshot) ?
25179 this.snapshot.items : this.data.items;
25180 var v, sv, r = [], l = {};
25181 for(var i = 0, len = d.length; i < len; i++){
25182 v = d[i].data[dataIndex];
25184 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
25193 * Revert to a view of the Record cache with no filtering applied.
25194 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
25196 clearFilter : function(suppressEvent){
25197 if(this.snapshot && this.snapshot != this.data){
25198 this.data = this.snapshot;
25199 delete this.snapshot;
25200 if(suppressEvent !== true){
25201 this.fireEvent("datachanged", this);
25207 afterEdit : function(record){
25208 if(this.modified.indexOf(record) == -1){
25209 this.modified.push(record);
25211 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
25215 afterReject : function(record){
25216 this.modified.remove(record);
25217 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
25221 afterCommit : function(record){
25222 this.modified.remove(record);
25223 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
25227 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
25228 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
25230 commitChanges : function(){
25231 var m = this.modified.slice(0);
25232 this.modified = [];
25233 for(var i = 0, len = m.length; i < len; i++){
25239 * Cancel outstanding changes on all changed records.
25241 rejectChanges : function(){
25242 var m = this.modified.slice(0);
25243 this.modified = [];
25244 for(var i = 0, len = m.length; i < len; i++){
25249 onMetaChange : function(meta, rtype, o){
25250 this.recordType = rtype;
25251 this.fields = rtype.prototype.fields;
25252 delete this.snapshot;
25253 this.sortInfo = meta.sortInfo || this.sortInfo;
25254 this.modified = [];
25255 this.fireEvent('metachange', this, this.reader.meta);
25258 moveIndex : function(data, type)
25260 var index = this.indexOf(data);
25262 var newIndex = index + type;
25266 this.insert(newIndex, data);
25271 * Ext JS Library 1.1.1
25272 * Copyright(c) 2006-2007, Ext JS, LLC.
25274 * Originally Released Under LGPL - original licence link has changed is not relivant.
25277 * <script type="text/javascript">
25281 * @class Roo.data.SimpleStore
25282 * @extends Roo.data.Store
25283 * Small helper class to make creating Stores from Array data easier.
25284 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
25285 * @cfg {Array} fields An array of field definition objects, or field name strings.
25286 * @cfg {Object} an existing reader (eg. copied from another store)
25287 * @cfg {Array} data The multi-dimensional array of data
25288 * @cfg {Roo.data.DataProxy} proxy [not-required]
25289 * @cfg {Roo.data.Reader} reader [not-required]
25291 * @param {Object} config
25293 Roo.data.SimpleStore = function(config)
25295 Roo.data.SimpleStore.superclass.constructor.call(this, {
25297 reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
25300 Roo.data.Record.create(config.fields)
25302 proxy : new Roo.data.MemoryProxy(config.data)
25306 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
25308 * Ext JS Library 1.1.1
25309 * Copyright(c) 2006-2007, Ext JS, LLC.
25311 * Originally Released Under LGPL - original licence link has changed is not relivant.
25314 * <script type="text/javascript">
25319 * @extends Roo.data.Store
25320 * @class Roo.data.JsonStore
25321 * Small helper class to make creating Stores for JSON data easier. <br/>
25323 var store = new Roo.data.JsonStore({
25324 url: 'get-images.php',
25326 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
25329 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
25330 * JsonReader and HttpProxy (unless inline data is provided).</b>
25331 * @cfg {Array} fields An array of field definition objects, or field name strings.
25333 * @param {Object} config
25335 Roo.data.JsonStore = function(c){
25336 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
25337 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
25338 reader: new Roo.data.JsonReader(c, c.fields)
25341 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
25343 * Ext JS Library 1.1.1
25344 * Copyright(c) 2006-2007, Ext JS, LLC.
25346 * Originally Released Under LGPL - original licence link has changed is not relivant.
25349 * <script type="text/javascript">
25353 Roo.data.Field = function(config){
25354 if(typeof config == "string"){
25355 config = {name: config};
25357 Roo.apply(this, config);
25360 this.type = "auto";
25363 var st = Roo.data.SortTypes;
25364 // named sortTypes are supported, here we look them up
25365 if(typeof this.sortType == "string"){
25366 this.sortType = st[this.sortType];
25369 // set default sortType for strings and dates
25370 if(!this.sortType){
25373 this.sortType = st.asUCString;
25376 this.sortType = st.asDate;
25379 this.sortType = st.none;
25384 var stripRe = /[\$,%]/g;
25386 // prebuilt conversion function for this field, instead of
25387 // switching every time we're reading a value
25389 var cv, dateFormat = this.dateFormat;
25394 cv = function(v){ return v; };
25397 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
25401 return v !== undefined && v !== null && v !== '' ?
25402 parseInt(String(v).replace(stripRe, ""), 10) : '';
25407 return v !== undefined && v !== null && v !== '' ?
25408 parseFloat(String(v).replace(stripRe, ""), 10) : '';
25413 cv = function(v){ return v === true || v === "true" || v == 1; };
25420 if(v instanceof Date){
25424 if(dateFormat == "timestamp"){
25425 return new Date(v*1000);
25427 return Date.parseDate(v, dateFormat);
25429 var parsed = Date.parse(v);
25430 return parsed ? new Date(parsed) : null;
25439 Roo.data.Field.prototype = {
25447 * Ext JS Library 1.1.1
25448 * Copyright(c) 2006-2007, Ext JS, LLC.
25450 * Originally Released Under LGPL - original licence link has changed is not relivant.
25453 * <script type="text/javascript">
25456 // Base class for reading structured data from a data source. This class is intended to be
25457 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
25460 * @class Roo.data.DataReader
25462 * Base class for reading structured data from a data source. This class is intended to be
25463 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
25466 Roo.data.DataReader = function(meta, recordType){
25470 this.recordType = recordType instanceof Array ?
25471 Roo.data.Record.create(recordType) : recordType;
25474 Roo.data.DataReader.prototype = {
25477 readerType : 'Data',
25479 * Create an empty record
25480 * @param {Object} data (optional) - overlay some values
25481 * @return {Roo.data.Record} record created.
25483 newRow : function(d) {
25485 this.recordType.prototype.fields.each(function(c) {
25487 case 'int' : da[c.name] = 0; break;
25488 case 'date' : da[c.name] = new Date(); break;
25489 case 'float' : da[c.name] = 0.0; break;
25490 case 'boolean' : da[c.name] = false; break;
25491 default : da[c.name] = ""; break;
25495 return new this.recordType(Roo.apply(da, d));
25501 * Ext JS Library 1.1.1
25502 * Copyright(c) 2006-2007, Ext JS, LLC.
25504 * Originally Released Under LGPL - original licence link has changed is not relivant.
25507 * <script type="text/javascript">
25511 * @class Roo.data.DataProxy
25512 * @extends Roo.util.Observable
25514 * This class is an abstract base class for implementations which provide retrieval of
25515 * unformatted data objects.<br>
25517 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
25518 * (of the appropriate type which knows how to parse the data object) to provide a block of
25519 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
25521 * Custom implementations must implement the load method as described in
25522 * {@link Roo.data.HttpProxy#load}.
25524 Roo.data.DataProxy = function(){
25527 * @event beforeload
25528 * Fires before a network request is made to retrieve a data object.
25529 * @param {Object} This DataProxy object.
25530 * @param {Object} params The params parameter to the load function.
25535 * Fires before the load method's callback is called.
25536 * @param {Object} This DataProxy object.
25537 * @param {Object} o The data object.
25538 * @param {Object} arg The callback argument object passed to the load function.
25542 * @event loadexception
25543 * Fires if an Exception occurs during data retrieval.
25544 * @param {Object} This DataProxy object.
25545 * @param {Object} o The data object.
25546 * @param {Object} arg The callback argument object passed to the load function.
25547 * @param {Object} e The Exception.
25549 loadexception : true
25551 Roo.data.DataProxy.superclass.constructor.call(this);
25554 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
25557 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
25561 * Ext JS Library 1.1.1
25562 * Copyright(c) 2006-2007, Ext JS, LLC.
25564 * Originally Released Under LGPL - original licence link has changed is not relivant.
25567 * <script type="text/javascript">
25570 * @class Roo.data.MemoryProxy
25571 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
25572 * to the Reader when its load method is called.
25574 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
25576 Roo.data.MemoryProxy = function(data){
25580 Roo.data.MemoryProxy.superclass.constructor.call(this);
25584 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
25587 * Load data from the requested source (in this case an in-memory
25588 * data object passed to the constructor), read the data object into
25589 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
25590 * process that block using the passed callback.
25591 * @param {Object} params This parameter is not used by the MemoryProxy class.
25592 * @param {Roo.data.DataReader} reader The Reader object which converts the data
25593 * object into a block of Roo.data.Records.
25594 * @param {Function} callback The function into which to pass the block of Roo.data.records.
25595 * The function must be passed <ul>
25596 * <li>The Record block object</li>
25597 * <li>The "arg" argument from the load function</li>
25598 * <li>A boolean success indicator</li>
25600 * @param {Object} scope The scope in which to call the callback
25601 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
25603 load : function(params, reader, callback, scope, arg){
25604 params = params || {};
25607 result = reader.readRecords(params.data ? params.data :this.data);
25609 this.fireEvent("loadexception", this, arg, null, e);
25610 callback.call(scope, null, arg, false);
25613 callback.call(scope, result, arg, true);
25617 update : function(params, records){
25622 * Ext JS Library 1.1.1
25623 * Copyright(c) 2006-2007, Ext JS, LLC.
25625 * Originally Released Under LGPL - original licence link has changed is not relivant.
25628 * <script type="text/javascript">
25631 * @class Roo.data.HttpProxy
25632 * @extends Roo.data.DataProxy
25633 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
25634 * configured to reference a certain URL.<br><br>
25636 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
25637 * from which the running page was served.<br><br>
25639 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
25641 * Be aware that to enable the browser to parse an XML document, the server must set
25642 * the Content-Type header in the HTTP response to "text/xml".
25644 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
25645 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
25646 * will be used to make the request.
25648 Roo.data.HttpProxy = function(conn){
25649 Roo.data.HttpProxy.superclass.constructor.call(this);
25650 // is conn a conn config or a real conn?
25652 this.useAjax = !conn || !conn.events;
25656 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
25657 // thse are take from connection...
25660 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
25663 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
25664 * extra parameters to each request made by this object. (defaults to undefined)
25667 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
25668 * to each request made by this object. (defaults to undefined)
25671 * @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)
25674 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
25677 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
25683 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
25687 * Return the {@link Roo.data.Connection} object being used by this Proxy.
25688 * @return {Connection} The Connection object. This object may be used to subscribe to events on
25689 * a finer-grained basis than the DataProxy events.
25691 getConnection : function(){
25692 return this.useAjax ? Roo.Ajax : this.conn;
25696 * Load data from the configured {@link Roo.data.Connection}, read the data object into
25697 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
25698 * process that block using the passed callback.
25699 * @param {Object} params An object containing properties which are to be used as HTTP parameters
25700 * for the request to the remote server.
25701 * @param {Roo.data.DataReader} reader The Reader object which converts the data
25702 * object into a block of Roo.data.Records.
25703 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
25704 * The function must be passed <ul>
25705 * <li>The Record block object</li>
25706 * <li>The "arg" argument from the load function</li>
25707 * <li>A boolean success indicator</li>
25709 * @param {Object} scope The scope in which to call the callback
25710 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
25712 load : function(params, reader, callback, scope, arg){
25713 if(this.fireEvent("beforeload", this, params) !== false){
25715 params : params || {},
25717 callback : callback,
25722 callback : this.loadResponse,
25726 Roo.applyIf(o, this.conn);
25727 if(this.activeRequest){
25728 Roo.Ajax.abort(this.activeRequest);
25730 this.activeRequest = Roo.Ajax.request(o);
25732 this.conn.request(o);
25735 callback.call(scope||this, null, arg, false);
25740 loadResponse : function(o, success, response){
25741 delete this.activeRequest;
25743 this.fireEvent("loadexception", this, o, response);
25744 o.request.callback.call(o.request.scope, null, o.request.arg, false);
25749 result = o.reader.read(response);
25752 o.raw = { errorMsg : response.responseText };
25753 this.fireEvent("loadexception", this, o, response, e);
25754 o.request.callback.call(o.request.scope, o, o.request.arg, false);
25758 this.fireEvent("load", this, o, o.request.arg);
25759 o.request.callback.call(o.request.scope, result, o.request.arg, true);
25763 update : function(dataSet){
25768 updateResponse : function(dataSet){
25773 * Ext JS Library 1.1.1
25774 * Copyright(c) 2006-2007, Ext JS, LLC.
25776 * Originally Released Under LGPL - original licence link has changed is not relivant.
25779 * <script type="text/javascript">
25783 * @class Roo.data.ScriptTagProxy
25784 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
25785 * other than the originating domain of the running page.<br><br>
25787 * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
25788 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
25790 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
25791 * source code that is used as the source inside a <script> tag.<br><br>
25793 * In order for the browser to process the returned data, the server must wrap the data object
25794 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
25795 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
25796 * depending on whether the callback name was passed:
25799 boolean scriptTag = false;
25800 String cb = request.getParameter("callback");
25803 response.setContentType("text/javascript");
25805 response.setContentType("application/x-json");
25807 Writer out = response.getWriter();
25809 out.write(cb + "(");
25811 out.print(dataBlock.toJsonString());
25818 * @param {Object} config A configuration object.
25820 Roo.data.ScriptTagProxy = function(config){
25821 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
25822 Roo.apply(this, config);
25823 this.head = document.getElementsByTagName("head")[0];
25826 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
25828 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
25830 * @cfg {String} url The URL from which to request the data object.
25833 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
25837 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
25838 * the server the name of the callback function set up by the load call to process the returned data object.
25839 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
25840 * javascript output which calls this named function passing the data object as its only parameter.
25842 callbackParam : "callback",
25844 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
25845 * name to the request.
25850 * Load data from the configured URL, read the data object into
25851 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
25852 * process that block using the passed callback.
25853 * @param {Object} params An object containing properties which are to be used as HTTP parameters
25854 * for the request to the remote server.
25855 * @param {Roo.data.DataReader} reader The Reader object which converts the data
25856 * object into a block of Roo.data.Records.
25857 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
25858 * The function must be passed <ul>
25859 * <li>The Record block object</li>
25860 * <li>The "arg" argument from the load function</li>
25861 * <li>A boolean success indicator</li>
25863 * @param {Object} scope The scope in which to call the callback
25864 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
25866 load : function(params, reader, callback, scope, arg){
25867 if(this.fireEvent("beforeload", this, params) !== false){
25869 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
25871 var url = this.url;
25872 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
25874 url += "&_dc=" + (new Date().getTime());
25876 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
25879 cb : "stcCallback"+transId,
25880 scriptId : "stcScript"+transId,
25884 callback : callback,
25890 window[trans.cb] = function(o){
25891 conn.handleResponse(o, trans);
25894 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
25896 if(this.autoAbort !== false){
25900 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
25902 var script = document.createElement("script");
25903 script.setAttribute("src", url);
25904 script.setAttribute("type", "text/javascript");
25905 script.setAttribute("id", trans.scriptId);
25906 this.head.appendChild(script);
25908 this.trans = trans;
25910 callback.call(scope||this, null, arg, false);
25915 isLoading : function(){
25916 return this.trans ? true : false;
25920 * Abort the current server request.
25922 abort : function(){
25923 if(this.isLoading()){
25924 this.destroyTrans(this.trans);
25929 destroyTrans : function(trans, isLoaded){
25930 this.head.removeChild(document.getElementById(trans.scriptId));
25931 clearTimeout(trans.timeoutId);
25933 window[trans.cb] = undefined;
25935 delete window[trans.cb];
25938 // if hasn't been loaded, wait for load to remove it to prevent script error
25939 window[trans.cb] = function(){
25940 window[trans.cb] = undefined;
25942 delete window[trans.cb];
25949 handleResponse : function(o, trans){
25950 this.trans = false;
25951 this.destroyTrans(trans, true);
25954 result = trans.reader.readRecords(o);
25956 this.fireEvent("loadexception", this, o, trans.arg, e);
25957 trans.callback.call(trans.scope||window, null, trans.arg, false);
25960 this.fireEvent("load", this, o, trans.arg);
25961 trans.callback.call(trans.scope||window, result, trans.arg, true);
25965 handleFailure : function(trans){
25966 this.trans = false;
25967 this.destroyTrans(trans, false);
25968 this.fireEvent("loadexception", this, null, trans.arg);
25969 trans.callback.call(trans.scope||window, null, trans.arg, false);
25973 * Ext JS Library 1.1.1
25974 * Copyright(c) 2006-2007, Ext JS, LLC.
25976 * Originally Released Under LGPL - original licence link has changed is not relivant.
25979 * <script type="text/javascript">
25983 * @class Roo.data.JsonReader
25984 * @extends Roo.data.DataReader
25985 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
25986 * based on mappings in a provided Roo.data.Record constructor.
25988 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
25989 * in the reply previously.
25994 var RecordDef = Roo.data.Record.create([
25995 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
25996 {name: 'occupation'} // This field will use "occupation" as the mapping.
25998 var myReader = new Roo.data.JsonReader({
25999 totalProperty: "results", // The property which contains the total dataset size (optional)
26000 root: "rows", // The property which contains an Array of row objects
26001 id: "id" // The property within each row object that provides an ID for the record (optional)
26005 * This would consume a JSON file like this:
26007 { 'results': 2, 'rows': [
26008 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
26009 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
26012 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
26013 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
26014 * paged from the remote server.
26015 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
26016 * @cfg {String} root name of the property which contains the Array of row objects.
26017 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
26018 * @cfg {Array} fields Array of field definition objects
26020 * Create a new JsonReader
26021 * @param {Object} meta Metadata configuration options
26022 * @param {Object} recordType Either an Array of field definition objects,
26023 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
26025 Roo.data.JsonReader = function(meta, recordType){
26028 // set some defaults:
26029 Roo.applyIf(meta, {
26030 totalProperty: 'total',
26031 successProperty : 'success',
26036 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
26038 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
26040 readerType : 'Json',
26043 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
26044 * Used by Store query builder to append _requestMeta to params.
26047 metaFromRemote : false,
26049 * This method is only used by a DataProxy which has retrieved data from a remote server.
26050 * @param {Object} response The XHR object which contains the JSON data in its responseText.
26051 * @return {Object} data A data block which is used by an Roo.data.Store object as
26052 * a cache of Roo.data.Records.
26054 read : function(response){
26055 var json = response.responseText;
26057 var o = /* eval:var:o */ eval("("+json+")");
26059 throw {message: "JsonReader.read: Json object not found"};
26065 this.metaFromRemote = true;
26066 this.meta = o.metaData;
26067 this.recordType = Roo.data.Record.create(o.metaData.fields);
26068 this.onMetaChange(this.meta, this.recordType, o);
26070 return this.readRecords(o);
26073 // private function a store will implement
26074 onMetaChange : function(meta, recordType, o){
26081 simpleAccess: function(obj, subsc) {
26088 getJsonAccessor: function(){
26090 return function(expr) {
26092 return(re.test(expr))
26093 ? new Function("obj", "return obj." + expr)
26098 return Roo.emptyFn;
26103 * Create a data block containing Roo.data.Records from an XML document.
26104 * @param {Object} o An object which contains an Array of row objects in the property specified
26105 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
26106 * which contains the total size of the dataset.
26107 * @return {Object} data A data block which is used by an Roo.data.Store object as
26108 * a cache of Roo.data.Records.
26110 readRecords : function(o){
26112 * After any data loads, the raw JSON data is available for further custom processing.
26116 var s = this.meta, Record = this.recordType,
26117 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
26119 // Generate extraction functions for the totalProperty, the root, the id, and for each field
26121 if(s.totalProperty) {
26122 this.getTotal = this.getJsonAccessor(s.totalProperty);
26124 if(s.successProperty) {
26125 this.getSuccess = this.getJsonAccessor(s.successProperty);
26127 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
26129 var g = this.getJsonAccessor(s.id);
26130 this.getId = function(rec) {
26132 return (r === undefined || r === "") ? null : r;
26135 this.getId = function(){return null;};
26138 for(var jj = 0; jj < fl; jj++){
26140 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
26141 this.ef[jj] = this.getJsonAccessor(map);
26145 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
26146 if(s.totalProperty){
26147 var vt = parseInt(this.getTotal(o), 10);
26152 if(s.successProperty){
26153 var vs = this.getSuccess(o);
26154 if(vs === false || vs === 'false'){
26159 for(var i = 0; i < c; i++){
26162 var id = this.getId(n);
26163 for(var j = 0; j < fl; j++){
26165 var v = this.ef[j](n);
26167 Roo.log('missing convert for ' + f.name);
26171 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
26175 raw : { errorMsg : "JSON Reader Error: fields or metadata not available to create Record" },
26181 var record = new Record(values, id);
26183 records[i] = record;
26189 totalRecords : totalRecords
26192 // used when loading children.. @see loadDataFromChildren
26193 toLoadData: function(rec)
26195 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
26196 var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
26197 return { data : data, total : data.length };
26202 * Ext JS Library 1.1.1
26203 * Copyright(c) 2006-2007, Ext JS, LLC.
26205 * Originally Released Under LGPL - original licence link has changed is not relivant.
26208 * <script type="text/javascript">
26212 * @class Roo.data.XmlReader
26213 * @extends Roo.data.DataReader
26214 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
26215 * based on mappings in a provided Roo.data.Record constructor.<br><br>
26217 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
26218 * header in the HTTP response must be set to "text/xml".</em>
26222 var RecordDef = Roo.data.Record.create([
26223 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
26224 {name: 'occupation'} // This field will use "occupation" as the mapping.
26226 var myReader = new Roo.data.XmlReader({
26227 totalRecords: "results", // The element which contains the total dataset size (optional)
26228 record: "row", // The repeated element which contains row information
26229 id: "id" // The element within the row that provides an ID for the record (optional)
26233 * This would consume an XML file like this:
26237 <results>2</results>
26240 <name>Bill</name>
26241 <occupation>Gardener</occupation>
26245 <name>Ben</name>
26246 <occupation>Horticulturalist</occupation>
26250 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
26251 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
26252 * paged from the remote server.
26253 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
26254 * @cfg {String} success The DomQuery path to the success attribute used by forms.
26255 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
26256 * a record identifier value.
26258 * Create a new XmlReader
26259 * @param {Object} meta Metadata configuration options
26260 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
26261 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
26262 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
26264 Roo.data.XmlReader = function(meta, recordType){
26266 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
26268 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
26270 readerType : 'Xml',
26273 * This method is only used by a DataProxy which has retrieved data from a remote server.
26274 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
26275 * to contain a method called 'responseXML' that returns an XML document object.
26276 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
26277 * a cache of Roo.data.Records.
26279 read : function(response){
26280 var doc = response.responseXML;
26282 throw {message: "XmlReader.read: XML Document not available"};
26284 return this.readRecords(doc);
26288 * Create a data block containing Roo.data.Records from an XML document.
26289 * @param {Object} doc A parsed XML document.
26290 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
26291 * a cache of Roo.data.Records.
26293 readRecords : function(doc){
26295 * After any data loads/reads, the raw XML Document is available for further custom processing.
26296 * @type XMLDocument
26298 this.xmlData = doc;
26299 var root = doc.documentElement || doc;
26300 var q = Roo.DomQuery;
26301 var recordType = this.recordType, fields = recordType.prototype.fields;
26302 var sid = this.meta.id;
26303 var totalRecords = 0, success = true;
26304 if(this.meta.totalRecords){
26305 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
26308 if(this.meta.success){
26309 var sv = q.selectValue(this.meta.success, root, true);
26310 success = sv !== false && sv !== 'false';
26313 var ns = q.select(this.meta.record, root);
26314 for(var i = 0, len = ns.length; i < len; i++) {
26317 var id = sid ? q.selectValue(sid, n) : undefined;
26318 for(var j = 0, jlen = fields.length; j < jlen; j++){
26319 var f = fields.items[j];
26320 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
26322 values[f.name] = v;
26324 var record = new recordType(values, id);
26326 records[records.length] = record;
26332 totalRecords : totalRecords || records.length
26337 * Ext JS Library 1.1.1
26338 * Copyright(c) 2006-2007, Ext JS, LLC.
26340 * Originally Released Under LGPL - original licence link has changed is not relivant.
26343 * <script type="text/javascript">
26347 * @class Roo.data.ArrayReader
26348 * @extends Roo.data.DataReader
26349 * Data reader class to create an Array of Roo.data.Record objects from an Array.
26350 * Each element of that Array represents a row of data fields. The
26351 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
26352 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
26356 var RecordDef = Roo.data.Record.create([
26357 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
26358 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
26360 var myReader = new Roo.data.ArrayReader({
26361 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
26365 * This would consume an Array like this:
26367 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
26371 * Create a new JsonReader
26372 * @param {Object} meta Metadata configuration options.
26373 * @param {Object|Array} recordType Either an Array of field definition objects
26375 * @cfg {Array} fields Array of field definition objects
26376 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
26377 * as specified to {@link Roo.data.Record#create},
26378 * or an {@link Roo.data.Record} object
26381 * created using {@link Roo.data.Record#create}.
26383 Roo.data.ArrayReader = function(meta, recordType)
26385 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
26388 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
26391 * Create a data block containing Roo.data.Records from an XML document.
26392 * @param {Object} o An Array of row objects which represents the dataset.
26393 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
26394 * a cache of Roo.data.Records.
26396 readRecords : function(o)
26398 var sid = this.meta ? this.meta.id : null;
26399 var recordType = this.recordType, fields = recordType.prototype.fields;
26402 for(var i = 0; i < root.length; i++){
26405 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
26406 for(var j = 0, jlen = fields.length; j < jlen; j++){
26407 var f = fields.items[j];
26408 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
26409 var v = n[k] !== undefined ? n[k] : f.defaultValue;
26411 values[f.name] = v;
26413 var record = new recordType(values, id);
26415 records[records.length] = record;
26419 totalRecords : records.length
26422 // used when loading children.. @see loadDataFromChildren
26423 toLoadData: function(rec)
26425 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
26426 return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
26433 * Ext JS Library 1.1.1
26434 * Copyright(c) 2006-2007, Ext JS, LLC.
26436 * Originally Released Under LGPL - original licence link has changed is not relivant.
26439 * <script type="text/javascript">
26444 * @class Roo.data.Tree
26445 * @extends Roo.util.Observable
26446 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
26447 * in the tree have most standard DOM functionality.
26449 * @param {Node} root (optional) The root node
26451 Roo.data.Tree = function(root){
26452 this.nodeHash = {};
26454 * The root node for this tree
26459 this.setRootNode(root);
26464 * Fires when a new child node is appended to a node in this tree.
26465 * @param {Tree} tree The owner tree
26466 * @param {Node} parent The parent node
26467 * @param {Node} node The newly appended node
26468 * @param {Number} index The index of the newly appended node
26473 * Fires when a child node is removed from a node in this tree.
26474 * @param {Tree} tree The owner tree
26475 * @param {Node} parent The parent node
26476 * @param {Node} node The child node removed
26481 * Fires when a node is moved to a new location in the tree
26482 * @param {Tree} tree The owner tree
26483 * @param {Node} node The node moved
26484 * @param {Node} oldParent The old parent of this node
26485 * @param {Node} newParent The new parent of this node
26486 * @param {Number} index The index it was moved to
26491 * Fires when a new child node is inserted in a node in this tree.
26492 * @param {Tree} tree The owner tree
26493 * @param {Node} parent The parent node
26494 * @param {Node} node The child node inserted
26495 * @param {Node} refNode The child node the node was inserted before
26499 * @event beforeappend
26500 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
26501 * @param {Tree} tree The owner tree
26502 * @param {Node} parent The parent node
26503 * @param {Node} node The child node to be appended
26505 "beforeappend" : true,
26507 * @event beforeremove
26508 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
26509 * @param {Tree} tree The owner tree
26510 * @param {Node} parent The parent node
26511 * @param {Node} node The child node to be removed
26513 "beforeremove" : true,
26515 * @event beforemove
26516 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
26517 * @param {Tree} tree The owner tree
26518 * @param {Node} node The node being moved
26519 * @param {Node} oldParent The parent of the node
26520 * @param {Node} newParent The new parent the node is moving to
26521 * @param {Number} index The index it is being moved to
26523 "beforemove" : true,
26525 * @event beforeinsert
26526 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
26527 * @param {Tree} tree The owner tree
26528 * @param {Node} parent The parent node
26529 * @param {Node} node The child node to be inserted
26530 * @param {Node} refNode The child node the node is being inserted before
26532 "beforeinsert" : true
26535 Roo.data.Tree.superclass.constructor.call(this);
26538 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
26539 pathSeparator: "/",
26541 proxyNodeEvent : function(){
26542 return this.fireEvent.apply(this, arguments);
26546 * Returns the root node for this tree.
26549 getRootNode : function(){
26554 * Sets the root node for this tree.
26555 * @param {Node} node
26558 setRootNode : function(node){
26560 node.ownerTree = this;
26561 node.isRoot = true;
26562 this.registerNode(node);
26567 * Gets a node in this tree by its id.
26568 * @param {String} id
26571 getNodeById : function(id){
26572 return this.nodeHash[id];
26575 registerNode : function(node){
26576 this.nodeHash[node.id] = node;
26579 unregisterNode : function(node){
26580 delete this.nodeHash[node.id];
26583 toString : function(){
26584 return "[Tree"+(this.id?" "+this.id:"")+"]";
26589 * @class Roo.data.Node
26590 * @extends Roo.util.Observable
26591 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
26592 * @cfg {String} id The id for this node. If one is not specified, one is generated.
26594 * @param {Object} attributes The attributes/config for the node
26596 Roo.data.Node = function(attributes){
26598 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
26601 this.attributes = attributes || {};
26602 this.leaf = this.attributes.leaf;
26604 * The node id. @type String
26606 this.id = this.attributes.id;
26608 this.id = Roo.id(null, "ynode-");
26609 this.attributes.id = this.id;
26614 * All child nodes of this node. @type Array
26616 this.childNodes = [];
26617 if(!this.childNodes.indexOf){ // indexOf is a must
26618 this.childNodes.indexOf = function(o){
26619 for(var i = 0, len = this.length; i < len; i++){
26628 * The parent node for this node. @type Node
26630 this.parentNode = null;
26632 * The first direct child node of this node, or null if this node has no child nodes. @type Node
26634 this.firstChild = null;
26636 * The last direct child node of this node, or null if this node has no child nodes. @type Node
26638 this.lastChild = null;
26640 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
26642 this.previousSibling = null;
26644 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
26646 this.nextSibling = null;
26651 * Fires when a new child node is appended
26652 * @param {Tree} tree The owner tree
26653 * @param {Node} this This node
26654 * @param {Node} node The newly appended node
26655 * @param {Number} index The index of the newly appended node
26660 * Fires when a child node is removed
26661 * @param {Tree} tree The owner tree
26662 * @param {Node} this This node
26663 * @param {Node} node The removed node
26668 * Fires when this node is moved to a new location in the tree
26669 * @param {Tree} tree The owner tree
26670 * @param {Node} this This node
26671 * @param {Node} oldParent The old parent of this node
26672 * @param {Node} newParent The new parent of this node
26673 * @param {Number} index The index it was moved to
26678 * Fires when a new child node is inserted.
26679 * @param {Tree} tree The owner tree
26680 * @param {Node} this This node
26681 * @param {Node} node The child node inserted
26682 * @param {Node} refNode The child node the node was inserted before
26686 * @event beforeappend
26687 * Fires before a new child is appended, return false to cancel the append.
26688 * @param {Tree} tree The owner tree
26689 * @param {Node} this This node
26690 * @param {Node} node The child node to be appended
26692 "beforeappend" : true,
26694 * @event beforeremove
26695 * Fires before a child is removed, return false to cancel the remove.
26696 * @param {Tree} tree The owner tree
26697 * @param {Node} this This node
26698 * @param {Node} node The child node to be removed
26700 "beforeremove" : true,
26702 * @event beforemove
26703 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
26704 * @param {Tree} tree The owner tree
26705 * @param {Node} this This node
26706 * @param {Node} oldParent The parent of this node
26707 * @param {Node} newParent The new parent this node is moving to
26708 * @param {Number} index The index it is being moved to
26710 "beforemove" : true,
26712 * @event beforeinsert
26713 * Fires before a new child is inserted, return false to cancel the insert.
26714 * @param {Tree} tree The owner tree
26715 * @param {Node} this This node
26716 * @param {Node} node The child node to be inserted
26717 * @param {Node} refNode The child node the node is being inserted before
26719 "beforeinsert" : true
26721 this.listeners = this.attributes.listeners;
26722 Roo.data.Node.superclass.constructor.call(this);
26725 Roo.extend(Roo.data.Node, Roo.util.Observable, {
26726 fireEvent : function(evtName){
26727 // first do standard event for this node
26728 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
26731 // then bubble it up to the tree if the event wasn't cancelled
26732 var ot = this.getOwnerTree();
26734 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
26742 * Returns true if this node is a leaf
26743 * @return {Boolean}
26745 isLeaf : function(){
26746 return this.leaf === true;
26750 setFirstChild : function(node){
26751 this.firstChild = node;
26755 setLastChild : function(node){
26756 this.lastChild = node;
26761 * Returns true if this node is the last child of its parent
26762 * @return {Boolean}
26764 isLast : function(){
26765 return (!this.parentNode ? true : this.parentNode.lastChild == this);
26769 * Returns true if this node is the first child of its parent
26770 * @return {Boolean}
26772 isFirst : function(){
26773 return (!this.parentNode ? true : this.parentNode.firstChild == this);
26776 hasChildNodes : function(){
26777 return !this.isLeaf() && this.childNodes.length > 0;
26781 * Insert node(s) as the last child node of this node.
26782 * @param {Node/Array} node The node or Array of nodes to append
26783 * @return {Node} The appended node if single append, or null if an array was passed
26785 appendChild : function(node){
26787 if(node instanceof Array){
26789 }else if(arguments.length > 1){
26793 // if passed an array or multiple args do them one by one
26795 for(var i = 0, len = multi.length; i < len; i++) {
26796 this.appendChild(multi[i]);
26799 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
26802 var index = this.childNodes.length;
26803 var oldParent = node.parentNode;
26804 // it's a move, make sure we move it cleanly
26806 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
26809 oldParent.removeChild(node);
26812 index = this.childNodes.length;
26814 this.setFirstChild(node);
26816 this.childNodes.push(node);
26817 node.parentNode = this;
26818 var ps = this.childNodes[index-1];
26820 node.previousSibling = ps;
26821 ps.nextSibling = node;
26823 node.previousSibling = null;
26825 node.nextSibling = null;
26826 this.setLastChild(node);
26827 node.setOwnerTree(this.getOwnerTree());
26828 this.fireEvent("append", this.ownerTree, this, node, index);
26829 if(this.ownerTree) {
26830 this.ownerTree.fireEvent("appendnode", this, node, index);
26833 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
26840 * Removes a child node from this node.
26841 * @param {Node} node The node to remove
26842 * @return {Node} The removed node
26844 removeChild : function(node){
26845 var index = this.childNodes.indexOf(node);
26849 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
26853 // remove it from childNodes collection
26854 this.childNodes.splice(index, 1);
26857 if(node.previousSibling){
26858 node.previousSibling.nextSibling = node.nextSibling;
26860 if(node.nextSibling){
26861 node.nextSibling.previousSibling = node.previousSibling;
26864 // update child refs
26865 if(this.firstChild == node){
26866 this.setFirstChild(node.nextSibling);
26868 if(this.lastChild == node){
26869 this.setLastChild(node.previousSibling);
26872 node.setOwnerTree(null);
26873 // clear any references from the node
26874 node.parentNode = null;
26875 node.previousSibling = null;
26876 node.nextSibling = null;
26877 this.fireEvent("remove", this.ownerTree, this, node);
26882 * Inserts the first node before the second node in this nodes childNodes collection.
26883 * @param {Node} node The node to insert
26884 * @param {Node} refNode The node to insert before (if null the node is appended)
26885 * @return {Node} The inserted node
26887 insertBefore : function(node, refNode){
26888 if(!refNode){ // like standard Dom, refNode can be null for append
26889 return this.appendChild(node);
26892 if(node == refNode){
26896 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
26899 var index = this.childNodes.indexOf(refNode);
26900 var oldParent = node.parentNode;
26901 var refIndex = index;
26903 // when moving internally, indexes will change after remove
26904 if(oldParent == this && this.childNodes.indexOf(node) < index){
26908 // it's a move, make sure we move it cleanly
26910 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
26913 oldParent.removeChild(node);
26916 this.setFirstChild(node);
26918 this.childNodes.splice(refIndex, 0, node);
26919 node.parentNode = this;
26920 var ps = this.childNodes[refIndex-1];
26922 node.previousSibling = ps;
26923 ps.nextSibling = node;
26925 node.previousSibling = null;
26927 node.nextSibling = refNode;
26928 refNode.previousSibling = node;
26929 node.setOwnerTree(this.getOwnerTree());
26930 this.fireEvent("insert", this.ownerTree, this, node, refNode);
26932 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
26938 * Returns the child node at the specified index.
26939 * @param {Number} index
26942 item : function(index){
26943 return this.childNodes[index];
26947 * Replaces one child node in this node with another.
26948 * @param {Node} newChild The replacement node
26949 * @param {Node} oldChild The node to replace
26950 * @return {Node} The replaced node
26952 replaceChild : function(newChild, oldChild){
26953 this.insertBefore(newChild, oldChild);
26954 this.removeChild(oldChild);
26959 * Returns the index of a child node
26960 * @param {Node} node
26961 * @return {Number} The index of the node or -1 if it was not found
26963 indexOf : function(child){
26964 return this.childNodes.indexOf(child);
26968 * Returns the tree this node is in.
26971 getOwnerTree : function(){
26972 // if it doesn't have one, look for one
26973 if(!this.ownerTree){
26977 this.ownerTree = p.ownerTree;
26983 return this.ownerTree;
26987 * Returns depth of this node (the root node has a depth of 0)
26990 getDepth : function(){
26993 while(p.parentNode){
27001 setOwnerTree : function(tree){
27002 // if it's move, we need to update everyone
27003 if(tree != this.ownerTree){
27004 if(this.ownerTree){
27005 this.ownerTree.unregisterNode(this);
27007 this.ownerTree = tree;
27008 var cs = this.childNodes;
27009 for(var i = 0, len = cs.length; i < len; i++) {
27010 cs[i].setOwnerTree(tree);
27013 tree.registerNode(this);
27019 * Returns the path for this node. The path can be used to expand or select this node programmatically.
27020 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
27021 * @return {String} The path
27023 getPath : function(attr){
27024 attr = attr || "id";
27025 var p = this.parentNode;
27026 var b = [this.attributes[attr]];
27028 b.unshift(p.attributes[attr]);
27031 var sep = this.getOwnerTree().pathSeparator;
27032 return sep + b.join(sep);
27036 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
27037 * function call will be the scope provided or the current node. The arguments to the function
27038 * will be the args provided or the current node. If the function returns false at any point,
27039 * the bubble is stopped.
27040 * @param {Function} fn The function to call
27041 * @param {Object} scope (optional) The scope of the function (defaults to current node)
27042 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
27044 bubble : function(fn, scope, args){
27047 if(fn.call(scope || p, args || p) === false){
27055 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
27056 * function call will be the scope provided or the current node. The arguments to the function
27057 * will be the args provided or the current node. If the function returns false at any point,
27058 * the cascade is stopped on that branch.
27059 * @param {Function} fn The function to call
27060 * @param {Object} scope (optional) The scope of the function (defaults to current node)
27061 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
27063 cascade : function(fn, scope, args){
27064 if(fn.call(scope || this, args || this) !== false){
27065 var cs = this.childNodes;
27066 for(var i = 0, len = cs.length; i < len; i++) {
27067 cs[i].cascade(fn, scope, args);
27073 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
27074 * function call will be the scope provided or the current node. The arguments to the function
27075 * will be the args provided or the current node. If the function returns false at any point,
27076 * the iteration stops.
27077 * @param {Function} fn The function to call
27078 * @param {Object} scope (optional) The scope of the function (defaults to current node)
27079 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
27081 eachChild : function(fn, scope, args){
27082 var cs = this.childNodes;
27083 for(var i = 0, len = cs.length; i < len; i++) {
27084 if(fn.call(scope || this, args || cs[i]) === false){
27091 * Finds the first child that has the attribute with the specified value.
27092 * @param {String} attribute The attribute name
27093 * @param {Mixed} value The value to search for
27094 * @return {Node} The found child or null if none was found
27096 findChild : function(attribute, value){
27097 var cs = this.childNodes;
27098 for(var i = 0, len = cs.length; i < len; i++) {
27099 if(cs[i].attributes[attribute] == value){
27107 * Finds the first child by a custom function. The child matches if the function passed
27109 * @param {Function} fn
27110 * @param {Object} scope (optional)
27111 * @return {Node} The found child or null if none was found
27113 findChildBy : function(fn, scope){
27114 var cs = this.childNodes;
27115 for(var i = 0, len = cs.length; i < len; i++) {
27116 if(fn.call(scope||cs[i], cs[i]) === true){
27124 * Sorts this nodes children using the supplied sort function
27125 * @param {Function} fn
27126 * @param {Object} scope (optional)
27128 sort : function(fn, scope){
27129 var cs = this.childNodes;
27130 var len = cs.length;
27132 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
27134 for(var i = 0; i < len; i++){
27136 n.previousSibling = cs[i-1];
27137 n.nextSibling = cs[i+1];
27139 this.setFirstChild(n);
27142 this.setLastChild(n);
27149 * Returns true if this node is an ancestor (at any point) of the passed node.
27150 * @param {Node} node
27151 * @return {Boolean}
27153 contains : function(node){
27154 return node.isAncestor(this);
27158 * Returns true if the passed node is an ancestor (at any point) of this node.
27159 * @param {Node} node
27160 * @return {Boolean}
27162 isAncestor : function(node){
27163 var p = this.parentNode;
27173 toString : function(){
27174 return "[Node"+(this.id?" "+this.id:"")+"]";
27178 * Ext JS Library 1.1.1
27179 * Copyright(c) 2006-2007, Ext JS, LLC.
27181 * Originally Released Under LGPL - original licence link has changed is not relivant.
27184 * <script type="text/javascript">
27189 * @class Roo.Shadow
27190 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
27191 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
27192 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
27194 * Create a new Shadow
27195 * @param {Object} config The config object
27197 Roo.Shadow = function(config){
27198 Roo.apply(this, config);
27199 if(typeof this.mode != "string"){
27200 this.mode = this.defaultMode;
27202 var o = this.offset, a = {h: 0};
27203 var rad = Math.floor(this.offset/2);
27204 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
27210 a.l -= this.offset + rad;
27211 a.t -= this.offset + rad;
27222 a.l -= (this.offset - rad);
27223 a.t -= this.offset + rad;
27225 a.w -= (this.offset - rad)*2;
27236 a.l -= (this.offset - rad);
27237 a.t -= (this.offset - rad);
27239 a.w -= (this.offset + rad + 1);
27240 a.h -= (this.offset + rad);
27249 Roo.Shadow.prototype = {
27251 * @cfg {String} mode
27252 * The shadow display mode. Supports the following options:<br />
27253 * sides: Shadow displays on both sides and bottom only<br />
27254 * frame: Shadow displays equally on all four sides<br />
27255 * drop: Traditional bottom-right drop shadow (default)
27259 * @cfg {String} offset
27260 * The number of pixels to offset the shadow from the element (defaults to 4)
27265 defaultMode: "drop",
27268 * Displays the shadow under the target element
27269 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
27271 show : function(target){
27272 target = Roo.get(target);
27274 this.el = Roo.Shadow.Pool.pull();
27275 if(this.el.dom.nextSibling != target.dom){
27276 this.el.insertBefore(target);
27279 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
27281 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
27284 target.getLeft(true),
27285 target.getTop(true),
27289 this.el.dom.style.display = "block";
27293 * Returns true if the shadow is visible, else false
27295 isVisible : function(){
27296 return this.el ? true : false;
27300 * Direct alignment when values are already available. Show must be called at least once before
27301 * calling this method to ensure it is initialized.
27302 * @param {Number} left The target element left position
27303 * @param {Number} top The target element top position
27304 * @param {Number} width The target element width
27305 * @param {Number} height The target element height
27307 realign : function(l, t, w, h){
27311 var a = this.adjusts, d = this.el.dom, s = d.style;
27313 s.left = (l+a.l)+"px";
27314 s.top = (t+a.t)+"px";
27315 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
27317 if(s.width != sws || s.height != shs){
27321 var cn = d.childNodes;
27322 var sww = Math.max(0, (sw-12))+"px";
27323 cn[0].childNodes[1].style.width = sww;
27324 cn[1].childNodes[1].style.width = sww;
27325 cn[2].childNodes[1].style.width = sww;
27326 cn[1].style.height = Math.max(0, (sh-12))+"px";
27332 * Hides this shadow
27336 this.el.dom.style.display = "none";
27337 Roo.Shadow.Pool.push(this.el);
27343 * Adjust the z-index of this shadow
27344 * @param {Number} zindex The new z-index
27346 setZIndex : function(z){
27349 this.el.setStyle("z-index", z);
27354 // Private utility class that manages the internal Shadow cache
27355 Roo.Shadow.Pool = function(){
27357 var markup = Roo.isIE ?
27358 '<div class="x-ie-shadow"></div>' :
27359 '<div class="x-shadow"><div class="xst"><div class="xstl"></div><div class="xstc"></div><div class="xstr"></div></div><div class="xsc"><div class="xsml"></div><div class="xsmc"></div><div class="xsmr"></div></div><div class="xsb"><div class="xsbl"></div><div class="xsbc"></div><div class="xsbr"></div></div></div>';
27362 var sh = p.shift();
27364 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
27365 sh.autoBoxAdjust = false;
27370 push : function(sh){
27376 * Ext JS Library 1.1.1
27377 * Copyright(c) 2006-2007, Ext JS, LLC.
27379 * Originally Released Under LGPL - original licence link has changed is not relivant.
27382 * <script type="text/javascript">
27387 * @class Roo.SplitBar
27388 * @extends Roo.util.Observable
27389 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
27393 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
27394 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
27395 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
27396 split.minSize = 100;
27397 split.maxSize = 600;
27398 split.animate = true;
27399 split.on('moved', splitterMoved);
27402 * Create a new SplitBar
27403 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
27404 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
27405 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
27406 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
27407 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
27408 position of the SplitBar).
27410 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
27413 this.el = Roo.get(dragElement, true);
27414 this.el.dom.unselectable = "on";
27416 this.resizingEl = Roo.get(resizingElement, true);
27420 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
27421 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
27424 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
27427 * The minimum size of the resizing element. (Defaults to 0)
27433 * The maximum size of the resizing element. (Defaults to 2000)
27436 this.maxSize = 2000;
27439 * Whether to animate the transition to the new size
27442 this.animate = false;
27445 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
27448 this.useShim = false;
27453 if(!existingProxy){
27455 this.proxy = Roo.SplitBar.createProxy(this.orientation);
27457 this.proxy = Roo.get(existingProxy).dom;
27460 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
27463 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
27466 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
27469 this.dragSpecs = {};
27472 * @private The adapter to use to positon and resize elements
27474 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
27475 this.adapter.init(this);
27477 if(this.orientation == Roo.SplitBar.HORIZONTAL){
27479 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
27480 this.el.addClass("x-splitbar-h");
27483 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
27484 this.el.addClass("x-splitbar-v");
27490 * Fires when the splitter is moved (alias for {@link #event-moved})
27491 * @param {Roo.SplitBar} this
27492 * @param {Number} newSize the new width or height
27497 * Fires when the splitter is moved
27498 * @param {Roo.SplitBar} this
27499 * @param {Number} newSize the new width or height
27503 * @event beforeresize
27504 * Fires before the splitter is dragged
27505 * @param {Roo.SplitBar} this
27507 "beforeresize" : true,
27509 "beforeapply" : true
27512 Roo.util.Observable.call(this);
27515 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
27516 onStartProxyDrag : function(x, y){
27517 this.fireEvent("beforeresize", this);
27519 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
27521 o.enableDisplayMode("block");
27522 // all splitbars share the same overlay
27523 Roo.SplitBar.prototype.overlay = o;
27525 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27526 this.overlay.show();
27527 Roo.get(this.proxy).setDisplayed("block");
27528 var size = this.adapter.getElementSize(this);
27529 this.activeMinSize = this.getMinimumSize();;
27530 this.activeMaxSize = this.getMaximumSize();;
27531 var c1 = size - this.activeMinSize;
27532 var c2 = Math.max(this.activeMaxSize - size, 0);
27533 if(this.orientation == Roo.SplitBar.HORIZONTAL){
27534 this.dd.resetConstraints();
27535 this.dd.setXConstraint(
27536 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
27537 this.placement == Roo.SplitBar.LEFT ? c2 : c1
27539 this.dd.setYConstraint(0, 0);
27541 this.dd.resetConstraints();
27542 this.dd.setXConstraint(0, 0);
27543 this.dd.setYConstraint(
27544 this.placement == Roo.SplitBar.TOP ? c1 : c2,
27545 this.placement == Roo.SplitBar.TOP ? c2 : c1
27548 this.dragSpecs.startSize = size;
27549 this.dragSpecs.startPoint = [x, y];
27550 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
27554 * @private Called after the drag operation by the DDProxy
27556 onEndProxyDrag : function(e){
27557 Roo.get(this.proxy).setDisplayed(false);
27558 var endPoint = Roo.lib.Event.getXY(e);
27560 this.overlay.hide();
27563 if(this.orientation == Roo.SplitBar.HORIZONTAL){
27564 newSize = this.dragSpecs.startSize +
27565 (this.placement == Roo.SplitBar.LEFT ?
27566 endPoint[0] - this.dragSpecs.startPoint[0] :
27567 this.dragSpecs.startPoint[0] - endPoint[0]
27570 newSize = this.dragSpecs.startSize +
27571 (this.placement == Roo.SplitBar.TOP ?
27572 endPoint[1] - this.dragSpecs.startPoint[1] :
27573 this.dragSpecs.startPoint[1] - endPoint[1]
27576 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
27577 if(newSize != this.dragSpecs.startSize){
27578 if(this.fireEvent('beforeapply', this, newSize) !== false){
27579 this.adapter.setElementSize(this, newSize);
27580 this.fireEvent("moved", this, newSize);
27581 this.fireEvent("resize", this, newSize);
27587 * Get the adapter this SplitBar uses
27588 * @return The adapter object
27590 getAdapter : function(){
27591 return this.adapter;
27595 * Set the adapter this SplitBar uses
27596 * @param {Object} adapter A SplitBar adapter object
27598 setAdapter : function(adapter){
27599 this.adapter = adapter;
27600 this.adapter.init(this);
27604 * Gets the minimum size for the resizing element
27605 * @return {Number} The minimum size
27607 getMinimumSize : function(){
27608 return this.minSize;
27612 * Sets the minimum size for the resizing element
27613 * @param {Number} minSize The minimum size
27615 setMinimumSize : function(minSize){
27616 this.minSize = minSize;
27620 * Gets the maximum size for the resizing element
27621 * @return {Number} The maximum size
27623 getMaximumSize : function(){
27624 return this.maxSize;
27628 * Sets the maximum size for the resizing element
27629 * @param {Number} maxSize The maximum size
27631 setMaximumSize : function(maxSize){
27632 this.maxSize = maxSize;
27636 * Sets the initialize size for the resizing element
27637 * @param {Number} size The initial size
27639 setCurrentSize : function(size){
27640 var oldAnimate = this.animate;
27641 this.animate = false;
27642 this.adapter.setElementSize(this, size);
27643 this.animate = oldAnimate;
27647 * Destroy this splitbar.
27648 * @param {Boolean} removeEl True to remove the element
27650 destroy : function(removeEl){
27652 this.shim.remove();
27655 this.proxy.parentNode.removeChild(this.proxy);
27663 * @private static Create our own proxy element element. So it will be the same same size on all browsers, we won't use borders. Instead we use a background color.
27665 Roo.SplitBar.createProxy = function(dir){
27666 var proxy = new Roo.Element(document.createElement("div"));
27667 proxy.unselectable();
27668 var cls = 'x-splitbar-proxy';
27669 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
27670 document.body.appendChild(proxy.dom);
27675 * @class Roo.SplitBar.BasicLayoutAdapter
27676 * Default Adapter. It assumes the splitter and resizing element are not positioned
27677 * elements and only gets/sets the width of the element. Generally used for table based layouts.
27679 Roo.SplitBar.BasicLayoutAdapter = function(){
27682 Roo.SplitBar.BasicLayoutAdapter.prototype = {
27683 // do nothing for now
27684 init : function(s){
27688 * Called before drag operations to get the current size of the resizing element.
27689 * @param {Roo.SplitBar} s The SplitBar using this adapter
27691 getElementSize : function(s){
27692 if(s.orientation == Roo.SplitBar.HORIZONTAL){
27693 return s.resizingEl.getWidth();
27695 return s.resizingEl.getHeight();
27700 * Called after drag operations to set the size of the resizing element.
27701 * @param {Roo.SplitBar} s The SplitBar using this adapter
27702 * @param {Number} newSize The new size to set
27703 * @param {Function} onComplete A function to be invoked when resizing is complete
27705 setElementSize : function(s, newSize, onComplete){
27706 if(s.orientation == Roo.SplitBar.HORIZONTAL){
27708 s.resizingEl.setWidth(newSize);
27710 onComplete(s, newSize);
27713 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
27718 s.resizingEl.setHeight(newSize);
27720 onComplete(s, newSize);
27723 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
27730 *@class Roo.SplitBar.AbsoluteLayoutAdapter
27731 * @extends Roo.SplitBar.BasicLayoutAdapter
27732 * Adapter that moves the splitter element to align with the resized sizing element.
27733 * Used with an absolute positioned SplitBar.
27734 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
27735 * document.body, make sure you assign an id to the body element.
27737 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
27738 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
27739 this.container = Roo.get(container);
27742 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
27743 init : function(s){
27744 this.basic.init(s);
27747 getElementSize : function(s){
27748 return this.basic.getElementSize(s);
27751 setElementSize : function(s, newSize, onComplete){
27752 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
27755 moveSplitter : function(s){
27756 var yes = Roo.SplitBar;
27757 switch(s.placement){
27759 s.el.setX(s.resizingEl.getRight());
27762 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
27765 s.el.setY(s.resizingEl.getBottom());
27768 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
27775 * Orientation constant - Create a vertical SplitBar
27779 Roo.SplitBar.VERTICAL = 1;
27782 * Orientation constant - Create a horizontal SplitBar
27786 Roo.SplitBar.HORIZONTAL = 2;
27789 * Placement constant - The resizing element is to the left of the splitter element
27793 Roo.SplitBar.LEFT = 1;
27796 * Placement constant - The resizing element is to the right of the splitter element
27800 Roo.SplitBar.RIGHT = 2;
27803 * Placement constant - The resizing element is positioned above the splitter element
27807 Roo.SplitBar.TOP = 3;
27810 * Placement constant - The resizing element is positioned under splitter element
27814 Roo.SplitBar.BOTTOM = 4;
27817 * Ext JS Library 1.1.1
27818 * Copyright(c) 2006-2007, Ext JS, LLC.
27820 * Originally Released Under LGPL - original licence link has changed is not relivant.
27823 * <script type="text/javascript">
27828 * @extends Roo.util.Observable
27829 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
27830 * This class also supports single and multi selection modes. <br>
27831 * Create a data model bound view:
27833 var store = new Roo.data.Store(...);
27835 var view = new Roo.View({
27837 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
27839 singleSelect: true,
27840 selectedClass: "ydataview-selected",
27844 // listen for node click?
27845 view.on("click", function(vw, index, node, e){
27846 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27850 dataModel.load("foobar.xml");
27852 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
27854 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
27855 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
27857 * Note: old style constructor is still suported (container, template, config)
27860 * Create a new View
27861 * @param {Object} config The config object
27864 Roo.View = function(config, depreciated_tpl, depreciated_config){
27866 this.parent = false;
27868 if (typeof(depreciated_tpl) == 'undefined') {
27869 // new way.. - universal constructor.
27870 Roo.apply(this, config);
27871 this.el = Roo.get(this.el);
27874 this.el = Roo.get(config);
27875 this.tpl = depreciated_tpl;
27876 Roo.apply(this, depreciated_config);
27878 this.wrapEl = this.el.wrap().wrap();
27879 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
27882 if(typeof(this.tpl) == "string"){
27883 this.tpl = new Roo.Template(this.tpl);
27885 // support xtype ctors..
27886 this.tpl = new Roo.factory(this.tpl, Roo);
27890 this.tpl.compile();
27895 * @event beforeclick
27896 * Fires before a click is processed. Returns false to cancel the default action.
27897 * @param {Roo.View} this
27898 * @param {Number} index The index of the target node
27899 * @param {HTMLElement} node The target node
27900 * @param {Roo.EventObject} e The raw event object
27902 "beforeclick" : true,
27905 * Fires when a template node is clicked.
27906 * @param {Roo.View} this
27907 * @param {Number} index The index of the target node
27908 * @param {HTMLElement} node The target node
27909 * @param {Roo.EventObject} e The raw event object
27914 * Fires when a template node is double clicked.
27915 * @param {Roo.View} this
27916 * @param {Number} index The index of the target node
27917 * @param {HTMLElement} node The target node
27918 * @param {Roo.EventObject} e The raw event object
27922 * @event contextmenu
27923 * Fires when a template node is right clicked.
27924 * @param {Roo.View} this
27925 * @param {Number} index The index of the target node
27926 * @param {HTMLElement} node The target node
27927 * @param {Roo.EventObject} e The raw event object
27929 "contextmenu" : true,
27931 * @event selectionchange
27932 * Fires when the selected nodes change.
27933 * @param {Roo.View} this
27934 * @param {Array} selections Array of the selected nodes
27936 "selectionchange" : true,
27939 * @event beforeselect
27940 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
27941 * @param {Roo.View} this
27942 * @param {HTMLElement} node The node to be selected
27943 * @param {Array} selections Array of currently selected nodes
27945 "beforeselect" : true,
27947 * @event preparedata
27948 * Fires on every row to render, to allow you to change the data.
27949 * @param {Roo.View} this
27950 * @param {Object} data to be rendered (change this)
27952 "preparedata" : true
27960 "click": this.onClick,
27961 "dblclick": this.onDblClick,
27962 "contextmenu": this.onContextMenu,
27966 this.selections = [];
27968 this.cmp = new Roo.CompositeElementLite([]);
27970 this.store = Roo.factory(this.store, Roo.data);
27971 this.setStore(this.store, true);
27974 if ( this.footer && this.footer.xtype) {
27976 var fctr = this.wrapEl.appendChild(document.createElement("div"));
27978 this.footer.dataSource = this.store;
27979 this.footer.container = fctr;
27980 this.footer = Roo.factory(this.footer, Roo);
27981 fctr.insertFirst(this.el);
27983 // this is a bit insane - as the paging toolbar seems to detach the el..
27984 // dom.parentNode.parentNode.parentNode
27985 // they get detached?
27989 Roo.View.superclass.constructor.call(this);
27994 Roo.extend(Roo.View, Roo.util.Observable, {
27997 * @cfg {Roo.data.Store} store Data store to load data from.
28002 * @cfg {String|Roo.Element} el The container element.
28007 * @cfg {String|Roo.Template} tpl The template used by this View
28011 * @cfg {String} dataName the named area of the template to use as the data area
28012 * Works with domtemplates roo-name="name"
28016 * @cfg {String} selectedClass The css class to add to selected nodes
28018 selectedClass : "x-view-selected",
28020 * @cfg {String} emptyText The empty text to show when nothing is loaded.
28025 * @cfg {String} text to display on mask (default Loading)
28029 * @cfg {Boolean} multiSelect Allow multiple selection
28031 multiSelect : false,
28033 * @cfg {Boolean} singleSelect Allow single selection
28035 singleSelect: false,
28038 * @cfg {Boolean} toggleSelect - selecting
28040 toggleSelect : false,
28043 * @cfg {Boolean} tickable - selecting
28048 * Returns the element this view is bound to.
28049 * @return {Roo.Element}
28051 getEl : function(){
28052 return this.wrapEl;
28058 * Refreshes the view. - called by datachanged on the store. - do not call directly.
28060 refresh : function(){
28061 //Roo.log('refresh');
28064 // if we are using something like 'domtemplate', then
28065 // the what gets used is:
28066 // t.applySubtemplate(NAME, data, wrapping data..)
28067 // the outer template then get' applied with
28068 // the store 'extra data'
28069 // and the body get's added to the
28070 // roo-name="data" node?
28071 // <span class='roo-tpl-{name}'></span> ?????
28075 this.clearSelections();
28076 this.el.update("");
28078 var records = this.store.getRange();
28079 if(records.length < 1) {
28081 // is this valid?? = should it render a template??
28083 this.el.update(this.emptyText);
28087 if (this.dataName) {
28088 this.el.update(t.apply(this.store.meta)); //????
28089 el = this.el.child('.roo-tpl-' + this.dataName);
28092 for(var i = 0, len = records.length; i < len; i++){
28093 var data = this.prepareData(records[i].data, i, records[i]);
28094 this.fireEvent("preparedata", this, data, i, records[i]);
28096 var d = Roo.apply({}, data);
28099 Roo.apply(d, {'roo-id' : Roo.id()});
28103 Roo.each(this.parent.item, function(item){
28104 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
28107 Roo.apply(d, {'roo-data-checked' : 'checked'});
28111 html[html.length] = Roo.util.Format.trim(
28113 t.applySubtemplate(this.dataName, d, this.store.meta) :
28120 el.update(html.join(""));
28121 this.nodes = el.dom.childNodes;
28122 this.updateIndexes(0);
28127 * Function to override to reformat the data that is sent to
28128 * the template for each node.
28129 * DEPRICATED - use the preparedata event handler.
28130 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
28131 * a JSON object for an UpdateManager bound view).
28133 prepareData : function(data, index, record)
28135 this.fireEvent("preparedata", this, data, index, record);
28139 onUpdate : function(ds, record){
28140 // Roo.log('on update');
28141 this.clearSelections();
28142 var index = this.store.indexOf(record);
28143 var n = this.nodes[index];
28144 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
28145 n.parentNode.removeChild(n);
28146 this.updateIndexes(index, index);
28152 onAdd : function(ds, records, index)
28154 //Roo.log(['on Add', ds, records, index] );
28155 this.clearSelections();
28156 if(this.nodes.length == 0){
28160 var n = this.nodes[index];
28161 for(var i = 0, len = records.length; i < len; i++){
28162 var d = this.prepareData(records[i].data, i, records[i]);
28164 this.tpl.insertBefore(n, d);
28167 this.tpl.append(this.el, d);
28170 this.updateIndexes(index);
28173 onRemove : function(ds, record, index){
28174 // Roo.log('onRemove');
28175 this.clearSelections();
28176 var el = this.dataName ?
28177 this.el.child('.roo-tpl-' + this.dataName) :
28180 el.dom.removeChild(this.nodes[index]);
28181 this.updateIndexes(index);
28185 * Refresh an individual node.
28186 * @param {Number} index
28188 refreshNode : function(index){
28189 this.onUpdate(this.store, this.store.getAt(index));
28192 updateIndexes : function(startIndex, endIndex){
28193 var ns = this.nodes;
28194 startIndex = startIndex || 0;
28195 endIndex = endIndex || ns.length - 1;
28196 for(var i = startIndex; i <= endIndex; i++){
28197 ns[i].nodeIndex = i;
28202 * Changes the data store this view uses and refresh the view.
28203 * @param {Store} store
28205 setStore : function(store, initial){
28206 if(!initial && this.store){
28207 this.store.un("datachanged", this.refresh);
28208 this.store.un("add", this.onAdd);
28209 this.store.un("remove", this.onRemove);
28210 this.store.un("update", this.onUpdate);
28211 this.store.un("clear", this.refresh);
28212 this.store.un("beforeload", this.onBeforeLoad);
28213 this.store.un("load", this.onLoad);
28214 this.store.un("loadexception", this.onLoad);
28218 store.on("datachanged", this.refresh, this);
28219 store.on("add", this.onAdd, this);
28220 store.on("remove", this.onRemove, this);
28221 store.on("update", this.onUpdate, this);
28222 store.on("clear", this.refresh, this);
28223 store.on("beforeload", this.onBeforeLoad, this);
28224 store.on("load", this.onLoad, this);
28225 store.on("loadexception", this.onLoad, this);
28233 * onbeforeLoad - masks the loading area.
28236 onBeforeLoad : function(store,opts)
28238 //Roo.log('onBeforeLoad');
28240 this.el.update("");
28242 this.el.mask(this.mask ? this.mask : "Loading" );
28244 onLoad : function ()
28251 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
28252 * @param {HTMLElement} node
28253 * @return {HTMLElement} The template node
28255 findItemFromChild : function(node){
28256 var el = this.dataName ?
28257 this.el.child('.roo-tpl-' + this.dataName,true) :
28260 if(!node || node.parentNode == el){
28263 var p = node.parentNode;
28264 while(p && p != el){
28265 if(p.parentNode == el){
28274 onClick : function(e){
28275 var item = this.findItemFromChild(e.getTarget());
28277 var index = this.indexOf(item);
28278 if(this.onItemClick(item, index, e) !== false){
28279 this.fireEvent("click", this, index, item, e);
28282 this.clearSelections();
28287 onContextMenu : function(e){
28288 var item = this.findItemFromChild(e.getTarget());
28290 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
28295 onDblClick : function(e){
28296 var item = this.findItemFromChild(e.getTarget());
28298 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
28302 onItemClick : function(item, index, e)
28304 if(this.fireEvent("beforeclick", this, index, item, e) === false){
28307 if (this.toggleSelect) {
28308 var m = this.isSelected(item) ? 'unselect' : 'select';
28311 _t[m](item, true, false);
28314 if(this.multiSelect || this.singleSelect){
28315 if(this.multiSelect && e.shiftKey && this.lastSelection){
28316 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
28318 this.select(item, this.multiSelect && e.ctrlKey);
28319 this.lastSelection = item;
28322 if(!this.tickable){
28323 e.preventDefault();
28331 * Get the number of selected nodes.
28334 getSelectionCount : function(){
28335 return this.selections.length;
28339 * Get the currently selected nodes.
28340 * @return {Array} An array of HTMLElements
28342 getSelectedNodes : function(){
28343 return this.selections;
28347 * Get the indexes of the selected nodes.
28350 getSelectedIndexes : function(){
28351 var indexes = [], s = this.selections;
28352 for(var i = 0, len = s.length; i < len; i++){
28353 indexes.push(s[i].nodeIndex);
28359 * Clear all selections
28360 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
28362 clearSelections : function(suppressEvent){
28363 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
28364 this.cmp.elements = this.selections;
28365 this.cmp.removeClass(this.selectedClass);
28366 this.selections = [];
28367 if(!suppressEvent){
28368 this.fireEvent("selectionchange", this, this.selections);
28374 * Returns true if the passed node is selected
28375 * @param {HTMLElement/Number} node The node or node index
28376 * @return {Boolean}
28378 isSelected : function(node){
28379 var s = this.selections;
28383 node = this.getNode(node);
28384 return s.indexOf(node) !== -1;
28389 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
28390 * @param {Boolean} keepExisting (optional) true to keep existing selections
28391 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
28393 select : function(nodeInfo, keepExisting, suppressEvent){
28394 if(nodeInfo instanceof Array){
28396 this.clearSelections(true);
28398 for(var i = 0, len = nodeInfo.length; i < len; i++){
28399 this.select(nodeInfo[i], true, true);
28403 var node = this.getNode(nodeInfo);
28404 if(!node || this.isSelected(node)){
28405 return; // already selected.
28408 this.clearSelections(true);
28411 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
28412 Roo.fly(node).addClass(this.selectedClass);
28413 this.selections.push(node);
28414 if(!suppressEvent){
28415 this.fireEvent("selectionchange", this, this.selections);
28423 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
28424 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
28425 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
28427 unselect : function(nodeInfo, keepExisting, suppressEvent)
28429 if(nodeInfo instanceof Array){
28430 Roo.each(this.selections, function(s) {
28431 this.unselect(s, nodeInfo);
28435 var node = this.getNode(nodeInfo);
28436 if(!node || !this.isSelected(node)){
28437 //Roo.log("not selected");
28438 return; // not selected.
28442 Roo.each(this.selections, function(s) {
28444 Roo.fly(node).removeClass(this.selectedClass);
28451 this.selections= ns;
28452 this.fireEvent("selectionchange", this, this.selections);
28456 * Gets a template node.
28457 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
28458 * @return {HTMLElement} The node or null if it wasn't found
28460 getNode : function(nodeInfo){
28461 if(typeof nodeInfo == "string"){
28462 return document.getElementById(nodeInfo);
28463 }else if(typeof nodeInfo == "number"){
28464 return this.nodes[nodeInfo];
28470 * Gets a range template nodes.
28471 * @param {Number} startIndex
28472 * @param {Number} endIndex
28473 * @return {Array} An array of nodes
28475 getNodes : function(start, end){
28476 var ns = this.nodes;
28477 start = start || 0;
28478 end = typeof end == "undefined" ? ns.length - 1 : end;
28481 for(var i = start; i <= end; i++){
28485 for(var i = start; i >= end; i--){
28493 * Finds the index of the passed node
28494 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
28495 * @return {Number} The index of the node or -1
28497 indexOf : function(node){
28498 node = this.getNode(node);
28499 if(typeof node.nodeIndex == "number"){
28500 return node.nodeIndex;
28502 var ns = this.nodes;
28503 for(var i = 0, len = ns.length; i < len; i++){
28513 * Ext JS Library 1.1.1
28514 * Copyright(c) 2006-2007, Ext JS, LLC.
28516 * Originally Released Under LGPL - original licence link has changed is not relivant.
28519 * <script type="text/javascript">
28523 * @class Roo.JsonView
28524 * @extends Roo.View
28525 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
28527 var view = new Roo.JsonView({
28528 container: "my-element",
28529 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
28534 // listen for node click?
28535 view.on("click", function(vw, index, node, e){
28536 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
28539 // direct load of JSON data
28540 view.load("foobar.php");
28542 // Example from my blog list
28543 var tpl = new Roo.Template(
28544 '<div class="entry">' +
28545 '<a class="entry-title" href="{link}">{title}</a>' +
28546 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
28547 "</div><hr />"
28550 var moreView = new Roo.JsonView({
28551 container : "entry-list",
28555 moreView.on("beforerender", this.sortEntries, this);
28557 url: "/blog/get-posts.php",
28558 params: "allposts=true",
28559 text: "Loading Blog Entries..."
28563 * Note: old code is supported with arguments : (container, template, config)
28567 * Create a new JsonView
28569 * @param {Object} config The config object
28572 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
28575 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
28577 var um = this.el.getUpdateManager();
28578 um.setRenderer(this);
28579 um.on("update", this.onLoad, this);
28580 um.on("failure", this.onLoadException, this);
28583 * @event beforerender
28584 * Fires before rendering of the downloaded JSON data.
28585 * @param {Roo.JsonView} this
28586 * @param {Object} data The JSON data loaded
28590 * Fires when data is loaded.
28591 * @param {Roo.JsonView} this
28592 * @param {Object} data The JSON data loaded
28593 * @param {Object} response The raw Connect response object
28596 * @event loadexception
28597 * Fires when loading fails.
28598 * @param {Roo.JsonView} this
28599 * @param {Object} response The raw Connect response object
28602 'beforerender' : true,
28604 'loadexception' : true
28607 Roo.extend(Roo.JsonView, Roo.View, {
28609 * @type {String} The root property in the loaded JSON object that contains the data
28614 * Refreshes the view.
28616 refresh : function(){
28617 this.clearSelections();
28618 this.el.update("");
28620 var o = this.jsonData;
28621 if(o && o.length > 0){
28622 for(var i = 0, len = o.length; i < len; i++){
28623 var data = this.prepareData(o[i], i, o);
28624 html[html.length] = this.tpl.apply(data);
28627 html.push(this.emptyText);
28629 this.el.update(html.join(""));
28630 this.nodes = this.el.dom.childNodes;
28631 this.updateIndexes(0);
28635 * Performs an async HTTP request, and loads the JSON from the response. If <i>params</i> are specified it uses POST, otherwise it uses GET.
28636 * @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:
28639 url: "your-url.php",
28640 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
28641 callback: yourFunction,
28642 scope: yourObject, //(optional scope)
28645 text: "Loading...",
28650 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
28651 * are respectively shorthand for <i>disableCaching</i>, <i>indicatorText</i>, and <i>loadScripts</i> and are used to set their associated property on this UpdateManager instance.
28652 * @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}
28653 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
28654 * @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.
28657 var um = this.el.getUpdateManager();
28658 um.update.apply(um, arguments);
28661 // note - render is a standard framework call...
28662 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
28663 render : function(el, response){
28665 this.clearSelections();
28666 this.el.update("");
28669 if (response != '') {
28670 o = Roo.util.JSON.decode(response.responseText);
28673 o = o[this.jsonRoot];
28679 * The current JSON data or null
28682 this.beforeRender();
28687 * Get the number of records in the current JSON dataset
28690 getCount : function(){
28691 return this.jsonData ? this.jsonData.length : 0;
28695 * Returns the JSON object for the specified node(s)
28696 * @param {HTMLElement/Array} node The node or an array of nodes
28697 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
28698 * you get the JSON object for the node
28700 getNodeData : function(node){
28701 if(node instanceof Array){
28703 for(var i = 0, len = node.length; i < len; i++){
28704 data.push(this.getNodeData(node[i]));
28708 return this.jsonData[this.indexOf(node)] || null;
28711 beforeRender : function(){
28712 this.snapshot = this.jsonData;
28714 this.sort.apply(this, this.sortInfo);
28716 this.fireEvent("beforerender", this, this.jsonData);
28719 onLoad : function(el, o){
28720 this.fireEvent("load", this, this.jsonData, o);
28723 onLoadException : function(el, o){
28724 this.fireEvent("loadexception", this, o);
28728 * Filter the data by a specific property.
28729 * @param {String} property A property on your JSON objects
28730 * @param {String/RegExp} value Either string that the property values
28731 * should start with, or a RegExp to test against the property
28733 filter : function(property, value){
28736 var ss = this.snapshot;
28737 if(typeof value == "string"){
28738 var vlen = value.length;
28740 this.clearFilter();
28743 value = value.toLowerCase();
28744 for(var i = 0, len = ss.length; i < len; i++){
28746 if(o[property].substr(0, vlen).toLowerCase() == value){
28750 } else if(value.exec){ // regex?
28751 for(var i = 0, len = ss.length; i < len; i++){
28753 if(value.test(o[property])){
28760 this.jsonData = data;
28766 * Filter by a function. The passed function will be called with each
28767 * object in the current dataset. If the function returns true the value is kept,
28768 * otherwise it is filtered.
28769 * @param {Function} fn
28770 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
28772 filterBy : function(fn, scope){
28775 var ss = this.snapshot;
28776 for(var i = 0, len = ss.length; i < len; i++){
28778 if(fn.call(scope || this, o)){
28782 this.jsonData = data;
28788 * Clears the current filter.
28790 clearFilter : function(){
28791 if(this.snapshot && this.jsonData != this.snapshot){
28792 this.jsonData = this.snapshot;
28799 * Sorts the data for this view and refreshes it.
28800 * @param {String} property A property on your JSON objects to sort on
28801 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
28802 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
28804 sort : function(property, dir, sortType){
28805 this.sortInfo = Array.prototype.slice.call(arguments, 0);
28808 var dsc = dir && dir.toLowerCase() == "desc";
28809 var f = function(o1, o2){
28810 var v1 = sortType ? sortType(o1[p]) : o1[p];
28811 var v2 = sortType ? sortType(o2[p]) : o2[p];
28814 return dsc ? +1 : -1;
28815 } else if(v1 > v2){
28816 return dsc ? -1 : +1;
28821 this.jsonData.sort(f);
28823 if(this.jsonData != this.snapshot){
28824 this.snapshot.sort(f);
28830 * Ext JS Library 1.1.1
28831 * Copyright(c) 2006-2007, Ext JS, LLC.
28833 * Originally Released Under LGPL - original licence link has changed is not relivant.
28836 * <script type="text/javascript">
28841 * @class Roo.ColorPalette
28842 * @extends Roo.Component
28843 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
28844 * Here's an example of typical usage:
28846 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
28847 cp.render('my-div');
28849 cp.on('select', function(palette, selColor){
28850 // do something with selColor
28854 * Create a new ColorPalette
28855 * @param {Object} config The config object
28857 Roo.ColorPalette = function(config){
28858 Roo.ColorPalette.superclass.constructor.call(this, config);
28862 * Fires when a color is selected
28863 * @param {ColorPalette} this
28864 * @param {String} color The 6-digit color hex code (without the # symbol)
28870 this.on("select", this.handler, this.scope, true);
28873 Roo.extend(Roo.ColorPalette, Roo.Component, {
28875 * @cfg {String} itemCls
28876 * The CSS class to apply to the containing element (defaults to "x-color-palette")
28878 itemCls : "x-color-palette",
28880 * @cfg {String} value
28881 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
28882 * the hex codes are case-sensitive.
28885 clickEvent:'click',
28887 ctype: "Roo.ColorPalette",
28890 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
28892 allowReselect : false,
28895 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
28896 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
28897 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
28898 * of colors with the width setting until the box is symmetrical.</p>
28899 * <p>You can override individual colors if needed:</p>
28901 var cp = new Roo.ColorPalette();
28902 cp.colors[0] = "FF0000"; // change the first box to red
28905 Or you can provide a custom array of your own for complete control:
28907 var cp = new Roo.ColorPalette();
28908 cp.colors = ["000000", "993300", "333300"];
28913 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
28914 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
28915 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
28916 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
28917 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
28921 onRender : function(container, position){
28922 var t = new Roo.MasterTemplate(
28923 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
28925 var c = this.colors;
28926 for(var i = 0, len = c.length; i < len; i++){
28929 var el = document.createElement("div");
28930 el.className = this.itemCls;
28932 container.dom.insertBefore(el, position);
28933 this.el = Roo.get(el);
28934 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
28935 if(this.clickEvent != 'click'){
28936 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
28941 afterRender : function(){
28942 Roo.ColorPalette.superclass.afterRender.call(this);
28944 var s = this.value;
28951 handleClick : function(e, t){
28952 e.preventDefault();
28953 if(!this.disabled){
28954 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
28955 this.select(c.toUpperCase());
28960 * Selects the specified color in the palette (fires the select event)
28961 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
28963 select : function(color){
28964 color = color.replace("#", "");
28965 if(color != this.value || this.allowReselect){
28968 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
28970 el.child("a.color-"+color).addClass("x-color-palette-sel");
28971 this.value = color;
28972 this.fireEvent("select", this, color);
28977 * Ext JS Library 1.1.1
28978 * Copyright(c) 2006-2007, Ext JS, LLC.
28980 * Originally Released Under LGPL - original licence link has changed is not relivant.
28983 * <script type="text/javascript">
28987 * @class Roo.DatePicker
28988 * @extends Roo.Component
28989 * Simple date picker class.
28991 * Create a new DatePicker
28992 * @param {Object} config The config object
28994 Roo.DatePicker = function(config){
28995 Roo.DatePicker.superclass.constructor.call(this, config);
28997 this.value = config && config.value ?
28998 config.value.clearTime() : new Date().clearTime();
29003 * Fires when a date is selected
29004 * @param {DatePicker} this
29005 * @param {Date} date The selected date
29009 * @event monthchange
29010 * Fires when the displayed month changes
29011 * @param {DatePicker} this
29012 * @param {Date} date The selected month
29014 'monthchange': true
29018 this.on("select", this.handler, this.scope || this);
29020 // build the disabledDatesRE
29021 if(!this.disabledDatesRE && this.disabledDates){
29022 var dd = this.disabledDates;
29024 for(var i = 0; i < dd.length; i++){
29026 if(i != dd.length-1) {
29030 this.disabledDatesRE = new RegExp(re + ")");
29034 Roo.extend(Roo.DatePicker, Roo.Component, {
29036 * @cfg {String} todayText
29037 * The text to display on the button that selects the current date (defaults to "Today")
29039 todayText : "Today",
29041 * @cfg {String} okText
29042 * The text to display on the ok button
29044 okText : " OK ", //   to give the user extra clicking room
29046 * @cfg {String} cancelText
29047 * The text to display on the cancel button
29049 cancelText : "Cancel",
29051 * @cfg {String} todayTip
29052 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
29054 todayTip : "{0} (Spacebar)",
29056 * @cfg {Date} minDate
29057 * Minimum allowable date (JavaScript date object, defaults to null)
29061 * @cfg {Date} maxDate
29062 * Maximum allowable date (JavaScript date object, defaults to null)
29066 * @cfg {String} minText
29067 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
29069 minText : "This date is before the minimum date",
29071 * @cfg {String} maxText
29072 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
29074 maxText : "This date is after the maximum date",
29076 * @cfg {String} format
29077 * The default date format string which can be overriden for localization support. The format must be
29078 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
29082 * @cfg {Array} disabledDays
29083 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
29085 disabledDays : null,
29087 * @cfg {String} disabledDaysText
29088 * The tooltip to display when the date falls on a disabled day (defaults to "")
29090 disabledDaysText : "",
29092 * @cfg {RegExp} disabledDatesRE
29093 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
29095 disabledDatesRE : null,
29097 * @cfg {String} disabledDatesText
29098 * The tooltip text to display when the date falls on a disabled date (defaults to "")
29100 disabledDatesText : "",
29102 * @cfg {Boolean} constrainToViewport
29103 * True to constrain the date picker to the viewport (defaults to true)
29105 constrainToViewport : true,
29107 * @cfg {Array} monthNames
29108 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
29110 monthNames : Date.monthNames,
29112 * @cfg {Array} dayNames
29113 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
29115 dayNames : Date.dayNames,
29117 * @cfg {String} nextText
29118 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
29120 nextText: 'Next Month (Control+Right)',
29122 * @cfg {String} prevText
29123 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
29125 prevText: 'Previous Month (Control+Left)',
29127 * @cfg {String} monthYearText
29128 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
29130 monthYearText: 'Choose a month (Control+Up/Down to move years)',
29132 * @cfg {Number} startDay
29133 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
29137 * @cfg {Bool} showClear
29138 * Show a clear button (usefull for date form elements that can be blank.)
29144 * Sets the value of the date field
29145 * @param {Date} value The date to set
29147 setValue : function(value){
29148 var old = this.value;
29150 if (typeof(value) == 'string') {
29152 value = Date.parseDate(value, this.format);
29155 value = new Date();
29158 this.value = value.clearTime(true);
29160 this.update(this.value);
29165 * Gets the current selected value of the date field
29166 * @return {Date} The selected date
29168 getValue : function(){
29173 focus : function(){
29175 this.update(this.activeDate);
29180 onRender : function(container, position){
29183 '<table cellspacing="0">',
29184 '<tr><td class="x-date-left"><a href="#" title="', this.prevText ,'"> </a></td><td class="x-date-middle" align="center"></td><td class="x-date-right"><a href="#" title="', this.nextText ,'"> </a></td></tr>',
29185 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
29186 var dn = this.dayNames;
29187 for(var i = 0; i < 7; i++){
29188 var d = this.startDay+i;
29192 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
29194 m[m.length] = "</tr></thead><tbody><tr>";
29195 for(var i = 0; i < 42; i++) {
29196 if(i % 7 == 0 && i != 0){
29197 m[m.length] = "</tr><tr>";
29199 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
29201 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
29202 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
29204 var el = document.createElement("div");
29205 el.className = "x-date-picker";
29206 el.innerHTML = m.join("");
29208 container.dom.insertBefore(el, position);
29210 this.el = Roo.get(el);
29211 this.eventEl = Roo.get(el.firstChild);
29213 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
29214 handler: this.showPrevMonth,
29216 preventDefault:true,
29220 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
29221 handler: this.showNextMonth,
29223 preventDefault:true,
29227 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
29229 this.monthPicker = this.el.down('div.x-date-mp');
29230 this.monthPicker.enableDisplayMode('block');
29232 var kn = new Roo.KeyNav(this.eventEl, {
29233 "left" : function(e){
29235 this.showPrevMonth() :
29236 this.update(this.activeDate.add("d", -1));
29239 "right" : function(e){
29241 this.showNextMonth() :
29242 this.update(this.activeDate.add("d", 1));
29245 "up" : function(e){
29247 this.showNextYear() :
29248 this.update(this.activeDate.add("d", -7));
29251 "down" : function(e){
29253 this.showPrevYear() :
29254 this.update(this.activeDate.add("d", 7));
29257 "pageUp" : function(e){
29258 this.showNextMonth();
29261 "pageDown" : function(e){
29262 this.showPrevMonth();
29265 "enter" : function(e){
29266 e.stopPropagation();
29273 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
29275 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
29277 this.el.unselectable();
29279 this.cells = this.el.select("table.x-date-inner tbody td");
29280 this.textNodes = this.el.query("table.x-date-inner tbody span");
29282 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
29284 tooltip: this.monthYearText
29287 this.mbtn.on('click', this.showMonthPicker, this);
29288 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
29291 var today = (new Date()).dateFormat(this.format);
29293 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
29294 if (this.showClear) {
29295 baseTb.add( new Roo.Toolbar.Fill());
29298 text: String.format(this.todayText, today),
29299 tooltip: String.format(this.todayTip, today),
29300 handler: this.selectToday,
29304 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
29307 if (this.showClear) {
29309 baseTb.add( new Roo.Toolbar.Fill());
29312 cls: 'x-btn-icon x-btn-clear',
29313 handler: function() {
29315 this.fireEvent("select", this, '');
29325 this.update(this.value);
29328 createMonthPicker : function(){
29329 if(!this.monthPicker.dom.firstChild){
29330 var buf = ['<table border="0" cellspacing="0">'];
29331 for(var i = 0; i < 6; i++){
29333 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
29334 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
29336 '<td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-prev"></a></td><td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-next"></a></td></tr>' :
29337 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
29341 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
29343 '</button><button type="button" class="x-date-mp-cancel">',
29345 '</button></td></tr>',
29348 this.monthPicker.update(buf.join(''));
29349 this.monthPicker.on('click', this.onMonthClick, this);
29350 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
29352 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
29353 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
29355 this.mpMonths.each(function(m, a, i){
29358 m.dom.xmonth = 5 + Math.round(i * .5);
29360 m.dom.xmonth = Math.round((i-1) * .5);
29366 showMonthPicker : function(){
29367 this.createMonthPicker();
29368 var size = this.el.getSize();
29369 this.monthPicker.setSize(size);
29370 this.monthPicker.child('table').setSize(size);
29372 this.mpSelMonth = (this.activeDate || this.value).getMonth();
29373 this.updateMPMonth(this.mpSelMonth);
29374 this.mpSelYear = (this.activeDate || this.value).getFullYear();
29375 this.updateMPYear(this.mpSelYear);
29377 this.monthPicker.slideIn('t', {duration:.2});
29380 updateMPYear : function(y){
29382 var ys = this.mpYears.elements;
29383 for(var i = 1; i <= 10; i++){
29384 var td = ys[i-1], y2;
29386 y2 = y + Math.round(i * .5);
29387 td.firstChild.innerHTML = y2;
29390 y2 = y - (5-Math.round(i * .5));
29391 td.firstChild.innerHTML = y2;
29394 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
29398 updateMPMonth : function(sm){
29399 this.mpMonths.each(function(m, a, i){
29400 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
29404 selectMPMonth: function(m){
29408 onMonthClick : function(e, t){
29410 var el = new Roo.Element(t), pn;
29411 if(el.is('button.x-date-mp-cancel')){
29412 this.hideMonthPicker();
29414 else if(el.is('button.x-date-mp-ok')){
29415 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
29416 this.hideMonthPicker();
29418 else if(pn = el.up('td.x-date-mp-month', 2)){
29419 this.mpMonths.removeClass('x-date-mp-sel');
29420 pn.addClass('x-date-mp-sel');
29421 this.mpSelMonth = pn.dom.xmonth;
29423 else if(pn = el.up('td.x-date-mp-year', 2)){
29424 this.mpYears.removeClass('x-date-mp-sel');
29425 pn.addClass('x-date-mp-sel');
29426 this.mpSelYear = pn.dom.xyear;
29428 else if(el.is('a.x-date-mp-prev')){
29429 this.updateMPYear(this.mpyear-10);
29431 else if(el.is('a.x-date-mp-next')){
29432 this.updateMPYear(this.mpyear+10);
29436 onMonthDblClick : function(e, t){
29438 var el = new Roo.Element(t), pn;
29439 if(pn = el.up('td.x-date-mp-month', 2)){
29440 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
29441 this.hideMonthPicker();
29443 else if(pn = el.up('td.x-date-mp-year', 2)){
29444 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
29445 this.hideMonthPicker();
29449 hideMonthPicker : function(disableAnim){
29450 if(this.monthPicker){
29451 if(disableAnim === true){
29452 this.monthPicker.hide();
29454 this.monthPicker.slideOut('t', {duration:.2});
29460 showPrevMonth : function(e){
29461 this.update(this.activeDate.add("mo", -1));
29465 showNextMonth : function(e){
29466 this.update(this.activeDate.add("mo", 1));
29470 showPrevYear : function(){
29471 this.update(this.activeDate.add("y", -1));
29475 showNextYear : function(){
29476 this.update(this.activeDate.add("y", 1));
29480 handleMouseWheel : function(e){
29481 var delta = e.getWheelDelta();
29483 this.showPrevMonth();
29485 } else if(delta < 0){
29486 this.showNextMonth();
29492 handleDateClick : function(e, t){
29494 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
29495 this.setValue(new Date(t.dateValue));
29496 this.fireEvent("select", this, this.value);
29501 selectToday : function(){
29502 this.setValue(new Date().clearTime());
29503 this.fireEvent("select", this, this.value);
29507 update : function(date)
29509 var vd = this.activeDate;
29510 this.activeDate = date;
29512 var t = date.getTime();
29513 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
29514 this.cells.removeClass("x-date-selected");
29515 this.cells.each(function(c){
29516 if(c.dom.firstChild.dateValue == t){
29517 c.addClass("x-date-selected");
29518 setTimeout(function(){
29519 try{c.dom.firstChild.focus();}catch(e){}
29528 var days = date.getDaysInMonth();
29529 var firstOfMonth = date.getFirstDateOfMonth();
29530 var startingPos = firstOfMonth.getDay()-this.startDay;
29532 if(startingPos <= this.startDay){
29536 var pm = date.add("mo", -1);
29537 var prevStart = pm.getDaysInMonth()-startingPos;
29539 var cells = this.cells.elements;
29540 var textEls = this.textNodes;
29541 days += startingPos;
29543 // convert everything to numbers so it's fast
29544 var day = 86400000;
29545 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
29546 var today = new Date().clearTime().getTime();
29547 var sel = date.clearTime().getTime();
29548 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
29549 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
29550 var ddMatch = this.disabledDatesRE;
29551 var ddText = this.disabledDatesText;
29552 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
29553 var ddaysText = this.disabledDaysText;
29554 var format = this.format;
29556 var setCellClass = function(cal, cell){
29558 var t = d.getTime();
29559 cell.firstChild.dateValue = t;
29561 cell.className += " x-date-today";
29562 cell.title = cal.todayText;
29565 cell.className += " x-date-selected";
29566 setTimeout(function(){
29567 try{cell.firstChild.focus();}catch(e){}
29572 cell.className = " x-date-disabled";
29573 cell.title = cal.minText;
29577 cell.className = " x-date-disabled";
29578 cell.title = cal.maxText;
29582 if(ddays.indexOf(d.getDay()) != -1){
29583 cell.title = ddaysText;
29584 cell.className = " x-date-disabled";
29587 if(ddMatch && format){
29588 var fvalue = d.dateFormat(format);
29589 if(ddMatch.test(fvalue)){
29590 cell.title = ddText.replace("%0", fvalue);
29591 cell.className = " x-date-disabled";
29597 for(; i < startingPos; i++) {
29598 textEls[i].innerHTML = (++prevStart);
29599 d.setDate(d.getDate()+1);
29600 cells[i].className = "x-date-prevday";
29601 setCellClass(this, cells[i]);
29603 for(; i < days; i++){
29604 intDay = i - startingPos + 1;
29605 textEls[i].innerHTML = (intDay);
29606 d.setDate(d.getDate()+1);
29607 cells[i].className = "x-date-active";
29608 setCellClass(this, cells[i]);
29611 for(; i < 42; i++) {
29612 textEls[i].innerHTML = (++extraDays);
29613 d.setDate(d.getDate()+1);
29614 cells[i].className = "x-date-nextday";
29615 setCellClass(this, cells[i]);
29618 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
29619 this.fireEvent('monthchange', this, date);
29621 if(!this.internalRender){
29622 var main = this.el.dom.firstChild;
29623 var w = main.offsetWidth;
29624 this.el.setWidth(w + this.el.getBorderWidth("lr"));
29625 Roo.fly(main).setWidth(w);
29626 this.internalRender = true;
29627 // opera does not respect the auto grow header center column
29628 // then, after it gets a width opera refuses to recalculate
29629 // without a second pass
29630 if(Roo.isOpera && !this.secondPass){
29631 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
29632 this.secondPass = true;
29633 this.update.defer(10, this, [date]);
29641 * Ext JS Library 1.1.1
29642 * Copyright(c) 2006-2007, Ext JS, LLC.
29644 * Originally Released Under LGPL - original licence link has changed is not relivant.
29647 * <script type="text/javascript">
29650 * @class Roo.TabPanel
29651 * @extends Roo.util.Observable
29652 * A lightweight tab container.
29656 // basic tabs 1, built from existing content
29657 var tabs = new Roo.TabPanel("tabs1");
29658 tabs.addTab("script", "View Script");
29659 tabs.addTab("markup", "View Markup");
29660 tabs.activate("script");
29662 // more advanced tabs, built from javascript
29663 var jtabs = new Roo.TabPanel("jtabs");
29664 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
29666 // set up the UpdateManager
29667 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
29668 var updater = tab2.getUpdateManager();
29669 updater.setDefaultUrl("ajax1.htm");
29670 tab2.on('activate', updater.refresh, updater, true);
29672 // Use setUrl for Ajax loading
29673 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
29674 tab3.setUrl("ajax2.htm", null, true);
29677 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
29680 jtabs.activate("jtabs-1");
29683 * Create a new TabPanel.
29684 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
29685 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
29687 Roo.TabPanel = function(container, config){
29689 * The container element for this TabPanel.
29690 * @type Roo.Element
29692 this.el = Roo.get(container, true);
29694 if(typeof config == "boolean"){
29695 this.tabPosition = config ? "bottom" : "top";
29697 Roo.apply(this, config);
29700 if(this.tabPosition == "bottom"){
29701 this.bodyEl = Roo.get(this.createBody(this.el.dom));
29702 this.el.addClass("x-tabs-bottom");
29704 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
29705 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
29706 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
29708 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
29710 if(this.tabPosition != "bottom"){
29711 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
29712 * @type Roo.Element
29714 this.bodyEl = Roo.get(this.createBody(this.el.dom));
29715 this.el.addClass("x-tabs-top");
29719 this.bodyEl.setStyle("position", "relative");
29721 this.active = null;
29722 this.activateDelegate = this.activate.createDelegate(this);
29727 * Fires when the active tab changes
29728 * @param {Roo.TabPanel} this
29729 * @param {Roo.TabPanelItem} activePanel The new active tab
29733 * @event beforetabchange
29734 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
29735 * @param {Roo.TabPanel} this
29736 * @param {Object} e Set cancel to true on this object to cancel the tab change
29737 * @param {Roo.TabPanelItem} tab The tab being changed to
29739 "beforetabchange" : true
29742 Roo.EventManager.onWindowResize(this.onResize, this);
29743 this.cpad = this.el.getPadding("lr");
29744 this.hiddenCount = 0;
29747 // toolbar on the tabbar support...
29748 if (this.toolbar) {
29749 var tcfg = this.toolbar;
29750 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
29751 this.toolbar = new Roo.Toolbar(tcfg);
29752 if (Roo.isSafari) {
29753 var tbl = tcfg.container.child('table', true);
29754 tbl.setAttribute('width', '100%');
29761 Roo.TabPanel.superclass.constructor.call(this);
29764 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
29766 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
29768 tabPosition : "top",
29770 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
29772 currentTabWidth : 0,
29774 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
29778 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
29782 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
29784 preferredTabWidth : 175,
29786 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
29788 resizeTabs : false,
29790 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
29792 monitorResize : true,
29794 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
29799 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
29800 * @param {String} id The id of the div to use <b>or create</b>
29801 * @param {String} text The text for the tab
29802 * @param {String} content (optional) Content to put in the TabPanelItem body
29803 * @param {Boolean} closable (optional) True to create a close icon on the tab
29804 * @return {Roo.TabPanelItem} The created TabPanelItem
29806 addTab : function(id, text, content, closable){
29807 var item = new Roo.TabPanelItem(this, id, text, closable);
29808 this.addTabItem(item);
29810 item.setContent(content);
29816 * Returns the {@link Roo.TabPanelItem} with the specified id/index
29817 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
29818 * @return {Roo.TabPanelItem}
29820 getTab : function(id){
29821 return this.items[id];
29825 * Hides the {@link Roo.TabPanelItem} with the specified id/index
29826 * @param {String/Number} id The id or index of the TabPanelItem to hide.
29828 hideTab : function(id){
29829 var t = this.items[id];
29832 this.hiddenCount++;
29833 this.autoSizeTabs();
29838 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
29839 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
29841 unhideTab : function(id){
29842 var t = this.items[id];
29844 t.setHidden(false);
29845 this.hiddenCount--;
29846 this.autoSizeTabs();
29851 * Adds an existing {@link Roo.TabPanelItem}.
29852 * @param {Roo.TabPanelItem} item The TabPanelItem to add
29854 addTabItem : function(item){
29855 this.items[item.id] = item;
29856 this.items.push(item);
29857 if(this.resizeTabs){
29858 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
29859 this.autoSizeTabs();
29866 * Removes a {@link Roo.TabPanelItem}.
29867 * @param {String/Number} id The id or index of the TabPanelItem to remove.
29869 removeTab : function(id){
29870 var items = this.items;
29871 var tab = items[id];
29872 if(!tab) { return; }
29873 var index = items.indexOf(tab);
29874 if(this.active == tab && items.length > 1){
29875 var newTab = this.getNextAvailable(index);
29880 this.stripEl.dom.removeChild(tab.pnode.dom);
29881 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
29882 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
29884 items.splice(index, 1);
29885 delete this.items[tab.id];
29886 tab.fireEvent("close", tab);
29887 tab.purgeListeners();
29888 this.autoSizeTabs();
29891 getNextAvailable : function(start){
29892 var items = this.items;
29894 // look for a next tab that will slide over to
29895 // replace the one being removed
29896 while(index < items.length){
29897 var item = items[++index];
29898 if(item && !item.isHidden()){
29902 // if one isn't found select the previous tab (on the left)
29905 var item = items[--index];
29906 if(item && !item.isHidden()){
29914 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
29915 * @param {String/Number} id The id or index of the TabPanelItem to disable.
29917 disableTab : function(id){
29918 var tab = this.items[id];
29919 if(tab && this.active != tab){
29925 * Enables a {@link Roo.TabPanelItem} that is disabled.
29926 * @param {String/Number} id The id or index of the TabPanelItem to enable.
29928 enableTab : function(id){
29929 var tab = this.items[id];
29934 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
29935 * @param {String/Number} id The id or index of the TabPanelItem to activate.
29936 * @return {Roo.TabPanelItem} The TabPanelItem.
29938 activate : function(id){
29939 var tab = this.items[id];
29943 if(tab == this.active || tab.disabled){
29947 this.fireEvent("beforetabchange", this, e, tab);
29948 if(e.cancel !== true && !tab.disabled){
29950 this.active.hide();
29952 this.active = this.items[id];
29953 this.active.show();
29954 this.fireEvent("tabchange", this, this.active);
29960 * Gets the active {@link Roo.TabPanelItem}.
29961 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
29963 getActiveTab : function(){
29964 return this.active;
29968 * Updates the tab body element to fit the height of the container element
29969 * for overflow scrolling
29970 * @param {Number} targetHeight (optional) Override the starting height from the elements height
29972 syncHeight : function(targetHeight){
29973 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
29974 var bm = this.bodyEl.getMargins();
29975 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
29976 this.bodyEl.setHeight(newHeight);
29980 onResize : function(){
29981 if(this.monitorResize){
29982 this.autoSizeTabs();
29987 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
29989 beginUpdate : function(){
29990 this.updating = true;
29994 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
29996 endUpdate : function(){
29997 this.updating = false;
29998 this.autoSizeTabs();
30002 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
30004 autoSizeTabs : function(){
30005 var count = this.items.length;
30006 var vcount = count - this.hiddenCount;
30007 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
30010 var w = Math.max(this.el.getWidth() - this.cpad, 10);
30011 var availWidth = Math.floor(w / vcount);
30012 var b = this.stripBody;
30013 if(b.getWidth() > w){
30014 var tabs = this.items;
30015 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
30016 if(availWidth < this.minTabWidth){
30017 /*if(!this.sleft){ // incomplete scrolling code
30018 this.createScrollButtons();
30021 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
30024 if(this.currentTabWidth < this.preferredTabWidth){
30025 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
30031 * Returns the number of tabs in this TabPanel.
30034 getCount : function(){
30035 return this.items.length;
30039 * Resizes all the tabs to the passed width
30040 * @param {Number} The new width
30042 setTabWidth : function(width){
30043 this.currentTabWidth = width;
30044 for(var i = 0, len = this.items.length; i < len; i++) {
30045 if(!this.items[i].isHidden()) {
30046 this.items[i].setWidth(width);
30052 * Destroys this TabPanel
30053 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
30055 destroy : function(removeEl){
30056 Roo.EventManager.removeResizeListener(this.onResize, this);
30057 for(var i = 0, len = this.items.length; i < len; i++){
30058 this.items[i].purgeListeners();
30060 if(removeEl === true){
30061 this.el.update("");
30068 * @class Roo.TabPanelItem
30069 * @extends Roo.util.Observable
30070 * Represents an individual item (tab plus body) in a TabPanel.
30071 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
30072 * @param {String} id The id of this TabPanelItem
30073 * @param {String} text The text for the tab of this TabPanelItem
30074 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
30076 Roo.TabPanelItem = function(tabPanel, id, text, closable){
30078 * The {@link Roo.TabPanel} this TabPanelItem belongs to
30079 * @type Roo.TabPanel
30081 this.tabPanel = tabPanel;
30083 * The id for this TabPanelItem
30088 this.disabled = false;
30092 this.loaded = false;
30093 this.closable = closable;
30096 * The body element for this TabPanelItem.
30097 * @type Roo.Element
30099 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
30100 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
30101 this.bodyEl.setStyle("display", "block");
30102 this.bodyEl.setStyle("zoom", "1");
30105 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
30107 this.el = Roo.get(els.el, true);
30108 this.inner = Roo.get(els.inner, true);
30109 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
30110 this.pnode = Roo.get(els.el.parentNode, true);
30111 this.el.on("mousedown", this.onTabMouseDown, this);
30112 this.el.on("click", this.onTabClick, this);
30115 var c = Roo.get(els.close, true);
30116 c.dom.title = this.closeText;
30117 c.addClassOnOver("close-over");
30118 c.on("click", this.closeClick, this);
30124 * Fires when this tab becomes the active tab.
30125 * @param {Roo.TabPanel} tabPanel The parent TabPanel
30126 * @param {Roo.TabPanelItem} this
30130 * @event beforeclose
30131 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
30132 * @param {Roo.TabPanelItem} this
30133 * @param {Object} e Set cancel to true on this object to cancel the close.
30135 "beforeclose": true,
30138 * Fires when this tab is closed.
30139 * @param {Roo.TabPanelItem} this
30143 * @event deactivate
30144 * Fires when this tab is no longer the active tab.
30145 * @param {Roo.TabPanel} tabPanel The parent TabPanel
30146 * @param {Roo.TabPanelItem} this
30148 "deactivate" : true
30150 this.hidden = false;
30152 Roo.TabPanelItem.superclass.constructor.call(this);
30155 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
30156 purgeListeners : function(){
30157 Roo.util.Observable.prototype.purgeListeners.call(this);
30158 this.el.removeAllListeners();
30161 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
30164 this.pnode.addClass("on");
30167 this.tabPanel.stripWrap.repaint();
30169 this.fireEvent("activate", this.tabPanel, this);
30173 * Returns true if this tab is the active tab.
30174 * @return {Boolean}
30176 isActive : function(){
30177 return this.tabPanel.getActiveTab() == this;
30181 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
30184 this.pnode.removeClass("on");
30186 this.fireEvent("deactivate", this.tabPanel, this);
30189 hideAction : function(){
30190 this.bodyEl.hide();
30191 this.bodyEl.setStyle("position", "absolute");
30192 this.bodyEl.setLeft("-20000px");
30193 this.bodyEl.setTop("-20000px");
30196 showAction : function(){
30197 this.bodyEl.setStyle("position", "relative");
30198 this.bodyEl.setTop("");
30199 this.bodyEl.setLeft("");
30200 this.bodyEl.show();
30204 * Set the tooltip for the tab.
30205 * @param {String} tooltip The tab's tooltip
30207 setTooltip : function(text){
30208 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
30209 this.textEl.dom.qtip = text;
30210 this.textEl.dom.removeAttribute('title');
30212 this.textEl.dom.title = text;
30216 onTabClick : function(e){
30217 e.preventDefault();
30218 this.tabPanel.activate(this.id);
30221 onTabMouseDown : function(e){
30222 e.preventDefault();
30223 this.tabPanel.activate(this.id);
30226 getWidth : function(){
30227 return this.inner.getWidth();
30230 setWidth : function(width){
30231 var iwidth = width - this.pnode.getPadding("lr");
30232 this.inner.setWidth(iwidth);
30233 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
30234 this.pnode.setWidth(width);
30238 * Show or hide the tab
30239 * @param {Boolean} hidden True to hide or false to show.
30241 setHidden : function(hidden){
30242 this.hidden = hidden;
30243 this.pnode.setStyle("display", hidden ? "none" : "");
30247 * Returns true if this tab is "hidden"
30248 * @return {Boolean}
30250 isHidden : function(){
30251 return this.hidden;
30255 * Returns the text for this tab
30258 getText : function(){
30262 autoSize : function(){
30263 //this.el.beginMeasure();
30264 this.textEl.setWidth(1);
30266 * #2804 [new] Tabs in Roojs
30267 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
30269 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
30270 //this.el.endMeasure();
30274 * Sets the text for the tab (Note: this also sets the tooltip text)
30275 * @param {String} text The tab's text and tooltip
30277 setText : function(text){
30279 this.textEl.update(text);
30280 this.setTooltip(text);
30281 if(!this.tabPanel.resizeTabs){
30286 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
30288 activate : function(){
30289 this.tabPanel.activate(this.id);
30293 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
30295 disable : function(){
30296 if(this.tabPanel.active != this){
30297 this.disabled = true;
30298 this.pnode.addClass("disabled");
30303 * Enables this TabPanelItem if it was previously disabled.
30305 enable : function(){
30306 this.disabled = false;
30307 this.pnode.removeClass("disabled");
30311 * Sets the content for this TabPanelItem.
30312 * @param {String} content The content
30313 * @param {Boolean} loadScripts true to look for and load scripts
30315 setContent : function(content, loadScripts){
30316 this.bodyEl.update(content, loadScripts);
30320 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
30321 * @return {Roo.UpdateManager} The UpdateManager
30323 getUpdateManager : function(){
30324 return this.bodyEl.getUpdateManager();
30328 * Set a URL to be used to load the content for this TabPanelItem.
30329 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
30330 * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
30331 * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this TabPanelItem is activated. (Defaults to false)
30332 * @return {Roo.UpdateManager} The UpdateManager
30334 setUrl : function(url, params, loadOnce){
30335 if(this.refreshDelegate){
30336 this.un('activate', this.refreshDelegate);
30338 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
30339 this.on("activate", this.refreshDelegate);
30340 return this.bodyEl.getUpdateManager();
30344 _handleRefresh : function(url, params, loadOnce){
30345 if(!loadOnce || !this.loaded){
30346 var updater = this.bodyEl.getUpdateManager();
30347 updater.update(url, params, this._setLoaded.createDelegate(this));
30352 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
30353 * Will fail silently if the setUrl method has not been called.
30354 * This does not activate the panel, just updates its content.
30356 refresh : function(){
30357 if(this.refreshDelegate){
30358 this.loaded = false;
30359 this.refreshDelegate();
30364 _setLoaded : function(){
30365 this.loaded = true;
30369 closeClick : function(e){
30372 this.fireEvent("beforeclose", this, o);
30373 if(o.cancel !== true){
30374 this.tabPanel.removeTab(this.id);
30378 * The text displayed in the tooltip for the close icon.
30381 closeText : "Close this tab"
30385 Roo.TabPanel.prototype.createStrip = function(container){
30386 var strip = document.createElement("div");
30387 strip.className = "x-tabs-wrap";
30388 container.appendChild(strip);
30392 Roo.TabPanel.prototype.createStripList = function(strip){
30393 // div wrapper for retard IE
30394 // returns the "tr" element.
30395 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
30396 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
30397 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
30398 return strip.firstChild.firstChild.firstChild.firstChild;
30401 Roo.TabPanel.prototype.createBody = function(container){
30402 var body = document.createElement("div");
30403 Roo.id(body, "tab-body");
30404 Roo.fly(body).addClass("x-tabs-body");
30405 container.appendChild(body);
30409 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
30410 var body = Roo.getDom(id);
30412 body = document.createElement("div");
30415 Roo.fly(body).addClass("x-tabs-item-body");
30416 bodyEl.insertBefore(body, bodyEl.firstChild);
30420 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
30421 var td = document.createElement("td");
30422 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
30423 //stripEl.appendChild(td);
30425 td.className = "x-tabs-closable";
30426 if(!this.closeTpl){
30427 this.closeTpl = new Roo.Template(
30428 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
30429 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
30430 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
30433 var el = this.closeTpl.overwrite(td, {"text": text});
30434 var close = el.getElementsByTagName("div")[0];
30435 var inner = el.getElementsByTagName("em")[0];
30436 return {"el": el, "close": close, "inner": inner};
30439 this.tabTpl = new Roo.Template(
30440 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
30441 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
30444 var el = this.tabTpl.overwrite(td, {"text": text});
30445 var inner = el.getElementsByTagName("em")[0];
30446 return {"el": el, "inner": inner};
30450 * Ext JS Library 1.1.1
30451 * Copyright(c) 2006-2007, Ext JS, LLC.
30453 * Originally Released Under LGPL - original licence link has changed is not relivant.
30456 * <script type="text/javascript">
30460 * @class Roo.Button
30461 * @extends Roo.util.Observable
30462 * Simple Button class
30463 * @cfg {String} text The button text
30464 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
30465 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
30466 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
30467 * @cfg {Object} scope The scope of the handler
30468 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
30469 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
30470 * @cfg {Boolean} hidden True to start hidden (defaults to false)
30471 * @cfg {Boolean} disabled True to start disabled (defaults to false)
30472 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
30473 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
30474 applies if enableToggle = true)
30475 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
30476 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
30477 an {@link Roo.util.ClickRepeater} config object (defaults to false).
30479 * Create a new button
30480 * @param {Object} config The config object
30482 Roo.Button = function(renderTo, config)
30486 renderTo = config.renderTo || false;
30489 Roo.apply(this, config);
30493 * Fires when this button is clicked
30494 * @param {Button} this
30495 * @param {EventObject} e The click event
30500 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
30501 * @param {Button} this
30502 * @param {Boolean} pressed
30507 * Fires when the mouse hovers over the button
30508 * @param {Button} this
30509 * @param {Event} e The event object
30511 'mouseover' : true,
30514 * Fires when the mouse exits the button
30515 * @param {Button} this
30516 * @param {Event} e The event object
30521 * Fires when the button is rendered
30522 * @param {Button} this
30527 this.menu = Roo.menu.MenuMgr.get(this.menu);
30529 // register listeners first!! - so render can be captured..
30530 Roo.util.Observable.call(this);
30532 this.render(renderTo);
30538 Roo.extend(Roo.Button, Roo.util.Observable, {
30544 * Read-only. True if this button is hidden
30549 * Read-only. True if this button is disabled
30554 * Read-only. True if this button is pressed (only if enableToggle = true)
30560 * @cfg {Number} tabIndex
30561 * The DOM tabIndex for this button (defaults to undefined)
30563 tabIndex : undefined,
30566 * @cfg {Boolean} enableToggle
30567 * True to enable pressed/not pressed toggling (defaults to false)
30569 enableToggle: false,
30571 * @cfg {Roo.menu.Menu} menu
30572 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
30576 * @cfg {String} menuAlign
30577 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
30579 menuAlign : "tl-bl?",
30582 * @cfg {String} iconCls
30583 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
30585 iconCls : undefined,
30587 * @cfg {String} type
30588 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
30593 menuClassTarget: 'tr',
30596 * @cfg {String} clickEvent
30597 * The type of event to map to the button's event handler (defaults to 'click')
30599 clickEvent : 'click',
30602 * @cfg {Boolean} handleMouseEvents
30603 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
30605 handleMouseEvents : true,
30608 * @cfg {String} tooltipType
30609 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
30611 tooltipType : 'qtip',
30614 * @cfg {String} cls
30615 * A CSS class to apply to the button's main element.
30619 * @cfg {Roo.Template} template (Optional)
30620 * An {@link Roo.Template} with which to create the Button's main element. This Template must
30621 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
30622 * require code modifications if required elements (e.g. a button) aren't present.
30626 render : function(renderTo){
30628 if(this.hideParent){
30629 this.parentEl = Roo.get(renderTo);
30631 if(!this.dhconfig){
30632 if(!this.template){
30633 if(!Roo.Button.buttonTemplate){
30634 // hideous table template
30635 Roo.Button.buttonTemplate = new Roo.Template(
30636 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
30637 '<td class="x-btn-left"><i> </i></td><td class="x-btn-center"><em unselectable="on"><button class="x-btn-text" type="{1}">{0}</button></em></td><td class="x-btn-right"><i> </i></td>',
30638 "</tr></tbody></table>");
30640 this.template = Roo.Button.buttonTemplate;
30642 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
30643 var btnEl = btn.child("button:first");
30644 btnEl.on('focus', this.onFocus, this);
30645 btnEl.on('blur', this.onBlur, this);
30647 btn.addClass(this.cls);
30650 btnEl.setStyle('background-image', 'url(' +this.icon +')');
30653 btnEl.addClass(this.iconCls);
30655 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
30658 if(this.tabIndex !== undefined){
30659 btnEl.dom.tabIndex = this.tabIndex;
30662 if(typeof this.tooltip == 'object'){
30663 Roo.QuickTips.tips(Roo.apply({
30667 btnEl.dom[this.tooltipType] = this.tooltip;
30671 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
30675 this.el.dom.id = this.el.id = this.id;
30678 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
30679 this.menu.on("show", this.onMenuShow, this);
30680 this.menu.on("hide", this.onMenuHide, this);
30682 btn.addClass("x-btn");
30683 if(Roo.isIE && !Roo.isIE7){
30684 this.autoWidth.defer(1, this);
30688 if(this.handleMouseEvents){
30689 btn.on("mouseover", this.onMouseOver, this);
30690 btn.on("mouseout", this.onMouseOut, this);
30691 btn.on("mousedown", this.onMouseDown, this);
30693 btn.on(this.clickEvent, this.onClick, this);
30694 //btn.on("mouseup", this.onMouseUp, this);
30701 Roo.ButtonToggleMgr.register(this);
30703 this.el.addClass("x-btn-pressed");
30706 var repeater = new Roo.util.ClickRepeater(btn,
30707 typeof this.repeat == "object" ? this.repeat : {}
30709 repeater.on("click", this.onClick, this);
30712 this.fireEvent('render', this);
30716 * Returns the button's underlying element
30717 * @return {Roo.Element} The element
30719 getEl : function(){
30724 * Destroys this Button and removes any listeners.
30726 destroy : function(){
30727 Roo.ButtonToggleMgr.unregister(this);
30728 this.el.removeAllListeners();
30729 this.purgeListeners();
30734 autoWidth : function(){
30736 this.el.setWidth("auto");
30737 if(Roo.isIE7 && Roo.isStrict){
30738 var ib = this.el.child('button');
30739 if(ib && ib.getWidth() > 20){
30741 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
30746 this.el.beginMeasure();
30748 if(this.el.getWidth() < this.minWidth){
30749 this.el.setWidth(this.minWidth);
30752 this.el.endMeasure();
30759 * Assigns this button's click handler
30760 * @param {Function} handler The function to call when the button is clicked
30761 * @param {Object} scope (optional) Scope for the function passed in
30763 setHandler : function(handler, scope){
30764 this.handler = handler;
30765 this.scope = scope;
30769 * Sets this button's text
30770 * @param {String} text The button text
30772 setText : function(text){
30775 this.el.child("td.x-btn-center button.x-btn-text").update(text);
30781 * Gets the text for this button
30782 * @return {String} The button text
30784 getText : function(){
30792 this.hidden = false;
30794 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
30802 this.hidden = true;
30804 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
30809 * Convenience function for boolean show/hide
30810 * @param {Boolean} visible True to show, false to hide
30812 setVisible: function(visible){
30821 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
30822 * @param {Boolean} state (optional) Force a particular state
30824 toggle : function(state){
30825 state = state === undefined ? !this.pressed : state;
30826 if(state != this.pressed){
30828 this.el.addClass("x-btn-pressed");
30829 this.pressed = true;
30830 this.fireEvent("toggle", this, true);
30832 this.el.removeClass("x-btn-pressed");
30833 this.pressed = false;
30834 this.fireEvent("toggle", this, false);
30836 if(this.toggleHandler){
30837 this.toggleHandler.call(this.scope || this, this, state);
30845 focus : function(){
30846 this.el.child('button:first').focus();
30850 * Disable this button
30852 disable : function(){
30854 this.el.addClass("x-btn-disabled");
30856 this.disabled = true;
30860 * Enable this button
30862 enable : function(){
30864 this.el.removeClass("x-btn-disabled");
30866 this.disabled = false;
30870 * Convenience function for boolean enable/disable
30871 * @param {Boolean} enabled True to enable, false to disable
30873 setDisabled : function(v){
30874 this[v !== true ? "enable" : "disable"]();
30878 onClick : function(e)
30881 e.preventDefault();
30886 if(!this.disabled){
30887 if(this.enableToggle){
30890 if(this.menu && !this.menu.isVisible()){
30891 this.menu.show(this.el, this.menuAlign);
30893 this.fireEvent("click", this, e);
30895 this.el.removeClass("x-btn-over");
30896 this.handler.call(this.scope || this, this, e);
30901 onMouseOver : function(e){
30902 if(!this.disabled){
30903 this.el.addClass("x-btn-over");
30904 this.fireEvent('mouseover', this, e);
30908 onMouseOut : function(e){
30909 if(!e.within(this.el, true)){
30910 this.el.removeClass("x-btn-over");
30911 this.fireEvent('mouseout', this, e);
30915 onFocus : function(e){
30916 if(!this.disabled){
30917 this.el.addClass("x-btn-focus");
30921 onBlur : function(e){
30922 this.el.removeClass("x-btn-focus");
30925 onMouseDown : function(e){
30926 if(!this.disabled && e.button == 0){
30927 this.el.addClass("x-btn-click");
30928 Roo.get(document).on('mouseup', this.onMouseUp, this);
30932 onMouseUp : function(e){
30934 this.el.removeClass("x-btn-click");
30935 Roo.get(document).un('mouseup', this.onMouseUp, this);
30939 onMenuShow : function(e){
30940 this.el.addClass("x-btn-menu-active");
30943 onMenuHide : function(e){
30944 this.el.removeClass("x-btn-menu-active");
30948 // Private utility class used by Button
30949 Roo.ButtonToggleMgr = function(){
30952 function toggleGroup(btn, state){
30954 var g = groups[btn.toggleGroup];
30955 for(var i = 0, l = g.length; i < l; i++){
30957 g[i].toggle(false);
30964 register : function(btn){
30965 if(!btn.toggleGroup){
30968 var g = groups[btn.toggleGroup];
30970 g = groups[btn.toggleGroup] = [];
30973 btn.on("toggle", toggleGroup);
30976 unregister : function(btn){
30977 if(!btn.toggleGroup){
30980 var g = groups[btn.toggleGroup];
30983 btn.un("toggle", toggleGroup);
30989 * Ext JS Library 1.1.1
30990 * Copyright(c) 2006-2007, Ext JS, LLC.
30992 * Originally Released Under LGPL - original licence link has changed is not relivant.
30995 * <script type="text/javascript">
30999 * @class Roo.SplitButton
31000 * @extends Roo.Button
31001 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
31002 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
31003 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
31004 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
31005 * @cfg {String} arrowTooltip The title attribute of the arrow
31007 * Create a new menu button
31008 * @param {String/HTMLElement/Element} renderTo The element to append the button to
31009 * @param {Object} config The config object
31011 Roo.SplitButton = function(renderTo, config){
31012 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
31014 * @event arrowclick
31015 * Fires when this button's arrow is clicked
31016 * @param {SplitButton} this
31017 * @param {EventObject} e The click event
31019 this.addEvents({"arrowclick":true});
31022 Roo.extend(Roo.SplitButton, Roo.Button, {
31023 render : function(renderTo){
31024 // this is one sweet looking template!
31025 var tpl = new Roo.Template(
31026 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
31027 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
31028 '<tr><td class="x-btn-left"><i> </i></td><td class="x-btn-center"><button class="x-btn-text" type="{1}">{0}</button></td></tr>',
31029 "</tbody></table></td><td>",
31030 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
31031 '<tr><td class="x-btn-center"><button class="x-btn-menu-arrow-el" type="button"> </button></td><td class="x-btn-right"><i> </i></td></tr>',
31032 "</tbody></table></td></tr></table>"
31034 var btn = tpl.append(renderTo, [this.text, this.type], true);
31035 var btnEl = btn.child("button");
31037 btn.addClass(this.cls);
31040 btnEl.setStyle('background-image', 'url(' +this.icon +')');
31043 btnEl.addClass(this.iconCls);
31045 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
31049 if(this.handleMouseEvents){
31050 btn.on("mouseover", this.onMouseOver, this);
31051 btn.on("mouseout", this.onMouseOut, this);
31052 btn.on("mousedown", this.onMouseDown, this);
31053 btn.on("mouseup", this.onMouseUp, this);
31055 btn.on(this.clickEvent, this.onClick, this);
31057 if(typeof this.tooltip == 'object'){
31058 Roo.QuickTips.tips(Roo.apply({
31062 btnEl.dom[this.tooltipType] = this.tooltip;
31065 if(this.arrowTooltip){
31066 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
31075 this.el.addClass("x-btn-pressed");
31077 if(Roo.isIE && !Roo.isIE7){
31078 this.autoWidth.defer(1, this);
31083 this.menu.on("show", this.onMenuShow, this);
31084 this.menu.on("hide", this.onMenuHide, this);
31086 this.fireEvent('render', this);
31090 autoWidth : function(){
31092 var tbl = this.el.child("table:first");
31093 var tbl2 = this.el.child("table:last");
31094 this.el.setWidth("auto");
31095 tbl.setWidth("auto");
31096 if(Roo.isIE7 && Roo.isStrict){
31097 var ib = this.el.child('button:first');
31098 if(ib && ib.getWidth() > 20){
31100 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
31105 this.el.beginMeasure();
31107 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
31108 tbl.setWidth(this.minWidth-tbl2.getWidth());
31111 this.el.endMeasure();
31114 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
31118 * Sets this button's click handler
31119 * @param {Function} handler The function to call when the button is clicked
31120 * @param {Object} scope (optional) Scope for the function passed above
31122 setHandler : function(handler, scope){
31123 this.handler = handler;
31124 this.scope = scope;
31128 * Sets this button's arrow click handler
31129 * @param {Function} handler The function to call when the arrow is clicked
31130 * @param {Object} scope (optional) Scope for the function passed above
31132 setArrowHandler : function(handler, scope){
31133 this.arrowHandler = handler;
31134 this.scope = scope;
31140 focus : function(){
31142 this.el.child("button:first").focus();
31147 onClick : function(e){
31148 e.preventDefault();
31149 if(!this.disabled){
31150 if(e.getTarget(".x-btn-menu-arrow-wrap")){
31151 if(this.menu && !this.menu.isVisible()){
31152 this.menu.show(this.el, this.menuAlign);
31154 this.fireEvent("arrowclick", this, e);
31155 if(this.arrowHandler){
31156 this.arrowHandler.call(this.scope || this, this, e);
31159 this.fireEvent("click", this, e);
31161 this.handler.call(this.scope || this, this, e);
31167 onMouseDown : function(e){
31168 if(!this.disabled){
31169 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
31173 onMouseUp : function(e){
31174 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
31179 // backwards compat
31180 Roo.MenuButton = Roo.SplitButton;/*
31182 * Ext JS Library 1.1.1
31183 * Copyright(c) 2006-2007, Ext JS, LLC.
31185 * Originally Released Under LGPL - original licence link has changed is not relivant.
31188 * <script type="text/javascript">
31192 * @class Roo.Toolbar
31193 * @children Roo.Toolbar.Item Roo.Toolbar.Button Roo.Toolbar.SplitButton Roo.form.Field
31194 * Basic Toolbar class.
31196 * Creates a new Toolbar
31197 * @param {Object} container The config object
31199 Roo.Toolbar = function(container, buttons, config)
31201 /// old consturctor format still supported..
31202 if(container instanceof Array){ // omit the container for later rendering
31203 buttons = container;
31207 if (typeof(container) == 'object' && container.xtype) {
31208 config = container;
31209 container = config.container;
31210 buttons = config.buttons || []; // not really - use items!!
31213 if (config && config.items) {
31214 xitems = config.items;
31215 delete config.items;
31217 Roo.apply(this, config);
31218 this.buttons = buttons;
31221 this.render(container);
31223 this.xitems = xitems;
31224 Roo.each(xitems, function(b) {
31230 Roo.Toolbar.prototype = {
31232 * @cfg {Array} items
31233 * array of button configs or elements to add (will be converted to a MixedCollection)
31237 * @cfg {String/HTMLElement/Element} container
31238 * The id or element that will contain the toolbar
31241 render : function(ct){
31242 this.el = Roo.get(ct);
31244 this.el.addClass(this.cls);
31246 // using a table allows for vertical alignment
31247 // 100% width is needed by Safari...
31248 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
31249 this.tr = this.el.child("tr", true);
31251 this.items = new Roo.util.MixedCollection(false, function(o){
31252 return o.id || ("item" + (++autoId));
31255 this.add.apply(this, this.buttons);
31256 delete this.buttons;
31261 * Adds element(s) to the toolbar -- this function takes a variable number of
31262 * arguments of mixed type and adds them to the toolbar.
31263 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
31265 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
31266 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
31267 * <li>Field: Any form field (equivalent to {@link #addField})</li>
31268 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
31269 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
31270 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
31271 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
31272 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
31273 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
31275 * @param {Mixed} arg2
31276 * @param {Mixed} etc.
31279 var a = arguments, l = a.length;
31280 for(var i = 0; i < l; i++){
31285 _add : function(el) {
31288 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
31291 if (el.applyTo){ // some kind of form field
31292 return this.addField(el);
31294 if (el.render){ // some kind of Toolbar.Item
31295 return this.addItem(el);
31297 if (typeof el == "string"){ // string
31298 if(el == "separator" || el == "-"){
31299 return this.addSeparator();
31302 return this.addSpacer();
31305 return this.addFill();
31307 return this.addText(el);
31310 if(el.tagName){ // element
31311 return this.addElement(el);
31313 if(typeof el == "object"){ // must be button config?
31314 return this.addButton(el);
31316 // and now what?!?!
31322 * Add an Xtype element
31323 * @param {Object} xtype Xtype Object
31324 * @return {Object} created Object
31326 addxtype : function(e){
31327 return this.add(e);
31331 * Returns the Element for this toolbar.
31332 * @return {Roo.Element}
31334 getEl : function(){
31340 * @return {Roo.Toolbar.Item} The separator item
31342 addSeparator : function(){
31343 return this.addItem(new Roo.Toolbar.Separator());
31347 * Adds a spacer element
31348 * @return {Roo.Toolbar.Spacer} The spacer item
31350 addSpacer : function(){
31351 return this.addItem(new Roo.Toolbar.Spacer());
31355 * Adds a fill element that forces subsequent additions to the right side of the toolbar
31356 * @return {Roo.Toolbar.Fill} The fill item
31358 addFill : function(){
31359 return this.addItem(new Roo.Toolbar.Fill());
31363 * Adds any standard HTML element to the toolbar
31364 * @param {String/HTMLElement/Element} el The element or id of the element to add
31365 * @return {Roo.Toolbar.Item} The element's item
31367 addElement : function(el){
31368 return this.addItem(new Roo.Toolbar.Item(el));
31371 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
31372 * @type Roo.util.MixedCollection
31377 * Adds any Toolbar.Item or subclass
31378 * @param {Roo.Toolbar.Item} item
31379 * @return {Roo.Toolbar.Item} The item
31381 addItem : function(item){
31382 var td = this.nextBlock();
31384 this.items.add(item);
31389 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
31390 * @param {Object/Array} config A button config or array of configs
31391 * @return {Roo.Toolbar.Button/Array}
31393 addButton : function(config){
31394 if(config instanceof Array){
31396 for(var i = 0, len = config.length; i < len; i++) {
31397 buttons.push(this.addButton(config[i]));
31402 if(!(config instanceof Roo.Toolbar.Button)){
31404 new Roo.Toolbar.SplitButton(config) :
31405 new Roo.Toolbar.Button(config);
31407 var td = this.nextBlock();
31414 * Adds text to the toolbar
31415 * @param {String} text The text to add
31416 * @return {Roo.Toolbar.Item} The element's item
31418 addText : function(text){
31419 return this.addItem(new Roo.Toolbar.TextItem(text));
31423 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
31424 * @param {Number} index The index where the item is to be inserted
31425 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
31426 * @return {Roo.Toolbar.Button/Item}
31428 insertButton : function(index, item){
31429 if(item instanceof Array){
31431 for(var i = 0, len = item.length; i < len; i++) {
31432 buttons.push(this.insertButton(index + i, item[i]));
31436 if (!(item instanceof Roo.Toolbar.Button)){
31437 item = new Roo.Toolbar.Button(item);
31439 var td = document.createElement("td");
31440 this.tr.insertBefore(td, this.tr.childNodes[index]);
31442 this.items.insert(index, item);
31447 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
31448 * @param {Object} config
31449 * @return {Roo.Toolbar.Item} The element's item
31451 addDom : function(config, returnEl){
31452 var td = this.nextBlock();
31453 Roo.DomHelper.overwrite(td, config);
31454 var ti = new Roo.Toolbar.Item(td.firstChild);
31456 this.items.add(ti);
31461 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
31462 * @type Roo.util.MixedCollection
31467 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
31468 * Note: the field should not have been rendered yet. For a field that has already been
31469 * rendered, use {@link #addElement}.
31470 * @param {Roo.form.Field} field
31471 * @return {Roo.ToolbarItem}
31475 addField : function(field) {
31476 if (!this.fields) {
31478 this.fields = new Roo.util.MixedCollection(false, function(o){
31479 return o.id || ("item" + (++autoId));
31484 var td = this.nextBlock();
31486 var ti = new Roo.Toolbar.Item(td.firstChild);
31488 this.items.add(ti);
31489 this.fields.add(field);
31500 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
31501 this.el.child('div').hide();
31509 this.el.child('div').show();
31513 nextBlock : function(){
31514 var td = document.createElement("td");
31515 this.tr.appendChild(td);
31520 destroy : function(){
31521 if(this.items){ // rendered?
31522 Roo.destroy.apply(Roo, this.items.items);
31524 if(this.fields){ // rendered?
31525 Roo.destroy.apply(Roo, this.fields.items);
31527 Roo.Element.uncache(this.el, this.tr);
31532 * @class Roo.Toolbar.Item
31533 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
31535 * Creates a new Item
31536 * @param {HTMLElement} el
31538 Roo.Toolbar.Item = function(el){
31540 if (typeof (el.xtype) != 'undefined') {
31545 this.el = Roo.getDom(el);
31546 this.id = Roo.id(this.el);
31547 this.hidden = false;
31552 * Fires when the button is rendered
31553 * @param {Button} this
31557 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
31559 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
31560 //Roo.Toolbar.Item.prototype = {
31563 * Get this item's HTML Element
31564 * @return {HTMLElement}
31566 getEl : function(){
31571 render : function(td){
31574 td.appendChild(this.el);
31576 this.fireEvent('render', this);
31580 * Removes and destroys this item.
31582 destroy : function(){
31583 this.td.parentNode.removeChild(this.td);
31590 this.hidden = false;
31591 this.td.style.display = "";
31598 this.hidden = true;
31599 this.td.style.display = "none";
31603 * Convenience function for boolean show/hide.
31604 * @param {Boolean} visible true to show/false to hide
31606 setVisible: function(visible){
31615 * Try to focus this item.
31617 focus : function(){
31618 Roo.fly(this.el).focus();
31622 * Disables this item.
31624 disable : function(){
31625 Roo.fly(this.td).addClass("x-item-disabled");
31626 this.disabled = true;
31627 this.el.disabled = true;
31631 * Enables this item.
31633 enable : function(){
31634 Roo.fly(this.td).removeClass("x-item-disabled");
31635 this.disabled = false;
31636 this.el.disabled = false;
31642 * @class Roo.Toolbar.Separator
31643 * @extends Roo.Toolbar.Item
31644 * A simple toolbar separator class
31646 * Creates a new Separator
31648 Roo.Toolbar.Separator = function(cfg){
31650 var s = document.createElement("span");
31651 s.className = "ytb-sep";
31656 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
31658 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
31659 enable:Roo.emptyFn,
31660 disable:Roo.emptyFn,
31665 * @class Roo.Toolbar.Spacer
31666 * @extends Roo.Toolbar.Item
31667 * A simple element that adds extra horizontal space to a toolbar.
31669 * Creates a new Spacer
31671 Roo.Toolbar.Spacer = function(cfg){
31672 var s = document.createElement("div");
31673 s.className = "ytb-spacer";
31677 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
31679 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
31680 enable:Roo.emptyFn,
31681 disable:Roo.emptyFn,
31686 * @class Roo.Toolbar.Fill
31687 * @extends Roo.Toolbar.Spacer
31688 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
31690 * Creates a new Spacer
31692 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
31694 render : function(td){
31695 td.style.width = '100%';
31696 Roo.Toolbar.Fill.superclass.render.call(this, td);
31701 * @class Roo.Toolbar.TextItem
31702 * @extends Roo.Toolbar.Item
31703 * A simple class that renders text directly into a toolbar.
31705 * Creates a new TextItem
31706 * @cfg {string} text
31708 Roo.Toolbar.TextItem = function(cfg){
31709 var text = cfg || "";
31710 if (typeof(cfg) == 'object') {
31711 text = cfg.text || "";
31715 var s = document.createElement("span");
31716 s.className = "ytb-text";
31717 s.innerHTML = text;
31722 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
31724 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
31727 enable:Roo.emptyFn,
31728 disable:Roo.emptyFn,
31731 * Shows this button
31734 this.hidden = false;
31735 this.el.style.display = "";
31739 * Hides this button
31742 this.hidden = true;
31743 this.el.style.display = "none";
31749 * @class Roo.Toolbar.Button
31750 * @extends Roo.Button
31751 * A button that renders into a toolbar.
31753 * Creates a new Button
31754 * @param {Object} config A standard {@link Roo.Button} config object
31756 Roo.Toolbar.Button = function(config){
31757 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
31759 Roo.extend(Roo.Toolbar.Button, Roo.Button,
31763 render : function(td){
31765 Roo.Toolbar.Button.superclass.render.call(this, td);
31769 * Removes and destroys this button
31771 destroy : function(){
31772 Roo.Toolbar.Button.superclass.destroy.call(this);
31773 this.td.parentNode.removeChild(this.td);
31777 * Shows this button
31780 this.hidden = false;
31781 this.td.style.display = "";
31785 * Hides this button
31788 this.hidden = true;
31789 this.td.style.display = "none";
31793 * Disables this item
31795 disable : function(){
31796 Roo.fly(this.td).addClass("x-item-disabled");
31797 this.disabled = true;
31801 * Enables this item
31803 enable : function(){
31804 Roo.fly(this.td).removeClass("x-item-disabled");
31805 this.disabled = false;
31808 // backwards compat
31809 Roo.ToolbarButton = Roo.Toolbar.Button;
31812 * @class Roo.Toolbar.SplitButton
31813 * @extends Roo.SplitButton
31814 * A menu button that renders into a toolbar.
31816 * Creates a new SplitButton
31817 * @param {Object} config A standard {@link Roo.SplitButton} config object
31819 Roo.Toolbar.SplitButton = function(config){
31820 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
31822 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
31823 render : function(td){
31825 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
31829 * Removes and destroys this button
31831 destroy : function(){
31832 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
31833 this.td.parentNode.removeChild(this.td);
31837 * Shows this button
31840 this.hidden = false;
31841 this.td.style.display = "";
31845 * Hides this button
31848 this.hidden = true;
31849 this.td.style.display = "none";
31853 // backwards compat
31854 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
31856 * Ext JS Library 1.1.1
31857 * Copyright(c) 2006-2007, Ext JS, LLC.
31859 * Originally Released Under LGPL - original licence link has changed is not relivant.
31862 * <script type="text/javascript">
31866 * @class Roo.PagingToolbar
31867 * @extends Roo.Toolbar
31868 * @children Roo.Toolbar.Item Roo.Toolbar.Button Roo.Toolbar.SplitButton Roo.form.Field
31869 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
31871 * Create a new PagingToolbar
31872 * @param {Object} config The config object
31874 Roo.PagingToolbar = function(el, ds, config)
31876 // old args format still supported... - xtype is prefered..
31877 if (typeof(el) == 'object' && el.xtype) {
31878 // created from xtype...
31880 ds = el.dataSource;
31881 el = config.container;
31884 if (config.items) {
31885 items = config.items;
31889 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
31892 this.renderButtons(this.el);
31895 // supprot items array.
31897 Roo.each(items, function(e) {
31898 this.add(Roo.factory(e));
31903 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
31906 * @cfg {String/HTMLElement/Element} container
31907 * container The id or element that will contain the toolbar
31910 * @cfg {Boolean} displayInfo
31911 * True to display the displayMsg (defaults to false)
31916 * @cfg {Number} pageSize
31917 * The number of records to display per page (defaults to 20)
31921 * @cfg {String} displayMsg
31922 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
31924 displayMsg : 'Displaying {0} - {1} of {2}',
31926 * @cfg {String} emptyMsg
31927 * The message to display when no records are found (defaults to "No data to display")
31929 emptyMsg : 'No data to display',
31931 * Customizable piece of the default paging text (defaults to "Page")
31934 beforePageText : "Page",
31936 * Customizable piece of the default paging text (defaults to "of %0")
31939 afterPageText : "of {0}",
31941 * Customizable piece of the default paging text (defaults to "First Page")
31944 firstText : "First Page",
31946 * Customizable piece of the default paging text (defaults to "Previous Page")
31949 prevText : "Previous Page",
31951 * Customizable piece of the default paging text (defaults to "Next Page")
31954 nextText : "Next Page",
31956 * Customizable piece of the default paging text (defaults to "Last Page")
31959 lastText : "Last Page",
31961 * Customizable piece of the default paging text (defaults to "Refresh")
31964 refreshText : "Refresh",
31967 renderButtons : function(el){
31968 Roo.PagingToolbar.superclass.render.call(this, el);
31969 this.first = this.addButton({
31970 tooltip: this.firstText,
31971 cls: "x-btn-icon x-grid-page-first",
31973 handler: this.onClick.createDelegate(this, ["first"])
31975 this.prev = this.addButton({
31976 tooltip: this.prevText,
31977 cls: "x-btn-icon x-grid-page-prev",
31979 handler: this.onClick.createDelegate(this, ["prev"])
31981 //this.addSeparator();
31982 this.add(this.beforePageText);
31983 this.field = Roo.get(this.addDom({
31988 cls: "x-grid-page-number"
31990 this.field.on("keydown", this.onPagingKeydown, this);
31991 this.field.on("focus", function(){this.dom.select();});
31992 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
31993 this.field.setHeight(18);
31994 //this.addSeparator();
31995 this.next = this.addButton({
31996 tooltip: this.nextText,
31997 cls: "x-btn-icon x-grid-page-next",
31999 handler: this.onClick.createDelegate(this, ["next"])
32001 this.last = this.addButton({
32002 tooltip: this.lastText,
32003 cls: "x-btn-icon x-grid-page-last",
32005 handler: this.onClick.createDelegate(this, ["last"])
32007 //this.addSeparator();
32008 this.loading = this.addButton({
32009 tooltip: this.refreshText,
32010 cls: "x-btn-icon x-grid-loading",
32011 handler: this.onClick.createDelegate(this, ["refresh"])
32014 if(this.displayInfo){
32015 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
32020 updateInfo : function(){
32021 if(this.displayEl){
32022 var count = this.ds.getCount();
32023 var msg = count == 0 ?
32027 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
32029 this.displayEl.update(msg);
32034 onLoad : function(ds, r, o){
32035 this.cursor = o.params ? o.params.start : 0;
32036 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
32038 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
32039 this.field.dom.value = ap;
32040 this.first.setDisabled(ap == 1);
32041 this.prev.setDisabled(ap == 1);
32042 this.next.setDisabled(ap == ps);
32043 this.last.setDisabled(ap == ps);
32044 this.loading.enable();
32049 getPageData : function(){
32050 var total = this.ds.getTotalCount();
32053 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
32054 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
32059 onLoadError : function(){
32060 this.loading.enable();
32064 onPagingKeydown : function(e){
32065 var k = e.getKey();
32066 var d = this.getPageData();
32068 var v = this.field.dom.value, pageNum;
32069 if(!v || isNaN(pageNum = parseInt(v, 10))){
32070 this.field.dom.value = d.activePage;
32073 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
32074 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
32077 else if(k == e.HOME || (k == e.UP && e.ctrlKey) || (k == e.PAGEUP && e.ctrlKey) || (k == e.RIGHT && e.ctrlKey) || k == e.END || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey))
32079 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
32080 this.field.dom.value = pageNum;
32081 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
32084 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
32086 var v = this.field.dom.value, pageNum;
32087 var increment = (e.shiftKey) ? 10 : 1;
32088 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
32091 if(!v || isNaN(pageNum = parseInt(v, 10))) {
32092 this.field.dom.value = d.activePage;
32095 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
32097 this.field.dom.value = parseInt(v, 10) + increment;
32098 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
32099 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
32106 beforeLoad : function(){
32108 this.loading.disable();
32113 onClick : function(which){
32117 ds.load({params:{start: 0, limit: this.pageSize}});
32120 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
32123 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
32126 var total = ds.getTotalCount();
32127 var extra = total % this.pageSize;
32128 var lastStart = extra ? (total - extra) : total-this.pageSize;
32129 ds.load({params:{start: lastStart, limit: this.pageSize}});
32132 ds.load({params:{start: this.cursor, limit: this.pageSize}});
32138 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
32139 * @param {Roo.data.Store} store The data store to unbind
32141 unbind : function(ds){
32142 ds.un("beforeload", this.beforeLoad, this);
32143 ds.un("load", this.onLoad, this);
32144 ds.un("loadexception", this.onLoadError, this);
32145 ds.un("remove", this.updateInfo, this);
32146 ds.un("add", this.updateInfo, this);
32147 this.ds = undefined;
32151 * Binds the paging toolbar to the specified {@link Roo.data.Store}
32152 * @param {Roo.data.Store} store The data store to bind
32154 bind : function(ds){
32155 ds.on("beforeload", this.beforeLoad, this);
32156 ds.on("load", this.onLoad, this);
32157 ds.on("loadexception", this.onLoadError, this);
32158 ds.on("remove", this.updateInfo, this);
32159 ds.on("add", this.updateInfo, this);
32164 * Ext JS Library 1.1.1
32165 * Copyright(c) 2006-2007, Ext JS, LLC.
32167 * Originally Released Under LGPL - original licence link has changed is not relivant.
32170 * <script type="text/javascript">
32174 * @class Roo.Resizable
32175 * @extends Roo.util.Observable
32176 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
32177 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
32178 * the textarea in a div and set "resizeChild" to true (or to the id of the element), <b>or</b> set wrap:true in your config and
32179 * the element will be wrapped for you automatically.</p>
32180 * <p>Here is the list of valid resize handles:</p>
32183 ------ -------------------
32192 'hd' horizontal drag
32195 * <p>Here's an example showing the creation of a typical Resizable:</p>
32197 var resizer = new Roo.Resizable("element-id", {
32205 resizer.on("resize", myHandler);
32207 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
32208 * resizer.east.setDisplayed(false);</p>
32209 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
32210 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
32211 * resize operation's new size (defaults to [0, 0])
32212 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
32213 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
32214 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
32215 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
32216 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
32217 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
32218 * @cfg {Number} width The width of the element in pixels (defaults to null)
32219 * @cfg {Number} height The height of the element in pixels (defaults to null)
32220 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
32221 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
32222 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
32223 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
32224 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
32225 * in favor of the handles config option (defaults to false)
32226 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
32227 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
32228 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
32229 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
32230 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
32231 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
32232 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
32233 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
32234 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
32235 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
32236 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
32238 * Create a new resizable component
32239 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
32240 * @param {Object} config configuration options
32242 Roo.Resizable = function(el, config)
32244 this.el = Roo.get(el);
32246 if(config && config.wrap){
32247 config.resizeChild = this.el;
32248 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
32249 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
32250 this.el.setStyle("overflow", "hidden");
32251 this.el.setPositioning(config.resizeChild.getPositioning());
32252 config.resizeChild.clearPositioning();
32253 if(!config.width || !config.height){
32254 var csize = config.resizeChild.getSize();
32255 this.el.setSize(csize.width, csize.height);
32257 if(config.pinned && !config.adjustments){
32258 config.adjustments = "auto";
32262 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
32263 this.proxy.unselectable();
32264 this.proxy.enableDisplayMode('block');
32266 Roo.apply(this, config);
32269 this.disableTrackOver = true;
32270 this.el.addClass("x-resizable-pinned");
32272 // if the element isn't positioned, make it relative
32273 var position = this.el.getStyle("position");
32274 if(position != "absolute" && position != "fixed"){
32275 this.el.setStyle("position", "relative");
32277 if(!this.handles){ // no handles passed, must be legacy style
32278 this.handles = 's,e,se';
32279 if(this.multiDirectional){
32280 this.handles += ',n,w';
32283 if(this.handles == "all"){
32284 this.handles = "n s e w ne nw se sw";
32286 var hs = this.handles.split(/\s*?[,;]\s*?| /);
32287 var ps = Roo.Resizable.positions;
32288 for(var i = 0, len = hs.length; i < len; i++){
32289 if(hs[i] && ps[hs[i]]){
32290 var pos = ps[hs[i]];
32291 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
32295 this.corner = this.southeast;
32297 // updateBox = the box can move..
32298 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
32299 this.updateBox = true;
32302 this.activeHandle = null;
32304 if(this.resizeChild){
32305 if(typeof this.resizeChild == "boolean"){
32306 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
32308 this.resizeChild = Roo.get(this.resizeChild, true);
32312 if(this.adjustments == "auto"){
32313 var rc = this.resizeChild;
32314 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
32315 if(rc && (hw || hn)){
32316 rc.position("relative");
32317 rc.setLeft(hw ? hw.el.getWidth() : 0);
32318 rc.setTop(hn ? hn.el.getHeight() : 0);
32320 this.adjustments = [
32321 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
32322 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
32326 if(this.draggable){
32327 this.dd = this.dynamic ?
32328 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
32329 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
32335 * @event beforeresize
32336 * Fired before resize is allowed. Set enabled to false to cancel resize.
32337 * @param {Roo.Resizable} this
32338 * @param {Roo.EventObject} e The mousedown event
32340 "beforeresize" : true,
32343 * Fired a resizing.
32344 * @param {Roo.Resizable} this
32345 * @param {Number} x The new x position
32346 * @param {Number} y The new y position
32347 * @param {Number} w The new w width
32348 * @param {Number} h The new h hight
32349 * @param {Roo.EventObject} e The mouseup event
32354 * Fired after a resize.
32355 * @param {Roo.Resizable} this
32356 * @param {Number} width The new width
32357 * @param {Number} height The new height
32358 * @param {Roo.EventObject} e The mouseup event
32363 if(this.width !== null && this.height !== null){
32364 this.resizeTo(this.width, this.height);
32366 this.updateChildSize();
32369 this.el.dom.style.zoom = 1;
32371 Roo.Resizable.superclass.constructor.call(this);
32374 Roo.extend(Roo.Resizable, Roo.util.Observable, {
32375 resizeChild : false,
32376 adjustments : [0, 0],
32386 multiDirectional : false,
32387 disableTrackOver : false,
32388 easing : 'easeOutStrong',
32389 widthIncrement : 0,
32390 heightIncrement : 0,
32394 preserveRatio : false,
32395 transparent: false,
32401 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
32403 constrainTo: undefined,
32405 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
32407 resizeRegion: undefined,
32411 * Perform a manual resize
32412 * @param {Number} width
32413 * @param {Number} height
32415 resizeTo : function(width, height){
32416 this.el.setSize(width, height);
32417 this.updateChildSize();
32418 this.fireEvent("resize", this, width, height, null);
32422 startSizing : function(e, handle){
32423 this.fireEvent("beforeresize", this, e);
32424 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
32427 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
32428 this.overlay.unselectable();
32429 this.overlay.enableDisplayMode("block");
32430 this.overlay.on("mousemove", this.onMouseMove, this);
32431 this.overlay.on("mouseup", this.onMouseUp, this);
32433 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
32435 this.resizing = true;
32436 this.startBox = this.el.getBox();
32437 this.startPoint = e.getXY();
32438 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
32439 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
32441 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32442 this.overlay.show();
32444 if(this.constrainTo) {
32445 var ct = Roo.get(this.constrainTo);
32446 this.resizeRegion = ct.getRegion().adjust(
32447 ct.getFrameWidth('t'),
32448 ct.getFrameWidth('l'),
32449 -ct.getFrameWidth('b'),
32450 -ct.getFrameWidth('r')
32454 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
32456 this.proxy.setBox(this.startBox);
32458 this.proxy.setStyle('visibility', 'visible');
32464 onMouseDown : function(handle, e){
32467 this.activeHandle = handle;
32468 this.startSizing(e, handle);
32473 onMouseUp : function(e){
32474 var size = this.resizeElement();
32475 this.resizing = false;
32477 this.overlay.hide();
32479 this.fireEvent("resize", this, size.width, size.height, e);
32483 updateChildSize : function(){
32485 if(this.resizeChild){
32487 var child = this.resizeChild;
32488 var adj = this.adjustments;
32489 if(el.dom.offsetWidth){
32490 var b = el.getSize(true);
32491 child.setSize(b.width+adj[0], b.height+adj[1]);
32493 // Second call here for IE
32494 // The first call enables instant resizing and
32495 // the second call corrects scroll bars if they
32498 setTimeout(function(){
32499 if(el.dom.offsetWidth){
32500 var b = el.getSize(true);
32501 child.setSize(b.width+adj[0], b.height+adj[1]);
32509 snap : function(value, inc, min){
32510 if(!inc || !value) {
32513 var newValue = value;
32514 var m = value % inc;
32517 newValue = value + (inc-m);
32519 newValue = value - m;
32522 return Math.max(min, newValue);
32526 resizeElement : function(){
32527 var box = this.proxy.getBox();
32528 if(this.updateBox){
32529 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
32531 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
32533 this.updateChildSize();
32541 constrain : function(v, diff, m, mx){
32544 }else if(v - diff > mx){
32551 onMouseMove : function(e){
32554 try{// try catch so if something goes wrong the user doesn't get hung
32556 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
32560 //var curXY = this.startPoint;
32561 var curSize = this.curSize || this.startBox;
32562 var x = this.startBox.x, y = this.startBox.y;
32563 var ox = x, oy = y;
32564 var w = curSize.width, h = curSize.height;
32565 var ow = w, oh = h;
32566 var mw = this.minWidth, mh = this.minHeight;
32567 var mxw = this.maxWidth, mxh = this.maxHeight;
32568 var wi = this.widthIncrement;
32569 var hi = this.heightIncrement;
32571 var eventXY = e.getXY();
32572 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
32573 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
32575 var pos = this.activeHandle.position;
32580 w = Math.min(Math.max(mw, w), mxw);
32585 h = Math.min(Math.max(mh, h), mxh);
32590 w = Math.min(Math.max(mw, w), mxw);
32591 h = Math.min(Math.max(mh, h), mxh);
32594 diffY = this.constrain(h, diffY, mh, mxh);
32601 var adiffX = Math.abs(diffX);
32602 var sub = (adiffX % wi); // how much
32603 if (sub > (wi/2)) { // far enough to snap
32604 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
32606 // remove difference..
32607 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
32611 x = Math.max(this.minX, x);
32614 diffX = this.constrain(w, diffX, mw, mxw);
32620 w = Math.min(Math.max(mw, w), mxw);
32621 diffY = this.constrain(h, diffY, mh, mxh);
32626 diffX = this.constrain(w, diffX, mw, mxw);
32627 diffY = this.constrain(h, diffY, mh, mxh);
32634 diffX = this.constrain(w, diffX, mw, mxw);
32636 h = Math.min(Math.max(mh, h), mxh);
32642 var sw = this.snap(w, wi, mw);
32643 var sh = this.snap(h, hi, mh);
32644 if(sw != w || sh != h){
32667 if(this.preserveRatio){
32672 h = Math.min(Math.max(mh, h), mxh);
32677 w = Math.min(Math.max(mw, w), mxw);
32682 w = Math.min(Math.max(mw, w), mxw);
32688 w = Math.min(Math.max(mw, w), mxw);
32694 h = Math.min(Math.max(mh, h), mxh);
32702 h = Math.min(Math.max(mh, h), mxh);
32712 h = Math.min(Math.max(mh, h), mxh);
32720 if (pos == 'hdrag') {
32723 this.proxy.setBounds(x, y, w, h);
32725 this.resizeElement();
32729 this.fireEvent("resizing", this, x, y, w, h, e);
32733 handleOver : function(){
32735 this.el.addClass("x-resizable-over");
32740 handleOut : function(){
32741 if(!this.resizing){
32742 this.el.removeClass("x-resizable-over");
32747 * Returns the element this component is bound to.
32748 * @return {Roo.Element}
32750 getEl : function(){
32755 * Returns the resizeChild element (or null).
32756 * @return {Roo.Element}
32758 getResizeChild : function(){
32759 return this.resizeChild;
32761 groupHandler : function()
32766 * Destroys this resizable. If the element was wrapped and
32767 * removeEl is not true then the element remains.
32768 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32770 destroy : function(removeEl){
32771 this.proxy.remove();
32773 this.overlay.removeAllListeners();
32774 this.overlay.remove();
32776 var ps = Roo.Resizable.positions;
32778 if(typeof ps[k] != "function" && this[ps[k]]){
32779 var h = this[ps[k]];
32780 h.el.removeAllListeners();
32785 this.el.update("");
32792 // hash to map config positions to true positions
32793 Roo.Resizable.positions = {
32794 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
32799 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
32801 // only initialize the template if resizable is used
32802 var tpl = Roo.DomHelper.createTemplate(
32803 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
32806 Roo.Resizable.Handle.prototype.tpl = tpl;
32808 this.position = pos;
32810 // show north drag fro topdra
32811 var handlepos = pos == 'hdrag' ? 'north' : pos;
32813 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
32814 if (pos == 'hdrag') {
32815 this.el.setStyle('cursor', 'pointer');
32817 this.el.unselectable();
32819 this.el.setOpacity(0);
32821 this.el.on("mousedown", this.onMouseDown, this);
32822 if(!disableTrackOver){
32823 this.el.on("mouseover", this.onMouseOver, this);
32824 this.el.on("mouseout", this.onMouseOut, this);
32829 Roo.Resizable.Handle.prototype = {
32830 afterResize : function(rz){
32835 onMouseDown : function(e){
32836 this.rz.onMouseDown(this, e);
32839 onMouseOver : function(e){
32840 this.rz.handleOver(this, e);
32843 onMouseOut : function(e){
32844 this.rz.handleOut(this, e);
32848 * Ext JS Library 1.1.1
32849 * Copyright(c) 2006-2007, Ext JS, LLC.
32851 * Originally Released Under LGPL - original licence link has changed is not relivant.
32854 * <script type="text/javascript">
32858 * @class Roo.Editor
32859 * @extends Roo.Component
32860 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
32862 * Create a new Editor
32863 * @param {Roo.form.Field} field The Field object (or descendant)
32864 * @param {Object} config The config object
32866 Roo.Editor = function(field, config){
32867 Roo.Editor.superclass.constructor.call(this, config);
32868 this.field = field;
32871 * @event beforestartedit
32872 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
32873 * false from the handler of this event.
32874 * @param {Editor} this
32875 * @param {Roo.Element} boundEl The underlying element bound to this editor
32876 * @param {Mixed} value The field value being set
32878 "beforestartedit" : true,
32881 * Fires when this editor is displayed
32882 * @param {Roo.Element} boundEl The underlying element bound to this editor
32883 * @param {Mixed} value The starting field value
32885 "startedit" : true,
32887 * @event beforecomplete
32888 * Fires after a change has been made to the field, but before the change is reflected in the underlying
32889 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
32890 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
32891 * event will not fire since no edit actually occurred.
32892 * @param {Editor} this
32893 * @param {Mixed} value The current field value
32894 * @param {Mixed} startValue The original field value
32896 "beforecomplete" : true,
32899 * Fires after editing is complete and any changed value has been written to the underlying field.
32900 * @param {Editor} this
32901 * @param {Mixed} value The current field value
32902 * @param {Mixed} startValue The original field value
32906 * @event specialkey
32907 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
32908 * {@link Roo.EventObject#getKey} to determine which key was pressed.
32909 * @param {Roo.form.Field} this
32910 * @param {Roo.EventObject} e The event object
32912 "specialkey" : true
32916 Roo.extend(Roo.Editor, Roo.Component, {
32918 * @cfg {Boolean/String} autosize
32919 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
32920 * or "height" to adopt the height only (defaults to false)
32923 * @cfg {Boolean} revertInvalid
32924 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
32925 * validation fails (defaults to true)
32928 * @cfg {Boolean} ignoreNoChange
32929 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
32930 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
32931 * will never be ignored.
32934 * @cfg {Boolean} hideEl
32935 * False to keep the bound element visible while the editor is displayed (defaults to true)
32938 * @cfg {Mixed} value
32939 * The data value of the underlying field (defaults to "")
32943 * @cfg {String} alignment
32944 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
32948 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
32949 * for bottom-right shadow (defaults to "frame")
32953 * @cfg {Boolean} constrain True to constrain the editor to the viewport
32957 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
32959 completeOnEnter : false,
32961 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
32963 cancelOnEsc : false,
32965 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
32970 onRender : function(ct, position){
32971 this.el = new Roo.Layer({
32972 shadow: this.shadow,
32978 constrain: this.constrain
32980 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
32981 if(this.field.msgTarget != 'title'){
32982 this.field.msgTarget = 'qtip';
32984 this.field.render(this.el);
32986 this.field.el.dom.setAttribute('autocomplete', 'off');
32988 this.field.on("specialkey", this.onSpecialKey, this);
32989 if(this.swallowKeys){
32990 this.field.el.swallowEvent(['keydown','keypress']);
32993 this.field.on("blur", this.onBlur, this);
32994 if(this.field.grow){
32995 this.field.on("autosize", this.el.sync, this.el, {delay:1});
32999 onSpecialKey : function(field, e)
33001 //Roo.log('editor onSpecialKey');
33002 if(this.completeOnEnter && e.getKey() == e.ENTER){
33004 this.completeEdit();
33007 // do not fire special key otherwise it might hide close the editor...
33008 if(e.getKey() == e.ENTER){
33011 if(this.cancelOnEsc && e.getKey() == e.ESC){
33015 this.fireEvent('specialkey', field, e);
33020 * Starts the editing process and shows the editor.
33021 * @param {String/HTMLElement/Element} el The element to edit
33022 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
33023 * to the innerHTML of el.
33025 startEdit : function(el, value){
33027 this.completeEdit();
33029 this.boundEl = Roo.get(el);
33030 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
33031 if(!this.rendered){
33032 this.render(this.parentEl || document.body);
33034 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
33037 this.startValue = v;
33038 this.field.setValue(v);
33040 var sz = this.boundEl.getSize();
33041 switch(this.autoSize){
33043 this.setSize(sz.width, "");
33046 this.setSize("", sz.height);
33049 this.setSize(sz.width, sz.height);
33052 this.el.alignTo(this.boundEl, this.alignment);
33053 this.editing = true;
33055 Roo.QuickTips.disable();
33061 * Sets the height and width of this editor.
33062 * @param {Number} width The new width
33063 * @param {Number} height The new height
33065 setSize : function(w, h){
33066 this.field.setSize(w, h);
33073 * Realigns the editor to the bound field based on the current alignment config value.
33075 realign : function(){
33076 this.el.alignTo(this.boundEl, this.alignment);
33080 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
33081 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
33083 completeEdit : function(remainVisible){
33087 var v = this.getValue();
33088 if(this.revertInvalid !== false && !this.field.isValid()){
33089 v = this.startValue;
33090 this.cancelEdit(true);
33092 if(String(v) === String(this.startValue) && this.ignoreNoChange){
33093 this.editing = false;
33097 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
33098 this.editing = false;
33099 if(this.updateEl && this.boundEl){
33100 this.boundEl.update(v);
33102 if(remainVisible !== true){
33105 this.fireEvent("complete", this, v, this.startValue);
33110 onShow : function(){
33112 if(this.hideEl !== false){
33113 this.boundEl.hide();
33116 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
33117 this.fixIEFocus = true;
33118 this.deferredFocus.defer(50, this);
33120 this.field.focus();
33122 this.fireEvent("startedit", this.boundEl, this.startValue);
33125 deferredFocus : function(){
33127 this.field.focus();
33132 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
33133 * reverted to the original starting value.
33134 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
33135 * cancel (defaults to false)
33137 cancelEdit : function(remainVisible){
33139 this.setValue(this.startValue);
33140 if(remainVisible !== true){
33147 onBlur : function(){
33148 if(this.allowBlur !== true && this.editing){
33149 this.completeEdit();
33154 onHide : function(){
33156 this.completeEdit();
33160 if(this.field.collapse){
33161 this.field.collapse();
33164 if(this.hideEl !== false){
33165 this.boundEl.show();
33168 Roo.QuickTips.enable();
33173 * Sets the data value of the editor
33174 * @param {Mixed} value Any valid value supported by the underlying field
33176 setValue : function(v){
33177 this.field.setValue(v);
33181 * Gets the data value of the editor
33182 * @return {Mixed} The data value
33184 getValue : function(){
33185 return this.field.getValue();
33189 * Ext JS Library 1.1.1
33190 * Copyright(c) 2006-2007, Ext JS, LLC.
33192 * Originally Released Under LGPL - original licence link has changed is not relivant.
33195 * <script type="text/javascript">
33199 * @class Roo.BasicDialog
33200 * @extends Roo.util.Observable
33201 * @parent none builder
33202 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
33204 var dlg = new Roo.BasicDialog("my-dlg", {
33213 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
33214 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
33215 dlg.addButton('Cancel', dlg.hide, dlg);
33218 <b>A Dialog should always be a direct child of the body element.</b>
33219 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
33220 * @cfg {String} title Default text to display in the title bar (defaults to null)
33221 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
33222 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
33223 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
33224 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
33225 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
33226 * (defaults to null with no animation)
33227 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
33228 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
33229 * property for valid values (defaults to 'all')
33230 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
33231 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
33232 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
33233 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
33234 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
33235 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
33236 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
33237 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
33238 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
33239 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
33240 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
33241 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
33242 * draggable = true (defaults to false)
33243 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
33244 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
33245 * shadow (defaults to false)
33246 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
33247 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
33248 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
33249 * @cfg {Array} buttons Array of buttons
33250 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
33252 * Create a new BasicDialog.
33253 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
33254 * @param {Object} config Configuration options
33256 Roo.BasicDialog = function(el, config){
33257 this.el = Roo.get(el);
33258 var dh = Roo.DomHelper;
33259 if(!this.el && config && config.autoCreate){
33260 if(typeof config.autoCreate == "object"){
33261 if(!config.autoCreate.id){
33262 config.autoCreate.id = el;
33264 this.el = dh.append(document.body,
33265 config.autoCreate, true);
33267 this.el = dh.append(document.body,
33268 {tag: "div", id: el, style:'visibility:hidden;'}, true);
33272 el.setDisplayed(true);
33273 el.hide = this.hideAction;
33275 el.addClass("x-dlg");
33277 Roo.apply(this, config);
33279 this.proxy = el.createProxy("x-dlg-proxy");
33280 this.proxy.hide = this.hideAction;
33281 this.proxy.setOpacity(.5);
33285 el.setWidth(config.width);
33288 el.setHeight(config.height);
33290 this.size = el.getSize();
33291 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
33292 this.xy = [config.x,config.y];
33294 this.xy = el.getCenterXY(true);
33296 /** The header element @type Roo.Element */
33297 this.header = el.child("> .x-dlg-hd");
33298 /** The body element @type Roo.Element */
33299 this.body = el.child("> .x-dlg-bd");
33300 /** The footer element @type Roo.Element */
33301 this.footer = el.child("> .x-dlg-ft");
33304 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
33307 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
33310 this.header.unselectable();
33312 this.header.update(this.title);
33314 // this element allows the dialog to be focused for keyboard event
33315 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
33316 this.focusEl.swallowEvent("click", true);
33318 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
33320 // wrap the body and footer for special rendering
33321 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
33323 this.bwrap.dom.appendChild(this.footer.dom);
33326 this.bg = this.el.createChild({
33327 tag: "div", cls:"x-dlg-bg",
33328 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
33330 this.centerBg = this.bg.child("div.x-dlg-bg-center");
33333 if(this.autoScroll !== false && !this.autoTabs){
33334 this.body.setStyle("overflow", "auto");
33337 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
33339 if(this.closable !== false){
33340 this.el.addClass("x-dlg-closable");
33341 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
33342 this.close.on("click", this.closeClick, this);
33343 this.close.addClassOnOver("x-dlg-close-over");
33345 if(this.collapsible !== false){
33346 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
33347 this.collapseBtn.on("click", this.collapseClick, this);
33348 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
33349 this.header.on("dblclick", this.collapseClick, this);
33351 if(this.resizable !== false){
33352 this.el.addClass("x-dlg-resizable");
33353 this.resizer = new Roo.Resizable(el, {
33354 minWidth: this.minWidth || 80,
33355 minHeight:this.minHeight || 80,
33356 handles: this.resizeHandles || "all",
33359 this.resizer.on("beforeresize", this.beforeResize, this);
33360 this.resizer.on("resize", this.onResize, this);
33362 if(this.draggable !== false){
33363 el.addClass("x-dlg-draggable");
33364 if (!this.proxyDrag) {
33365 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
33368 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
33370 dd.setHandleElId(this.header.id);
33371 dd.endDrag = this.endMove.createDelegate(this);
33372 dd.startDrag = this.startMove.createDelegate(this);
33373 dd.onDrag = this.onDrag.createDelegate(this);
33378 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
33379 this.mask.enableDisplayMode("block");
33381 this.el.addClass("x-dlg-modal");
33384 this.shadow = new Roo.Shadow({
33385 mode : typeof this.shadow == "string" ? this.shadow : "sides",
33386 offset : this.shadowOffset
33389 this.shadowOffset = 0;
33391 if(Roo.useShims && this.shim !== false){
33392 this.shim = this.el.createShim();
33393 this.shim.hide = this.hideAction;
33401 if (this.buttons) {
33402 var bts= this.buttons;
33404 Roo.each(bts, function(b) {
33413 * Fires when a key is pressed
33414 * @param {Roo.BasicDialog} this
33415 * @param {Roo.EventObject} e
33420 * Fires when this dialog is moved by the user.
33421 * @param {Roo.BasicDialog} this
33422 * @param {Number} x The new page X
33423 * @param {Number} y The new page Y
33428 * Fires when this dialog is resized by the user.
33429 * @param {Roo.BasicDialog} this
33430 * @param {Number} width The new width
33431 * @param {Number} height The new height
33435 * @event beforehide
33436 * Fires before this dialog is hidden.
33437 * @param {Roo.BasicDialog} this
33439 "beforehide" : true,
33442 * Fires when this dialog is hidden.
33443 * @param {Roo.BasicDialog} this
33447 * @event beforeshow
33448 * Fires before this dialog is shown.
33449 * @param {Roo.BasicDialog} this
33451 "beforeshow" : true,
33454 * Fires when this dialog is shown.
33455 * @param {Roo.BasicDialog} this
33459 el.on("keydown", this.onKeyDown, this);
33460 el.on("mousedown", this.toFront, this);
33461 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
33463 Roo.DialogManager.register(this);
33464 Roo.BasicDialog.superclass.constructor.call(this);
33467 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
33468 shadowOffset: Roo.isIE ? 6 : 5,
33471 minButtonWidth: 75,
33472 defaultButton: null,
33473 buttonAlign: "right",
33478 * Sets the dialog title text
33479 * @param {String} text The title text to display
33480 * @return {Roo.BasicDialog} this
33482 setTitle : function(text){
33483 this.header.update(text);
33488 closeClick : function(){
33493 collapseClick : function(){
33494 this[this.collapsed ? "expand" : "collapse"]();
33498 * Collapses the dialog to its minimized state (only the title bar is visible).
33499 * Equivalent to the user clicking the collapse dialog button.
33501 collapse : function(){
33502 if(!this.collapsed){
33503 this.collapsed = true;
33504 this.el.addClass("x-dlg-collapsed");
33505 this.restoreHeight = this.el.getHeight();
33506 this.resizeTo(this.el.getWidth(), this.header.getHeight());
33511 * Expands a collapsed dialog back to its normal state. Equivalent to the user
33512 * clicking the expand dialog button.
33514 expand : function(){
33515 if(this.collapsed){
33516 this.collapsed = false;
33517 this.el.removeClass("x-dlg-collapsed");
33518 this.resizeTo(this.el.getWidth(), this.restoreHeight);
33523 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
33524 * @return {Roo.TabPanel} The tabs component
33526 initTabs : function(){
33527 var tabs = this.getTabs();
33528 while(tabs.getTab(0)){
33531 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
33533 tabs.addTab(Roo.id(dom), dom.title);
33541 beforeResize : function(){
33542 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
33546 onResize : function(){
33547 this.refreshSize();
33548 this.syncBodyHeight();
33549 this.adjustAssets();
33551 this.fireEvent("resize", this, this.size.width, this.size.height);
33555 onKeyDown : function(e){
33556 if(this.isVisible()){
33557 this.fireEvent("keydown", this, e);
33562 * Resizes the dialog.
33563 * @param {Number} width
33564 * @param {Number} height
33565 * @return {Roo.BasicDialog} this
33567 resizeTo : function(width, height){
33568 this.el.setSize(width, height);
33569 this.size = {width: width, height: height};
33570 this.syncBodyHeight();
33571 if(this.fixedcenter){
33574 if(this.isVisible()){
33575 this.constrainXY();
33576 this.adjustAssets();
33578 this.fireEvent("resize", this, width, height);
33584 * Resizes the dialog to fit the specified content size.
33585 * @param {Number} width
33586 * @param {Number} height
33587 * @return {Roo.BasicDialog} this
33589 setContentSize : function(w, h){
33590 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
33591 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
33592 //if(!this.el.isBorderBox()){
33593 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
33594 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
33597 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
33598 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
33600 this.resizeTo(w, h);
33605 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
33606 * executed in response to a particular key being pressed while the dialog is active.
33607 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
33608 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
33609 * @param {Function} fn The function to call
33610 * @param {Object} scope (optional) The scope of the function
33611 * @return {Roo.BasicDialog} this
33613 addKeyListener : function(key, fn, scope){
33614 var keyCode, shift, ctrl, alt;
33615 if(typeof key == "object" && !(key instanceof Array)){
33616 keyCode = key["key"];
33617 shift = key["shift"];
33618 ctrl = key["ctrl"];
33623 var handler = function(dlg, e){
33624 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
33625 var k = e.getKey();
33626 if(keyCode instanceof Array){
33627 for(var i = 0, len = keyCode.length; i < len; i++){
33628 if(keyCode[i] == k){
33629 fn.call(scope || window, dlg, k, e);
33635 fn.call(scope || window, dlg, k, e);
33640 this.on("keydown", handler);
33645 * Returns the TabPanel component (creates it if it doesn't exist).
33646 * Note: If you wish to simply check for the existence of tabs without creating them,
33647 * check for a null 'tabs' property.
33648 * @return {Roo.TabPanel} The tabs component
33650 getTabs : function(){
33652 this.el.addClass("x-dlg-auto-tabs");
33653 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
33654 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
33660 * Adds a button to the footer section of the dialog.
33661 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
33662 * object or a valid Roo.DomHelper element config
33663 * @param {Function} handler The function called when the button is clicked
33664 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
33665 * @return {Roo.Button} The new button
33667 addButton : function(config, handler, scope){
33668 var dh = Roo.DomHelper;
33670 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
33672 if(!this.btnContainer){
33673 var tb = this.footer.createChild({
33675 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
33676 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
33678 this.btnContainer = tb.firstChild.firstChild.firstChild;
33683 minWidth: this.minButtonWidth,
33686 if(typeof config == "string"){
33687 bconfig.text = config;
33690 bconfig.dhconfig = config;
33692 Roo.apply(bconfig, config);
33696 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
33697 bconfig.position = Math.max(0, bconfig.position);
33698 fc = this.btnContainer.childNodes[bconfig.position];
33701 var btn = new Roo.Button(
33703 this.btnContainer.insertBefore(document.createElement("td"),fc)
33704 : this.btnContainer.appendChild(document.createElement("td")),
33705 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
33708 this.syncBodyHeight();
33711 * Array of all the buttons that have been added to this dialog via addButton
33716 this.buttons.push(btn);
33721 * Sets the default button to be focused when the dialog is displayed.
33722 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
33723 * @return {Roo.BasicDialog} this
33725 setDefaultButton : function(btn){
33726 this.defaultButton = btn;
33731 getHeaderFooterHeight : function(safe){
33734 height += this.header.getHeight();
33737 var fm = this.footer.getMargins();
33738 height += (this.footer.getHeight()+fm.top+fm.bottom);
33740 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
33741 height += this.centerBg.getPadding("tb");
33746 syncBodyHeight : function()
33748 var bd = this.body, // the text
33749 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
33751 var height = this.size.height - this.getHeaderFooterHeight(false);
33752 bd.setHeight(height-bd.getMargins("tb"));
33753 var hh = this.header.getHeight();
33754 var h = this.size.height-hh;
33757 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
33758 bw.setHeight(h-cb.getPadding("tb"));
33760 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
33761 bd.setWidth(bw.getWidth(true));
33763 this.tabs.syncHeight();
33765 this.tabs.el.repaint();
33771 * Restores the previous state of the dialog if Roo.state is configured.
33772 * @return {Roo.BasicDialog} this
33774 restoreState : function(){
33775 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
33776 if(box && box.width){
33777 this.xy = [box.x, box.y];
33778 this.resizeTo(box.width, box.height);
33784 beforeShow : function(){
33786 if(this.fixedcenter){
33787 this.xy = this.el.getCenterXY(true);
33790 Roo.get(document.body).addClass("x-body-masked");
33791 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
33794 this.constrainXY();
33798 animShow : function(){
33799 var b = Roo.get(this.animateTarget).getBox();
33800 this.proxy.setSize(b.width, b.height);
33801 this.proxy.setLocation(b.x, b.y);
33803 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
33804 true, .35, this.showEl.createDelegate(this));
33808 * Shows the dialog.
33809 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
33810 * @return {Roo.BasicDialog} this
33812 show : function(animateTarget){
33813 if (this.fireEvent("beforeshow", this) === false){
33816 if(this.syncHeightBeforeShow){
33817 this.syncBodyHeight();
33818 }else if(this.firstShow){
33819 this.firstShow = false;
33820 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
33822 this.animateTarget = animateTarget || this.animateTarget;
33823 if(!this.el.isVisible()){
33825 if(this.animateTarget && Roo.get(this.animateTarget)){
33835 showEl : function(){
33837 this.el.setXY(this.xy);
33839 this.adjustAssets(true);
33842 // IE peekaboo bug - fix found by Dave Fenwick
33846 this.fireEvent("show", this);
33850 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
33851 * dialog itself will receive focus.
33853 focus : function(){
33854 if(this.defaultButton){
33855 this.defaultButton.focus();
33857 this.focusEl.focus();
33862 constrainXY : function(){
33863 if(this.constraintoviewport !== false){
33864 if(!this.viewSize){
33865 if(this.container){
33866 var s = this.container.getSize();
33867 this.viewSize = [s.width, s.height];
33869 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
33872 var s = Roo.get(this.container||document).getScroll();
33874 var x = this.xy[0], y = this.xy[1];
33875 var w = this.size.width, h = this.size.height;
33876 var vw = this.viewSize[0], vh = this.viewSize[1];
33877 // only move it if it needs it
33879 // first validate right/bottom
33880 if(x + w > vw+s.left){
33884 if(y + h > vh+s.top){
33888 // then make sure top/left isn't negative
33900 if(this.isVisible()){
33901 this.el.setLocation(x, y);
33902 this.adjustAssets();
33909 onDrag : function(){
33910 if(!this.proxyDrag){
33911 this.xy = this.el.getXY();
33912 this.adjustAssets();
33917 adjustAssets : function(doShow){
33918 var x = this.xy[0], y = this.xy[1];
33919 var w = this.size.width, h = this.size.height;
33920 if(doShow === true){
33922 this.shadow.show(this.el);
33928 if(this.shadow && this.shadow.isVisible()){
33929 this.shadow.show(this.el);
33931 if(this.shim && this.shim.isVisible()){
33932 this.shim.setBounds(x, y, w, h);
33937 adjustViewport : function(w, h){
33939 w = Roo.lib.Dom.getViewWidth();
33940 h = Roo.lib.Dom.getViewHeight();
33943 this.viewSize = [w, h];
33944 if(this.modal && this.mask.isVisible()){
33945 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
33946 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
33948 if(this.isVisible()){
33949 this.constrainXY();
33954 * Destroys this dialog and all its supporting elements (including any tabs, shim,
33955 * shadow, proxy, mask, etc.) Also removes all event listeners.
33956 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
33958 destroy : function(removeEl){
33959 if(this.isVisible()){
33960 this.animateTarget = null;
33963 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
33965 this.tabs.destroy(removeEl);
33978 for(var i = 0, len = this.buttons.length; i < len; i++){
33979 this.buttons[i].destroy();
33982 this.el.removeAllListeners();
33983 if(removeEl === true){
33984 this.el.update("");
33987 Roo.DialogManager.unregister(this);
33991 startMove : function(){
33992 if(this.proxyDrag){
33995 if(this.constraintoviewport !== false){
33996 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
34001 endMove : function(){
34002 if(!this.proxyDrag){
34003 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
34005 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
34008 this.refreshSize();
34009 this.adjustAssets();
34011 this.fireEvent("move", this, this.xy[0], this.xy[1]);
34015 * Brings this dialog to the front of any other visible dialogs
34016 * @return {Roo.BasicDialog} this
34018 toFront : function(){
34019 Roo.DialogManager.bringToFront(this);
34024 * Sends this dialog to the back (under) of any other visible dialogs
34025 * @return {Roo.BasicDialog} this
34027 toBack : function(){
34028 Roo.DialogManager.sendToBack(this);
34033 * Centers this dialog in the viewport
34034 * @return {Roo.BasicDialog} this
34036 center : function(){
34037 var xy = this.el.getCenterXY(true);
34038 this.moveTo(xy[0], xy[1]);
34043 * Moves the dialog's top-left corner to the specified point
34044 * @param {Number} x
34045 * @param {Number} y
34046 * @return {Roo.BasicDialog} this
34048 moveTo : function(x, y){
34050 if(this.isVisible()){
34051 this.el.setXY(this.xy);
34052 this.adjustAssets();
34058 * Aligns the dialog to the specified element
34059 * @param {String/HTMLElement/Roo.Element} element The element to align to.
34060 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
34061 * @param {Array} offsets (optional) Offset the positioning by [x, y]
34062 * @return {Roo.BasicDialog} this
34064 alignTo : function(element, position, offsets){
34065 this.xy = this.el.getAlignToXY(element, position, offsets);
34066 if(this.isVisible()){
34067 this.el.setXY(this.xy);
34068 this.adjustAssets();
34074 * Anchors an element to another element and realigns it when the window is resized.
34075 * @param {String/HTMLElement/Roo.Element} element The element to align to.
34076 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
34077 * @param {Array} offsets (optional) Offset the positioning by [x, y]
34078 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
34079 * is a number, it is used as the buffer delay (defaults to 50ms).
34080 * @return {Roo.BasicDialog} this
34082 anchorTo : function(el, alignment, offsets, monitorScroll){
34083 var action = function(){
34084 this.alignTo(el, alignment, offsets);
34086 Roo.EventManager.onWindowResize(action, this);
34087 var tm = typeof monitorScroll;
34088 if(tm != 'undefined'){
34089 Roo.EventManager.on(window, 'scroll', action, this,
34090 {buffer: tm == 'number' ? monitorScroll : 50});
34097 * Returns true if the dialog is visible
34098 * @return {Boolean}
34100 isVisible : function(){
34101 return this.el.isVisible();
34105 animHide : function(callback){
34106 var b = Roo.get(this.animateTarget).getBox();
34108 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
34110 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
34111 this.hideEl.createDelegate(this, [callback]));
34115 * Hides the dialog.
34116 * @param {Function} callback (optional) Function to call when the dialog is hidden
34117 * @return {Roo.BasicDialog} this
34119 hide : function(callback){
34120 if (this.fireEvent("beforehide", this) === false){
34124 this.shadow.hide();
34129 // sometimes animateTarget seems to get set.. causing problems...
34130 // this just double checks..
34131 if(this.animateTarget && Roo.get(this.animateTarget)) {
34132 this.animHide(callback);
34135 this.hideEl(callback);
34141 hideEl : function(callback){
34145 Roo.get(document.body).removeClass("x-body-masked");
34147 this.fireEvent("hide", this);
34148 if(typeof callback == "function"){
34154 hideAction : function(){
34155 this.setLeft("-10000px");
34156 this.setTop("-10000px");
34157 this.setStyle("visibility", "hidden");
34161 refreshSize : function(){
34162 this.size = this.el.getSize();
34163 this.xy = this.el.getXY();
34164 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
34168 // z-index is managed by the DialogManager and may be overwritten at any time
34169 setZIndex : function(index){
34171 this.mask.setStyle("z-index", index);
34174 this.shim.setStyle("z-index", ++index);
34177 this.shadow.setZIndex(++index);
34179 this.el.setStyle("z-index", ++index);
34181 this.proxy.setStyle("z-index", ++index);
34184 this.resizer.proxy.setStyle("z-index", ++index);
34187 this.lastZIndex = index;
34191 * Returns the element for this dialog
34192 * @return {Roo.Element} The underlying dialog Element
34194 getEl : function(){
34200 * @class Roo.DialogManager
34201 * Provides global access to BasicDialogs that have been created and
34202 * support for z-indexing (layering) multiple open dialogs.
34204 Roo.DialogManager = function(){
34206 var accessList = [];
34210 var sortDialogs = function(d1, d2){
34211 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
34215 var orderDialogs = function(){
34216 accessList.sort(sortDialogs);
34217 var seed = Roo.DialogManager.zseed;
34218 for(var i = 0, len = accessList.length; i < len; i++){
34219 var dlg = accessList[i];
34221 dlg.setZIndex(seed + (i*10));
34228 * The starting z-index for BasicDialogs (defaults to 9000)
34229 * @type Number The z-index value
34234 register : function(dlg){
34235 list[dlg.id] = dlg;
34236 accessList.push(dlg);
34240 unregister : function(dlg){
34241 delete list[dlg.id];
34244 if(!accessList.indexOf){
34245 for( i = 0, len = accessList.length; i < len; i++){
34246 if(accessList[i] == dlg){
34247 accessList.splice(i, 1);
34252 i = accessList.indexOf(dlg);
34254 accessList.splice(i, 1);
34260 * Gets a registered dialog by id
34261 * @param {String/Object} id The id of the dialog or a dialog
34262 * @return {Roo.BasicDialog} this
34264 get : function(id){
34265 return typeof id == "object" ? id : list[id];
34269 * Brings the specified dialog to the front
34270 * @param {String/Object} dlg The id of the dialog or a dialog
34271 * @return {Roo.BasicDialog} this
34273 bringToFront : function(dlg){
34274 dlg = this.get(dlg);
34277 dlg._lastAccess = new Date().getTime();
34284 * Sends the specified dialog to the back
34285 * @param {String/Object} dlg The id of the dialog or a dialog
34286 * @return {Roo.BasicDialog} this
34288 sendToBack : function(dlg){
34289 dlg = this.get(dlg);
34290 dlg._lastAccess = -(new Date().getTime());
34296 * Hides all dialogs
34298 hideAll : function(){
34299 for(var id in list){
34300 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
34309 * @class Roo.LayoutDialog
34310 * @extends Roo.BasicDialog
34311 * @children Roo.ContentPanel
34312 * @parent builder none
34313 * Dialog which provides adjustments for working with a layout in a Dialog.
34314 * Add your necessary layout config options to the dialog's config.<br>
34315 * Example usage (including a nested layout):
34318 dialog = new Roo.LayoutDialog("download-dlg", {
34327 // layout config merges with the dialog config
34329 tabPosition: "top",
34330 alwaysShowTabs: true
34333 dialog.addKeyListener(27, dialog.hide, dialog);
34334 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
34335 dialog.addButton("Build It!", this.getDownload, this);
34337 // we can even add nested layouts
34338 var innerLayout = new Roo.BorderLayout("dl-inner", {
34348 innerLayout.beginUpdate();
34349 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
34350 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
34351 innerLayout.endUpdate(true);
34353 var layout = dialog.getLayout();
34354 layout.beginUpdate();
34355 layout.add("center", new Roo.ContentPanel("standard-panel",
34356 {title: "Download the Source", fitToFrame:true}));
34357 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
34358 {title: "Build your own roo.js"}));
34359 layout.getRegion("center").showPanel(sp);
34360 layout.endUpdate();
34364 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
34365 * @param {Object} config configuration options
34367 Roo.LayoutDialog = function(el, cfg){
34370 if (typeof(cfg) == 'undefined') {
34371 config = Roo.apply({}, el);
34372 // not sure why we use documentElement here.. - it should always be body.
34373 // IE7 borks horribly if we use documentElement.
34374 // webkit also does not like documentElement - it creates a body element...
34375 el = Roo.get( document.body || document.documentElement ).createChild();
34376 //config.autoCreate = true;
34380 config.autoTabs = false;
34381 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
34382 this.body.setStyle({overflow:"hidden", position:"relative"});
34383 this.layout = new Roo.BorderLayout(this.body.dom, config);
34384 this.layout.monitorWindowResize = false;
34385 this.el.addClass("x-dlg-auto-layout");
34386 // fix case when center region overwrites center function
34387 this.center = Roo.BasicDialog.prototype.center;
34388 this.on("show", this.layout.layout, this.layout, true);
34389 if (config.items) {
34390 var xitems = config.items;
34391 delete config.items;
34392 Roo.each(xitems, this.addxtype, this);
34397 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
34401 * @cfg {Roo.LayoutRegion} east
34404 * @cfg {Roo.LayoutRegion} west
34407 * @cfg {Roo.LayoutRegion} south
34410 * @cfg {Roo.LayoutRegion} north
34413 * @cfg {Roo.LayoutRegion} center
34416 * @cfg {Roo.Button} buttons[] Bottom buttons..
34421 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
34424 endUpdate : function(){
34425 this.layout.endUpdate();
34429 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
34432 beginUpdate : function(){
34433 this.layout.beginUpdate();
34437 * Get the BorderLayout for this dialog
34438 * @return {Roo.BorderLayout}
34440 getLayout : function(){
34441 return this.layout;
34444 showEl : function(){
34445 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
34447 this.layout.layout();
34452 // Use the syncHeightBeforeShow config option to control this automatically
34453 syncBodyHeight : function(){
34454 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
34455 if(this.layout){this.layout.layout();}
34459 * Add an xtype element (actually adds to the layout.)
34460 * @return {Object} xdata xtype object data.
34463 addxtype : function(c) {
34464 return this.layout.addxtype(c);
34468 * Ext JS Library 1.1.1
34469 * Copyright(c) 2006-2007, Ext JS, LLC.
34471 * Originally Released Under LGPL - original licence link has changed is not relivant.
34474 * <script type="text/javascript">
34478 * @class Roo.MessageBox
34479 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
34483 Roo.Msg.alert('Status', 'Changes saved successfully.');
34485 // Prompt for user data:
34486 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
34488 // process text value...
34492 // Show a dialog using config options:
34494 title:'Save Changes?',
34495 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
34496 buttons: Roo.Msg.YESNOCANCEL,
34503 Roo.MessageBox = function(){
34504 var dlg, opt, mask, waitTimer;
34505 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
34506 var buttons, activeTextEl, bwidth;
34509 var handleButton = function(button){
34511 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
34515 var handleHide = function(){
34516 if(opt && opt.cls){
34517 dlg.el.removeClass(opt.cls);
34520 Roo.TaskMgr.stop(waitTimer);
34526 var updateButtons = function(b){
34529 buttons["ok"].hide();
34530 buttons["cancel"].hide();
34531 buttons["yes"].hide();
34532 buttons["no"].hide();
34533 dlg.footer.dom.style.display = 'none';
34536 dlg.footer.dom.style.display = '';
34537 for(var k in buttons){
34538 if(typeof buttons[k] != "function"){
34541 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
34542 width += buttons[k].el.getWidth()+15;
34552 var handleEsc = function(d, k, e){
34553 if(opt && opt.closable !== false){
34563 * Returns a reference to the underlying {@link Roo.BasicDialog} element
34564 * @return {Roo.BasicDialog} The BasicDialog element
34566 getDialog : function(){
34568 dlg = new Roo.BasicDialog("x-msg-box", {
34573 constraintoviewport:false,
34575 collapsible : false,
34578 width:400, height:100,
34579 buttonAlign:"center",
34580 closeClick : function(){
34581 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
34582 handleButton("no");
34584 handleButton("cancel");
34588 dlg.on("hide", handleHide);
34590 dlg.addKeyListener(27, handleEsc);
34592 var bt = this.buttonText;
34593 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
34594 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
34595 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
34596 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
34597 bodyEl = dlg.body.createChild({
34599 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" /><textarea class="roo-mb-textarea"></textarea><div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
34601 msgEl = bodyEl.dom.firstChild;
34602 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
34603 textboxEl.enableDisplayMode();
34604 textboxEl.addKeyListener([10,13], function(){
34605 if(dlg.isVisible() && opt && opt.buttons){
34606 if(opt.buttons.ok){
34607 handleButton("ok");
34608 }else if(opt.buttons.yes){
34609 handleButton("yes");
34613 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
34614 textareaEl.enableDisplayMode();
34615 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
34616 progressEl.enableDisplayMode();
34617 var pf = progressEl.dom.firstChild;
34619 pp = Roo.get(pf.firstChild);
34620 pp.setHeight(pf.offsetHeight);
34628 * Updates the message box body text
34629 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
34630 * the XHTML-compliant non-breaking space character '&#160;')
34631 * @return {Roo.MessageBox} This message box
34633 updateText : function(text){
34634 if(!dlg.isVisible() && !opt.width){
34635 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
34637 msgEl.innerHTML = text || ' ';
34639 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
34640 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
34642 Math.min(opt.width || cw , this.maxWidth),
34643 Math.max(opt.minWidth || this.minWidth, bwidth)
34646 activeTextEl.setWidth(w);
34648 if(dlg.isVisible()){
34649 dlg.fixedcenter = false;
34651 // to big, make it scroll. = But as usual stupid IE does not support
34654 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
34655 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
34656 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
34658 bodyEl.dom.style.height = '';
34659 bodyEl.dom.style.overflowY = '';
34662 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
34664 bodyEl.dom.style.overflowX = '';
34667 dlg.setContentSize(w, bodyEl.getHeight());
34668 if(dlg.isVisible()){
34669 dlg.fixedcenter = true;
34675 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
34676 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
34677 * @param {Number} value Any number between 0 and 1 (e.g., .5)
34678 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
34679 * @return {Roo.MessageBox} This message box
34681 updateProgress : function(value, text){
34683 this.updateText(text);
34685 if (pp) { // weird bug on my firefox - for some reason this is not defined
34686 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
34692 * Returns true if the message box is currently displayed
34693 * @return {Boolean} True if the message box is visible, else false
34695 isVisible : function(){
34696 return dlg && dlg.isVisible();
34700 * Hides the message box if it is displayed
34703 if(this.isVisible()){
34709 * Displays a new message box, or reinitializes an existing message box, based on the config options
34710 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
34711 * The following config object properties are supported:
34713 Property Type Description
34714 ---------- --------------- ------------------------------------------------------------------------------------
34715 animEl String/Element An id or Element from which the message box should animate as it opens and
34716 closes (defaults to undefined)
34717 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
34718 cancel:'Bar'}), or false to not show any buttons (defaults to false)
34719 closable Boolean False to hide the top-right close button (defaults to true). Note that
34720 progress and wait dialogs will ignore this property and always hide the
34721 close button as they can only be closed programmatically.
34722 cls String A custom CSS class to apply to the message box element
34723 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
34724 displayed (defaults to 75)
34725 fn Function A callback function to execute after closing the dialog. The arguments to the
34726 function will be btn (the name of the button that was clicked, if applicable,
34727 e.g. "ok"), and text (the value of the active text field, if applicable).
34728 Progress and wait dialogs will ignore this option since they do not respond to
34729 user actions and can only be closed programmatically, so any required function
34730 should be called by the same code after it closes the dialog.
34731 icon String A CSS class that provides a background image to be used as an icon for
34732 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
34733 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
34734 minWidth Number The minimum width in pixels of the message box (defaults to 100)
34735 modal Boolean False to allow user interaction with the page while the message box is
34736 displayed (defaults to true)
34737 msg String A string that will replace the existing message box body text (defaults
34738 to the XHTML-compliant non-breaking space character ' ')
34739 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
34740 progress Boolean True to display a progress bar (defaults to false)
34741 progressText String The text to display inside the progress bar if progress = true (defaults to '')
34742 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
34743 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
34744 title String The title text
34745 value String The string value to set into the active textbox element if displayed
34746 wait Boolean True to display a progress bar (defaults to false)
34747 width Number The width of the dialog in pixels
34754 msg: 'Please enter your address:',
34756 buttons: Roo.MessageBox.OKCANCEL,
34759 animEl: 'addAddressBtn'
34762 * @param {Object} config Configuration options
34763 * @return {Roo.MessageBox} This message box
34765 show : function(options)
34768 // this causes nightmares if you show one dialog after another
34769 // especially on callbacks..
34771 if(this.isVisible()){
34774 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
34775 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
34776 Roo.log("New Dialog Message:" + options.msg )
34777 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
34778 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
34781 var d = this.getDialog();
34783 d.setTitle(opt.title || " ");
34784 d.close.setDisplayed(opt.closable !== false);
34785 activeTextEl = textboxEl;
34786 opt.prompt = opt.prompt || (opt.multiline ? true : false);
34791 textareaEl.setHeight(typeof opt.multiline == "number" ?
34792 opt.multiline : this.defaultTextHeight);
34793 activeTextEl = textareaEl;
34802 progressEl.setDisplayed(opt.progress === true);
34803 this.updateProgress(0);
34804 activeTextEl.dom.value = opt.value || "";
34806 dlg.setDefaultButton(activeTextEl);
34808 var bs = opt.buttons;
34811 db = buttons["ok"];
34812 }else if(bs && bs.yes){
34813 db = buttons["yes"];
34815 dlg.setDefaultButton(db);
34817 bwidth = updateButtons(opt.buttons);
34818 this.updateText(opt.msg);
34820 d.el.addClass(opt.cls);
34822 d.proxyDrag = opt.proxyDrag === true;
34823 d.modal = opt.modal !== false;
34824 d.mask = opt.modal !== false ? mask : false;
34825 if(!d.isVisible()){
34826 // force it to the end of the z-index stack so it gets a cursor in FF
34827 document.body.appendChild(dlg.el.dom);
34828 d.animateTarget = null;
34829 d.show(options.animEl);
34835 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
34836 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
34837 * and closing the message box when the process is complete.
34838 * @param {String} title The title bar text
34839 * @param {String} msg The message box body text
34840 * @return {Roo.MessageBox} This message box
34842 progress : function(title, msg){
34849 minWidth: this.minProgressWidth,
34856 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
34857 * If a callback function is passed it will be called after the user clicks the button, and the
34858 * id of the button that was clicked will be passed as the only parameter to the callback
34859 * (could also be the top-right close button).
34860 * @param {String} title The title bar text
34861 * @param {String} msg The message box body text
34862 * @param {Function} fn (optional) The callback function invoked after the message box is closed
34863 * @param {Object} scope (optional) The scope of the callback function
34864 * @return {Roo.MessageBox} This message box
34866 alert : function(title, msg, fn, scope){
34879 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
34880 * interaction while waiting for a long-running process to complete that does not have defined intervals.
34881 * You are responsible for closing the message box when the process is complete.
34882 * @param {String} msg The message box body text
34883 * @param {String} title (optional) The title bar text
34884 * @return {Roo.MessageBox} This message box
34886 wait : function(msg, title){
34897 waitTimer = Roo.TaskMgr.start({
34899 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
34907 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
34908 * If a callback function is passed it will be called after the user clicks either button, and the id of the
34909 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
34910 * @param {String} title The title bar text
34911 * @param {String} msg The message box body text
34912 * @param {Function} fn (optional) The callback function invoked after the message box is closed
34913 * @param {Object} scope (optional) The scope of the callback function
34914 * @return {Roo.MessageBox} This message box
34916 confirm : function(title, msg, fn, scope){
34920 buttons: this.YESNO,
34929 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
34930 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
34931 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
34932 * (could also be the top-right close button) and the text that was entered will be passed as the two
34933 * parameters to the callback.
34934 * @param {String} title The title bar text
34935 * @param {String} msg The message box body text
34936 * @param {Function} fn (optional) The callback function invoked after the message box is closed
34937 * @param {Object} scope (optional) The scope of the callback function
34938 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
34939 * property, or the height in pixels to create the textbox (defaults to false / single-line)
34940 * @return {Roo.MessageBox} This message box
34942 prompt : function(title, msg, fn, scope, multiline){
34946 buttons: this.OKCANCEL,
34951 multiline: multiline,
34958 * Button config that displays a single OK button
34963 * Button config that displays Yes and No buttons
34966 YESNO : {yes:true, no:true},
34968 * Button config that displays OK and Cancel buttons
34971 OKCANCEL : {ok:true, cancel:true},
34973 * Button config that displays Yes, No and Cancel buttons
34976 YESNOCANCEL : {yes:true, no:true, cancel:true},
34979 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
34982 defaultTextHeight : 75,
34984 * The maximum width in pixels of the message box (defaults to 600)
34989 * The minimum width in pixels of the message box (defaults to 100)
34994 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
34995 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
34998 minProgressWidth : 250,
35000 * An object containing the default button text strings that can be overriden for localized language support.
35001 * Supported properties are: ok, cancel, yes and no.
35002 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
35015 * Shorthand for {@link Roo.MessageBox}
35017 Roo.Msg = Roo.MessageBox;/*
35019 * Ext JS Library 1.1.1
35020 * Copyright(c) 2006-2007, Ext JS, LLC.
35022 * Originally Released Under LGPL - original licence link has changed is not relivant.
35025 * <script type="text/javascript">
35028 * @class Roo.QuickTips
35029 * Provides attractive and customizable tooltips for any element.
35032 Roo.QuickTips = function(){
35033 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
35034 var ce, bd, xy, dd;
35035 var visible = false, disabled = true, inited = false;
35036 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
35038 var onOver = function(e){
35042 var t = e.getTarget();
35043 if(!t || t.nodeType !== 1 || t == document || t == document.body){
35046 if(ce && t == ce.el){
35047 clearTimeout(hideProc);
35050 if(t && tagEls[t.id]){
35051 tagEls[t.id].el = t;
35052 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
35055 var ttp, et = Roo.fly(t);
35056 var ns = cfg.namespace;
35057 if(tm.interceptTitles && t.title){
35060 t.removeAttribute("title");
35061 e.preventDefault();
35063 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
35066 showProc = show.defer(tm.showDelay, tm, [{
35068 text: ttp.replace(/\\n/g,'<br/>'),
35069 width: et.getAttributeNS(ns, cfg.width),
35070 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
35071 title: et.getAttributeNS(ns, cfg.title),
35072 cls: et.getAttributeNS(ns, cfg.cls)
35077 var onOut = function(e){
35078 clearTimeout(showProc);
35079 var t = e.getTarget();
35080 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
35081 hideProc = setTimeout(hide, tm.hideDelay);
35085 var onMove = function(e){
35091 if(tm.trackMouse && ce){
35096 var onDown = function(e){
35097 clearTimeout(showProc);
35098 clearTimeout(hideProc);
35100 if(tm.hideOnClick){
35103 tm.enable.defer(100, tm);
35108 var getPad = function(){
35109 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
35112 var show = function(o){
35116 clearTimeout(dismissProc);
35118 if(removeCls){ // in case manually hidden
35119 el.removeClass(removeCls);
35123 el.addClass(ce.cls);
35124 removeCls = ce.cls;
35127 tipTitle.update(ce.title);
35130 tipTitle.update('');
35133 el.dom.style.width = tm.maxWidth+'px';
35134 //tipBody.dom.style.width = '';
35135 tipBodyText.update(o.text);
35136 var p = getPad(), w = ce.width;
35138 var td = tipBodyText.dom;
35139 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
35140 if(aw > tm.maxWidth){
35142 }else if(aw < tm.minWidth){
35148 //tipBody.setWidth(w);
35149 el.setWidth(parseInt(w, 10) + p);
35150 if(ce.autoHide === false){
35151 close.setDisplayed(true);
35156 close.setDisplayed(false);
35162 el.avoidY = xy[1]-18;
35167 el.setStyle("visibility", "visible");
35168 el.fadeIn({callback: afterShow});
35174 var afterShow = function(){
35178 if(tm.autoDismiss && ce.autoHide !== false){
35179 dismissProc = setTimeout(hide, tm.autoDismissDelay);
35184 var hide = function(noanim){
35185 clearTimeout(dismissProc);
35186 clearTimeout(hideProc);
35188 if(el.isVisible()){
35190 if(noanim !== true && tm.animate){
35191 el.fadeOut({callback: afterHide});
35198 var afterHide = function(){
35201 el.removeClass(removeCls);
35208 * @cfg {Number} minWidth
35209 * The minimum width of the quick tip (defaults to 40)
35213 * @cfg {Number} maxWidth
35214 * The maximum width of the quick tip (defaults to 300)
35218 * @cfg {Boolean} interceptTitles
35219 * True to automatically use the element's DOM title value if available (defaults to false)
35221 interceptTitles : false,
35223 * @cfg {Boolean} trackMouse
35224 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
35226 trackMouse : false,
35228 * @cfg {Boolean} hideOnClick
35229 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
35231 hideOnClick : true,
35233 * @cfg {Number} showDelay
35234 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
35238 * @cfg {Number} hideDelay
35239 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
35243 * @cfg {Boolean} autoHide
35244 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
35245 * Used in conjunction with hideDelay.
35250 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
35251 * (defaults to true). Used in conjunction with autoDismissDelay.
35253 autoDismiss : true,
35256 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
35258 autoDismissDelay : 5000,
35260 * @cfg {Boolean} animate
35261 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
35266 * @cfg {String} title
35267 * Title text to display (defaults to ''). This can be any valid HTML markup.
35271 * @cfg {String} text
35272 * Body text to display (defaults to ''). This can be any valid HTML markup.
35276 * @cfg {String} cls
35277 * A CSS class to apply to the base quick tip element (defaults to '').
35281 * @cfg {Number} width
35282 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
35283 * minWidth or maxWidth.
35288 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
35289 * or display QuickTips in a page.
35292 tm = Roo.QuickTips;
35293 cfg = tm.tagConfig;
35295 if(!Roo.isReady){ // allow calling of init() before onReady
35296 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
35299 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
35300 el.fxDefaults = {stopFx: true};
35301 // maximum custom styling
35302 //el.update('<div class="x-tip-top-left"><div class="x-tip-top-right"><div class="x-tip-top"></div></div></div><div class="x-tip-bd-left"><div class="x-tip-bd-right"><div class="x-tip-bd"><div class="x-tip-close"></div><h3></h3><div class="x-tip-bd-inner"></div><div class="x-clear"></div></div></div></div><div class="x-tip-ft-left"><div class="x-tip-ft-right"><div class="x-tip-ft"></div></div></div>');
35303 el.update('<div class="x-tip-bd"><div class="x-tip-close"></div><h3></h3><div class="x-tip-bd-inner"></div><div class="x-clear"></div></div>');
35304 tipTitle = el.child('h3');
35305 tipTitle.enableDisplayMode("block");
35306 tipBody = el.child('div.x-tip-bd');
35307 tipBodyText = el.child('div.x-tip-bd-inner');
35308 //bdLeft = el.child('div.x-tip-bd-left');
35309 //bdRight = el.child('div.x-tip-bd-right');
35310 close = el.child('div.x-tip-close');
35311 close.enableDisplayMode("block");
35312 close.on("click", hide);
35313 var d = Roo.get(document);
35314 d.on("mousedown", onDown);
35315 d.on("mouseover", onOver);
35316 d.on("mouseout", onOut);
35317 d.on("mousemove", onMove);
35318 esc = d.addKeyListener(27, hide);
35321 dd = el.initDD("default", null, {
35322 onDrag : function(){
35326 dd.setHandleElId(tipTitle.id);
35335 * Configures a new quick tip instance and assigns it to a target element. The following config options
35338 Property Type Description
35339 ---------- --------------------- ------------------------------------------------------------------------
35340 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
35342 * @param {Object} config The config object
35344 register : function(config){
35345 var cs = config instanceof Array ? config : arguments;
35346 for(var i = 0, len = cs.length; i < len; i++) {
35348 var target = c.target;
35350 if(target instanceof Array){
35351 for(var j = 0, jlen = target.length; j < jlen; j++){
35352 tagEls[target[j]] = c;
35355 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
35362 * Removes this quick tip from its element and destroys it.
35363 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
35365 unregister : function(el){
35366 delete tagEls[Roo.id(el)];
35370 * Enable this quick tip.
35372 enable : function(){
35373 if(inited && disabled){
35375 if(locks.length < 1){
35382 * Disable this quick tip.
35384 disable : function(){
35386 clearTimeout(showProc);
35387 clearTimeout(hideProc);
35388 clearTimeout(dismissProc);
35396 * Returns true if the quick tip is enabled, else false.
35398 isEnabled : function(){
35404 namespace : "roo", // was ext?? this may break..
35405 alt_namespace : "ext",
35406 attribute : "qtip",
35416 // backwards compat
35417 Roo.QuickTips.tips = Roo.QuickTips.register;/*
35419 * Ext JS Library 1.1.1
35420 * Copyright(c) 2006-2007, Ext JS, LLC.
35422 * Originally Released Under LGPL - original licence link has changed is not relivant.
35425 * <script type="text/javascript">
35430 * @class Roo.tree.TreePanel
35431 * @extends Roo.data.Tree
35432 * @cfg {Roo.tree.TreeNode} root The root node
35433 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
35434 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
35435 * @cfg {Boolean} enableDD true to enable drag and drop
35436 * @cfg {Boolean} enableDrag true to enable just drag
35437 * @cfg {Boolean} enableDrop true to enable just drop
35438 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
35439 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
35440 * @cfg {String} ddGroup The DD group this TreePanel belongs to
35441 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
35442 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
35443 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
35444 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
35445 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
35446 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
35447 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
35448 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
35449 * @cfg {Roo.tree.TreeLoader} loader A TreeLoader for use with this TreePanel
35450 * @cfg {Roo.tree.TreeEditor} editor The TreeEditor to display when clicked.
35451 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
35452 * @cfg {Function} renderer DEPRECATED - use TreeLoader:create event / Sets the rendering (formatting) function for the nodes. to return HTML markup for the tree view. The render function is called with the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
35453 * @cfg {Function} rendererTip DEPRECATED - use TreeLoader:create event / Sets the rendering (formatting) function for the nodes hovertip to return HTML markup for the tree view. The render function is called with the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
35456 * @param {String/HTMLElement/Element} el The container element
35457 * @param {Object} config
35459 Roo.tree.TreePanel = function(el, config){
35461 var loader = false;
35463 root = config.root;
35464 delete config.root;
35466 if (config.loader) {
35467 loader = config.loader;
35468 delete config.loader;
35471 Roo.apply(this, config);
35472 Roo.tree.TreePanel.superclass.constructor.call(this);
35473 this.el = Roo.get(el);
35474 this.el.addClass('x-tree');
35475 //console.log(root);
35477 this.setRootNode( Roo.factory(root, Roo.tree));
35480 this.loader = Roo.factory(loader, Roo.tree);
35483 * Read-only. The id of the container element becomes this TreePanel's id.
35485 this.id = this.el.id;
35488 * @event beforeload
35489 * Fires before a node is loaded, return false to cancel
35490 * @param {Node} node The node being loaded
35492 "beforeload" : true,
35495 * Fires when a node is loaded
35496 * @param {Node} node The node that was loaded
35500 * @event textchange
35501 * Fires when the text for a node is changed
35502 * @param {Node} node The node
35503 * @param {String} text The new text
35504 * @param {String} oldText The old text
35506 "textchange" : true,
35508 * @event beforeexpand
35509 * Fires before a node is expanded, return false to cancel.
35510 * @param {Node} node The node
35511 * @param {Boolean} deep
35512 * @param {Boolean} anim
35514 "beforeexpand" : true,
35516 * @event beforecollapse
35517 * Fires before a node is collapsed, return false to cancel.
35518 * @param {Node} node The node
35519 * @param {Boolean} deep
35520 * @param {Boolean} anim
35522 "beforecollapse" : true,
35525 * Fires when a node is expanded
35526 * @param {Node} node The node
35530 * @event disabledchange
35531 * Fires when the disabled status of a node changes
35532 * @param {Node} node The node
35533 * @param {Boolean} disabled
35535 "disabledchange" : true,
35538 * Fires when a node is collapsed
35539 * @param {Node} node The node
35543 * @event beforeclick
35544 * Fires before click processing on a node. Return false to cancel the default action.
35545 * @param {Node} node The node
35546 * @param {Roo.EventObject} e The event object
35548 "beforeclick":true,
35550 * @event checkchange
35551 * Fires when a node with a checkbox's checked property changes
35552 * @param {Node} this This node
35553 * @param {Boolean} checked
35555 "checkchange":true,
35558 * Fires when a node is clicked
35559 * @param {Node} node The node
35560 * @param {Roo.EventObject} e The event object
35565 * Fires when a node is double clicked
35566 * @param {Node} node The node
35567 * @param {Roo.EventObject} e The event object
35571 * @event contextmenu
35572 * Fires when a node is right clicked
35573 * @param {Node} node The node
35574 * @param {Roo.EventObject} e The event object
35576 "contextmenu":true,
35578 * @event beforechildrenrendered
35579 * Fires right before the child nodes for a node are rendered
35580 * @param {Node} node The node
35582 "beforechildrenrendered":true,
35585 * Fires when a node starts being dragged
35586 * @param {Roo.tree.TreePanel} this
35587 * @param {Roo.tree.TreeNode} node
35588 * @param {event} e The raw browser event
35590 "startdrag" : true,
35593 * Fires when a drag operation is complete
35594 * @param {Roo.tree.TreePanel} this
35595 * @param {Roo.tree.TreeNode} node
35596 * @param {event} e The raw browser event
35601 * Fires when a dragged node is dropped on a valid DD target
35602 * @param {Roo.tree.TreePanel} this
35603 * @param {Roo.tree.TreeNode} node
35604 * @param {DD} dd The dd it was dropped on
35605 * @param {event} e The raw browser event
35609 * @event beforenodedrop
35610 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
35611 * passed to handlers has the following properties:<br />
35612 * <ul style="padding:5px;padding-left:16px;">
35613 * <li>tree - The TreePanel</li>
35614 * <li>target - The node being targeted for the drop</li>
35615 * <li>data - The drag data from the drag source</li>
35616 * <li>point - The point of the drop - append, above or below</li>
35617 * <li>source - The drag source</li>
35618 * <li>rawEvent - Raw mouse event</li>
35619 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
35620 * to be inserted by setting them on this object.</li>
35621 * <li>cancel - Set this to true to cancel the drop.</li>
35623 * @param {Object} dropEvent
35625 "beforenodedrop" : true,
35628 * Fires after a DD object is dropped on a node in this tree. The dropEvent
35629 * passed to handlers has the following properties:<br />
35630 * <ul style="padding:5px;padding-left:16px;">
35631 * <li>tree - The TreePanel</li>
35632 * <li>target - The node being targeted for the drop</li>
35633 * <li>data - The drag data from the drag source</li>
35634 * <li>point - The point of the drop - append, above or below</li>
35635 * <li>source - The drag source</li>
35636 * <li>rawEvent - Raw mouse event</li>
35637 * <li>dropNode - Dropped node(s).</li>
35639 * @param {Object} dropEvent
35643 * @event nodedragover
35644 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
35645 * passed to handlers has the following properties:<br />
35646 * <ul style="padding:5px;padding-left:16px;">
35647 * <li>tree - The TreePanel</li>
35648 * <li>target - The node being targeted for the drop</li>
35649 * <li>data - The drag data from the drag source</li>
35650 * <li>point - The point of the drop - append, above or below</li>
35651 * <li>source - The drag source</li>
35652 * <li>rawEvent - Raw mouse event</li>
35653 * <li>dropNode - Drop node(s) provided by the source.</li>
35654 * <li>cancel - Set this to true to signal drop not allowed.</li>
35656 * @param {Object} dragOverEvent
35658 "nodedragover" : true,
35660 * @event appendnode
35661 * Fires when append node to the tree
35662 * @param {Roo.tree.TreePanel} this
35663 * @param {Roo.tree.TreeNode} node
35664 * @param {Number} index The index of the newly appended node
35666 "appendnode" : true
35669 if(this.singleExpand){
35670 this.on("beforeexpand", this.restrictExpand, this);
35673 this.editor.tree = this;
35674 this.editor = Roo.factory(this.editor, Roo.tree);
35677 if (this.selModel) {
35678 this.selModel = Roo.factory(this.selModel, Roo.tree);
35682 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
35683 rootVisible : true,
35684 animate: Roo.enableFx,
35687 hlDrop : Roo.enableFx,
35691 rendererTip: false,
35693 restrictExpand : function(node){
35694 var p = node.parentNode;
35696 if(p.expandedChild && p.expandedChild.parentNode == p){
35697 p.expandedChild.collapse();
35699 p.expandedChild = node;
35703 // private override
35704 setRootNode : function(node){
35705 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
35706 if(!this.rootVisible){
35707 node.ui = new Roo.tree.RootTreeNodeUI(node);
35713 * Returns the container element for this TreePanel
35715 getEl : function(){
35720 * Returns the default TreeLoader for this TreePanel
35722 getLoader : function(){
35723 return this.loader;
35729 expandAll : function(){
35730 this.root.expand(true);
35734 * Collapse all nodes
35736 collapseAll : function(){
35737 this.root.collapse(true);
35741 * Returns the selection model used by this TreePanel
35743 getSelectionModel : function(){
35744 if(!this.selModel){
35745 this.selModel = new Roo.tree.DefaultSelectionModel();
35747 return this.selModel;
35751 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
35752 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
35753 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
35756 getChecked : function(a, startNode){
35757 startNode = startNode || this.root;
35759 var f = function(){
35760 if(this.attributes.checked){
35761 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
35764 startNode.cascade(f);
35769 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
35770 * @param {String} path
35771 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
35772 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
35773 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
35775 expandPath : function(path, attr, callback){
35776 attr = attr || "id";
35777 var keys = path.split(this.pathSeparator);
35778 var curNode = this.root;
35779 if(curNode.attributes[attr] != keys[1]){ // invalid root
35781 callback(false, null);
35786 var f = function(){
35787 if(++index == keys.length){
35789 callback(true, curNode);
35793 var c = curNode.findChild(attr, keys[index]);
35796 callback(false, curNode);
35801 c.expand(false, false, f);
35803 curNode.expand(false, false, f);
35807 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
35808 * @param {String} path
35809 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
35810 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
35811 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
35813 selectPath : function(path, attr, callback){
35814 attr = attr || "id";
35815 var keys = path.split(this.pathSeparator);
35816 var v = keys.pop();
35817 if(keys.length > 0){
35818 var f = function(success, node){
35819 if(success && node){
35820 var n = node.findChild(attr, v);
35826 }else if(callback){
35827 callback(false, n);
35831 callback(false, n);
35835 this.expandPath(keys.join(this.pathSeparator), attr, f);
35837 this.root.select();
35839 callback(true, this.root);
35844 getTreeEl : function(){
35849 * Trigger rendering of this TreePanel
35851 render : function(){
35852 if (this.innerCt) {
35853 return this; // stop it rendering more than once!!
35856 this.innerCt = this.el.createChild({tag:"ul",
35857 cls:"x-tree-root-ct " +
35858 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
35860 if(this.containerScroll){
35861 Roo.dd.ScrollManager.register(this.el);
35863 if((this.enableDD || this.enableDrop) && !this.dropZone){
35865 * The dropZone used by this tree if drop is enabled
35866 * @type Roo.tree.TreeDropZone
35868 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
35869 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
35872 if((this.enableDD || this.enableDrag) && !this.dragZone){
35874 * The dragZone used by this tree if drag is enabled
35875 * @type Roo.tree.TreeDragZone
35877 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
35878 ddGroup: this.ddGroup || "TreeDD",
35879 scroll: this.ddScroll
35882 this.getSelectionModel().init(this);
35884 Roo.log("ROOT not set in tree");
35887 this.root.render();
35888 if(!this.rootVisible){
35889 this.root.renderChildren();
35895 * Ext JS Library 1.1.1
35896 * Copyright(c) 2006-2007, Ext JS, LLC.
35898 * Originally Released Under LGPL - original licence link has changed is not relivant.
35901 * <script type="text/javascript">
35906 * @class Roo.tree.DefaultSelectionModel
35907 * @extends Roo.util.Observable
35908 * The default single selection for a TreePanel.
35909 * @param {Object} cfg Configuration
35911 Roo.tree.DefaultSelectionModel = function(cfg){
35912 this.selNode = null;
35918 * @event selectionchange
35919 * Fires when the selected node changes
35920 * @param {DefaultSelectionModel} this
35921 * @param {TreeNode} node the new selection
35923 "selectionchange" : true,
35926 * @event beforeselect
35927 * Fires before the selected node changes, return false to cancel the change
35928 * @param {DefaultSelectionModel} this
35929 * @param {TreeNode} node the new selection
35930 * @param {TreeNode} node the old selection
35932 "beforeselect" : true
35935 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
35938 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
35939 init : function(tree){
35941 tree.getTreeEl().on("keydown", this.onKeyDown, this);
35942 tree.on("click", this.onNodeClick, this);
35945 onNodeClick : function(node, e){
35946 if (e.ctrlKey && this.selNode == node) {
35947 this.unselect(node);
35955 * @param {TreeNode} node The node to select
35956 * @return {TreeNode} The selected node
35958 select : function(node){
35959 var last = this.selNode;
35960 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
35962 last.ui.onSelectedChange(false);
35964 this.selNode = node;
35965 node.ui.onSelectedChange(true);
35966 this.fireEvent("selectionchange", this, node, last);
35973 * @param {TreeNode} node The node to unselect
35975 unselect : function(node){
35976 if(this.selNode == node){
35977 this.clearSelections();
35982 * Clear all selections
35984 clearSelections : function(){
35985 var n = this.selNode;
35987 n.ui.onSelectedChange(false);
35988 this.selNode = null;
35989 this.fireEvent("selectionchange", this, null);
35995 * Get the selected node
35996 * @return {TreeNode} The selected node
35998 getSelectedNode : function(){
35999 return this.selNode;
36003 * Returns true if the node is selected
36004 * @param {TreeNode} node The node to check
36005 * @return {Boolean}
36007 isSelected : function(node){
36008 return this.selNode == node;
36012 * Selects the node above the selected node in the tree, intelligently walking the nodes
36013 * @return TreeNode The new selection
36015 selectPrevious : function(){
36016 var s = this.selNode || this.lastSelNode;
36020 var ps = s.previousSibling;
36022 if(!ps.isExpanded() || ps.childNodes.length < 1){
36023 return this.select(ps);
36025 var lc = ps.lastChild;
36026 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
36029 return this.select(lc);
36031 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
36032 return this.select(s.parentNode);
36038 * Selects the node above the selected node in the tree, intelligently walking the nodes
36039 * @return TreeNode The new selection
36041 selectNext : function(){
36042 var s = this.selNode || this.lastSelNode;
36046 if(s.firstChild && s.isExpanded()){
36047 return this.select(s.firstChild);
36048 }else if(s.nextSibling){
36049 return this.select(s.nextSibling);
36050 }else if(s.parentNode){
36052 s.parentNode.bubble(function(){
36053 if(this.nextSibling){
36054 newS = this.getOwnerTree().selModel.select(this.nextSibling);
36063 onKeyDown : function(e){
36064 var s = this.selNode || this.lastSelNode;
36065 // undesirable, but required
36070 var k = e.getKey();
36078 this.selectPrevious();
36081 e.preventDefault();
36082 if(s.hasChildNodes()){
36083 if(!s.isExpanded()){
36085 }else if(s.firstChild){
36086 this.select(s.firstChild, e);
36091 e.preventDefault();
36092 if(s.hasChildNodes() && s.isExpanded()){
36094 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
36095 this.select(s.parentNode, e);
36103 * @class Roo.tree.MultiSelectionModel
36104 * @extends Roo.util.Observable
36105 * Multi selection for a TreePanel.
36106 * @param {Object} cfg Configuration
36108 Roo.tree.MultiSelectionModel = function(){
36109 this.selNodes = [];
36113 * @event selectionchange
36114 * Fires when the selected nodes change
36115 * @param {MultiSelectionModel} this
36116 * @param {Array} nodes Array of the selected nodes
36118 "selectionchange" : true
36120 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
36124 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
36125 init : function(tree){
36127 tree.getTreeEl().on("keydown", this.onKeyDown, this);
36128 tree.on("click", this.onNodeClick, this);
36131 onNodeClick : function(node, e){
36132 this.select(node, e, e.ctrlKey);
36137 * @param {TreeNode} node The node to select
36138 * @param {EventObject} e (optional) An event associated with the selection
36139 * @param {Boolean} keepExisting True to retain existing selections
36140 * @return {TreeNode} The selected node
36142 select : function(node, e, keepExisting){
36143 if(keepExisting !== true){
36144 this.clearSelections(true);
36146 if(this.isSelected(node)){
36147 this.lastSelNode = node;
36150 this.selNodes.push(node);
36151 this.selMap[node.id] = node;
36152 this.lastSelNode = node;
36153 node.ui.onSelectedChange(true);
36154 this.fireEvent("selectionchange", this, this.selNodes);
36160 * @param {TreeNode} node The node to unselect
36162 unselect : function(node){
36163 if(this.selMap[node.id]){
36164 node.ui.onSelectedChange(false);
36165 var sn = this.selNodes;
36168 index = sn.indexOf(node);
36170 for(var i = 0, len = sn.length; i < len; i++){
36178 this.selNodes.splice(index, 1);
36180 delete this.selMap[node.id];
36181 this.fireEvent("selectionchange", this, this.selNodes);
36186 * Clear all selections
36188 clearSelections : function(suppressEvent){
36189 var sn = this.selNodes;
36191 for(var i = 0, len = sn.length; i < len; i++){
36192 sn[i].ui.onSelectedChange(false);
36194 this.selNodes = [];
36196 if(suppressEvent !== true){
36197 this.fireEvent("selectionchange", this, this.selNodes);
36203 * Returns true if the node is selected
36204 * @param {TreeNode} node The node to check
36205 * @return {Boolean}
36207 isSelected : function(node){
36208 return this.selMap[node.id] ? true : false;
36212 * Returns an array of the selected nodes
36215 getSelectedNodes : function(){
36216 return this.selNodes;
36219 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
36221 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
36223 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
36226 * Ext JS Library 1.1.1
36227 * Copyright(c) 2006-2007, Ext JS, LLC.
36229 * Originally Released Under LGPL - original licence link has changed is not relivant.
36232 * <script type="text/javascript">
36236 * @class Roo.tree.TreeNode
36237 * @extends Roo.data.Node
36238 * @cfg {String} text The text for this node
36239 * @cfg {Boolean} expanded true to start the node expanded
36240 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
36241 * @cfg {Boolean} allowDrop false if this node cannot be drop on
36242 * @cfg {Boolean} disabled true to start the node disabled
36243 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
36244 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
36245 * @cfg {String} cls A css class to be added to the node
36246 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
36247 * @cfg {String} href URL of the link used for the node (defaults to #)
36248 * @cfg {String} hrefTarget target frame for the link
36249 * @cfg {String} qtip An Ext QuickTip for the node
36250 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
36251 * @cfg {Boolean} singleClickExpand True for single click expand on this node
36252 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
36253 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
36254 * (defaults to undefined with no checkbox rendered)
36256 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
36258 Roo.tree.TreeNode = function(attributes){
36259 attributes = attributes || {};
36260 if(typeof attributes == "string"){
36261 attributes = {text: attributes};
36263 this.childrenRendered = false;
36264 this.rendered = false;
36265 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
36266 this.expanded = attributes.expanded === true;
36267 this.isTarget = attributes.isTarget !== false;
36268 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
36269 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
36272 * Read-only. The text for this node. To change it use setText().
36275 this.text = attributes.text;
36277 * True if this node is disabled.
36280 this.disabled = attributes.disabled === true;
36284 * @event textchange
36285 * Fires when the text for this node is changed
36286 * @param {Node} this This node
36287 * @param {String} text The new text
36288 * @param {String} oldText The old text
36290 "textchange" : true,
36292 * @event beforeexpand
36293 * Fires before this node is expanded, return false to cancel.
36294 * @param {Node} this This node
36295 * @param {Boolean} deep
36296 * @param {Boolean} anim
36298 "beforeexpand" : true,
36300 * @event beforecollapse
36301 * Fires before this node is collapsed, return false to cancel.
36302 * @param {Node} this This node
36303 * @param {Boolean} deep
36304 * @param {Boolean} anim
36306 "beforecollapse" : true,
36309 * Fires when this node is expanded
36310 * @param {Node} this This node
36314 * @event disabledchange
36315 * Fires when the disabled status of this node changes
36316 * @param {Node} this This node
36317 * @param {Boolean} disabled
36319 "disabledchange" : true,
36322 * Fires when this node is collapsed
36323 * @param {Node} this This node
36327 * @event beforeclick
36328 * Fires before click processing. Return false to cancel the default action.
36329 * @param {Node} this This node
36330 * @param {Roo.EventObject} e The event object
36332 "beforeclick":true,
36334 * @event checkchange
36335 * Fires when a node with a checkbox's checked property changes
36336 * @param {Node} this This node
36337 * @param {Boolean} checked
36339 "checkchange":true,
36342 * Fires when this node is clicked
36343 * @param {Node} this This node
36344 * @param {Roo.EventObject} e The event object
36349 * Fires when this node is double clicked
36350 * @param {Node} this This node
36351 * @param {Roo.EventObject} e The event object
36355 * @event contextmenu
36356 * Fires when this node is right clicked
36357 * @param {Node} this This node
36358 * @param {Roo.EventObject} e The event object
36360 "contextmenu":true,
36362 * @event beforechildrenrendered
36363 * Fires right before the child nodes for this node are rendered
36364 * @param {Node} this This node
36366 "beforechildrenrendered":true
36369 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
36372 * Read-only. The UI for this node
36375 this.ui = new uiClass(this);
36377 // finally support items[]
36378 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
36383 Roo.each(this.attributes.items, function(c) {
36384 this.appendChild(Roo.factory(c,Roo.Tree));
36386 delete this.attributes.items;
36391 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
36392 preventHScroll: true,
36394 * Returns true if this node is expanded
36395 * @return {Boolean}
36397 isExpanded : function(){
36398 return this.expanded;
36402 * Returns the UI object for this node
36403 * @return {TreeNodeUI}
36405 getUI : function(){
36409 // private override
36410 setFirstChild : function(node){
36411 var of = this.firstChild;
36412 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
36413 if(this.childrenRendered && of && node != of){
36414 of.renderIndent(true, true);
36417 this.renderIndent(true, true);
36421 // private override
36422 setLastChild : function(node){
36423 var ol = this.lastChild;
36424 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
36425 if(this.childrenRendered && ol && node != ol){
36426 ol.renderIndent(true, true);
36429 this.renderIndent(true, true);
36433 // these methods are overridden to provide lazy rendering support
36434 // private override
36435 appendChild : function()
36437 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
36438 if(node && this.childrenRendered){
36441 this.ui.updateExpandIcon();
36445 // private override
36446 removeChild : function(node){
36447 this.ownerTree.getSelectionModel().unselect(node);
36448 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
36449 // if it's been rendered remove dom node
36450 if(this.childrenRendered){
36453 if(this.childNodes.length < 1){
36454 this.collapse(false, false);
36456 this.ui.updateExpandIcon();
36458 if(!this.firstChild) {
36459 this.childrenRendered = false;
36464 // private override
36465 insertBefore : function(node, refNode){
36466 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
36467 if(newNode && refNode && this.childrenRendered){
36470 this.ui.updateExpandIcon();
36475 * Sets the text for this node
36476 * @param {String} text
36478 setText : function(text){
36479 var oldText = this.text;
36481 this.attributes.text = text;
36482 if(this.rendered){ // event without subscribing
36483 this.ui.onTextChange(this, text, oldText);
36485 this.fireEvent("textchange", this, text, oldText);
36489 * Triggers selection of this node
36491 select : function(){
36492 this.getOwnerTree().getSelectionModel().select(this);
36496 * Triggers deselection of this node
36498 unselect : function(){
36499 this.getOwnerTree().getSelectionModel().unselect(this);
36503 * Returns true if this node is selected
36504 * @return {Boolean}
36506 isSelected : function(){
36507 return this.getOwnerTree().getSelectionModel().isSelected(this);
36511 * Expand this node.
36512 * @param {Boolean} deep (optional) True to expand all children as well
36513 * @param {Boolean} anim (optional) false to cancel the default animation
36514 * @param {Function} callback (optional) A callback to be called when
36515 * expanding this node completes (does not wait for deep expand to complete).
36516 * Called with 1 parameter, this node.
36518 expand : function(deep, anim, callback){
36519 if(!this.expanded){
36520 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
36523 if(!this.childrenRendered){
36524 this.renderChildren();
36526 this.expanded = true;
36528 if(!this.isHiddenRoot() && (this.getOwnerTree() && this.getOwnerTree().animate && anim !== false) || anim){
36529 this.ui.animExpand(function(){
36530 this.fireEvent("expand", this);
36531 if(typeof callback == "function"){
36535 this.expandChildNodes(true);
36537 }.createDelegate(this));
36541 this.fireEvent("expand", this);
36542 if(typeof callback == "function"){
36547 if(typeof callback == "function"){
36552 this.expandChildNodes(true);
36556 isHiddenRoot : function(){
36557 return this.isRoot && !this.getOwnerTree().rootVisible;
36561 * Collapse this node.
36562 * @param {Boolean} deep (optional) True to collapse all children as well
36563 * @param {Boolean} anim (optional) false to cancel the default animation
36565 collapse : function(deep, anim){
36566 if(this.expanded && !this.isHiddenRoot()){
36567 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
36570 this.expanded = false;
36571 if((this.getOwnerTree().animate && anim !== false) || anim){
36572 this.ui.animCollapse(function(){
36573 this.fireEvent("collapse", this);
36575 this.collapseChildNodes(true);
36577 }.createDelegate(this));
36580 this.ui.collapse();
36581 this.fireEvent("collapse", this);
36585 var cs = this.childNodes;
36586 for(var i = 0, len = cs.length; i < len; i++) {
36587 cs[i].collapse(true, false);
36593 delayedExpand : function(delay){
36594 if(!this.expandProcId){
36595 this.expandProcId = this.expand.defer(delay, this);
36600 cancelExpand : function(){
36601 if(this.expandProcId){
36602 clearTimeout(this.expandProcId);
36604 this.expandProcId = false;
36608 * Toggles expanded/collapsed state of the node
36610 toggle : function(){
36619 * Ensures all parent nodes are expanded
36621 ensureVisible : function(callback){
36622 var tree = this.getOwnerTree();
36623 tree.expandPath(this.parentNode.getPath(), false, function(){
36624 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
36625 Roo.callback(callback);
36626 }.createDelegate(this));
36630 * Expand all child nodes
36631 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
36633 expandChildNodes : function(deep){
36634 var cs = this.childNodes;
36635 for(var i = 0, len = cs.length; i < len; i++) {
36636 cs[i].expand(deep);
36641 * Collapse all child nodes
36642 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
36644 collapseChildNodes : function(deep){
36645 var cs = this.childNodes;
36646 for(var i = 0, len = cs.length; i < len; i++) {
36647 cs[i].collapse(deep);
36652 * Disables this node
36654 disable : function(){
36655 this.disabled = true;
36657 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
36658 this.ui.onDisableChange(this, true);
36660 this.fireEvent("disabledchange", this, true);
36664 * Enables this node
36666 enable : function(){
36667 this.disabled = false;
36668 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
36669 this.ui.onDisableChange(this, false);
36671 this.fireEvent("disabledchange", this, false);
36675 renderChildren : function(suppressEvent){
36676 if(suppressEvent !== false){
36677 this.fireEvent("beforechildrenrendered", this);
36679 var cs = this.childNodes;
36680 for(var i = 0, len = cs.length; i < len; i++){
36681 cs[i].render(true);
36683 this.childrenRendered = true;
36687 sort : function(fn, scope){
36688 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
36689 if(this.childrenRendered){
36690 var cs = this.childNodes;
36691 for(var i = 0, len = cs.length; i < len; i++){
36692 cs[i].render(true);
36698 render : function(bulkRender){
36699 this.ui.render(bulkRender);
36700 if(!this.rendered){
36701 this.rendered = true;
36703 this.expanded = false;
36704 this.expand(false, false);
36710 renderIndent : function(deep, refresh){
36712 this.ui.childIndent = null;
36714 this.ui.renderIndent();
36715 if(deep === true && this.childrenRendered){
36716 var cs = this.childNodes;
36717 for(var i = 0, len = cs.length; i < len; i++){
36718 cs[i].renderIndent(true, refresh);
36724 * Ext JS Library 1.1.1
36725 * Copyright(c) 2006-2007, Ext JS, LLC.
36727 * Originally Released Under LGPL - original licence link has changed is not relivant.
36730 * <script type="text/javascript">
36734 * @class Roo.tree.AsyncTreeNode
36735 * @extends Roo.tree.TreeNode
36736 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
36738 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
36740 Roo.tree.AsyncTreeNode = function(config){
36741 this.loaded = false;
36742 this.loading = false;
36743 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
36745 * @event beforeload
36746 * Fires before this node is loaded, return false to cancel
36747 * @param {Node} this This node
36749 this.addEvents({'beforeload':true, 'load': true});
36752 * Fires when this node is loaded
36753 * @param {Node} this This node
36756 * The loader used by this node (defaults to using the tree's defined loader)
36761 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
36762 expand : function(deep, anim, callback){
36763 if(this.loading){ // if an async load is already running, waiting til it's done
36765 var f = function(){
36766 if(!this.loading){ // done loading
36767 clearInterval(timer);
36768 this.expand(deep, anim, callback);
36770 }.createDelegate(this);
36771 timer = setInterval(f, 200);
36775 if(this.fireEvent("beforeload", this) === false){
36778 this.loading = true;
36779 this.ui.beforeLoad(this);
36780 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
36782 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
36786 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
36790 * Returns true if this node is currently loading
36791 * @return {Boolean}
36793 isLoading : function(){
36794 return this.loading;
36797 loadComplete : function(deep, anim, callback){
36798 this.loading = false;
36799 this.loaded = true;
36800 this.ui.afterLoad(this);
36801 this.fireEvent("load", this);
36802 this.expand(deep, anim, callback);
36806 * Returns true if this node has been loaded
36807 * @return {Boolean}
36809 isLoaded : function(){
36810 return this.loaded;
36813 hasChildNodes : function(){
36814 if(!this.isLeaf() && !this.loaded){
36817 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
36822 * Trigger a reload for this node
36823 * @param {Function} callback
36825 reload : function(callback){
36826 this.collapse(false, false);
36827 while(this.firstChild){
36828 this.removeChild(this.firstChild);
36830 this.childrenRendered = false;
36831 this.loaded = false;
36832 if(this.isHiddenRoot()){
36833 this.expanded = false;
36835 this.expand(false, false, callback);
36839 * Ext JS Library 1.1.1
36840 * Copyright(c) 2006-2007, Ext JS, LLC.
36842 * Originally Released Under LGPL - original licence link has changed is not relivant.
36845 * <script type="text/javascript">
36849 * @class Roo.tree.TreeNodeUI
36851 * @param {Object} node The node to render
36852 * The TreeNode UI implementation is separate from the
36853 * tree implementation. Unless you are customizing the tree UI,
36854 * you should never have to use this directly.
36856 Roo.tree.TreeNodeUI = function(node){
36858 this.rendered = false;
36859 this.animating = false;
36860 this.emptyIcon = Roo.BLANK_IMAGE_URL;
36863 Roo.tree.TreeNodeUI.prototype = {
36864 removeChild : function(node){
36866 this.ctNode.removeChild(node.ui.getEl());
36870 beforeLoad : function(){
36871 this.addClass("x-tree-node-loading");
36874 afterLoad : function(){
36875 this.removeClass("x-tree-node-loading");
36878 onTextChange : function(node, text, oldText){
36880 this.textNode.innerHTML = text;
36884 onDisableChange : function(node, state){
36885 this.disabled = state;
36887 this.addClass("x-tree-node-disabled");
36889 this.removeClass("x-tree-node-disabled");
36893 onSelectedChange : function(state){
36896 this.addClass("x-tree-selected");
36899 this.removeClass("x-tree-selected");
36903 onMove : function(tree, node, oldParent, newParent, index, refNode){
36904 this.childIndent = null;
36906 var targetNode = newParent.ui.getContainer();
36907 if(!targetNode){//target not rendered
36908 this.holder = document.createElement("div");
36909 this.holder.appendChild(this.wrap);
36912 var insertBefore = refNode ? refNode.ui.getEl() : null;
36914 targetNode.insertBefore(this.wrap, insertBefore);
36916 targetNode.appendChild(this.wrap);
36918 this.node.renderIndent(true);
36922 addClass : function(cls){
36924 Roo.fly(this.elNode).addClass(cls);
36928 removeClass : function(cls){
36930 Roo.fly(this.elNode).removeClass(cls);
36934 remove : function(){
36936 this.holder = document.createElement("div");
36937 this.holder.appendChild(this.wrap);
36941 fireEvent : function(){
36942 return this.node.fireEvent.apply(this.node, arguments);
36945 initEvents : function(){
36946 this.node.on("move", this.onMove, this);
36947 var E = Roo.EventManager;
36948 var a = this.anchor;
36950 var el = Roo.fly(a, '_treeui');
36952 if(Roo.isOpera){ // opera render bug ignores the CSS
36953 el.setStyle("text-decoration", "none");
36956 el.on("click", this.onClick, this);
36957 el.on("dblclick", this.onDblClick, this);
36960 Roo.EventManager.on(this.checkbox,
36961 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
36964 el.on("contextmenu", this.onContextMenu, this);
36966 var icon = Roo.fly(this.iconNode);
36967 icon.on("click", this.onClick, this);
36968 icon.on("dblclick", this.onDblClick, this);
36969 icon.on("contextmenu", this.onContextMenu, this);
36970 E.on(this.ecNode, "click", this.ecClick, this, true);
36972 if(this.node.disabled){
36973 this.addClass("x-tree-node-disabled");
36975 if(this.node.hidden){
36976 this.addClass("x-tree-node-disabled");
36978 var ot = this.node.getOwnerTree();
36979 var dd = ot ? (ot.enableDD || ot.enableDrag || ot.enableDrop) : false;
36980 if(dd && (!this.node.isRoot || ot.rootVisible)){
36981 Roo.dd.Registry.register(this.elNode, {
36983 handles: this.getDDHandles(),
36989 getDDHandles : function(){
36990 return [this.iconNode, this.textNode];
36995 this.wrap.style.display = "none";
37001 this.wrap.style.display = "";
37005 onContextMenu : function(e){
37006 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
37007 e.preventDefault();
37009 this.fireEvent("contextmenu", this.node, e);
37013 onClick : function(e){
37018 if(this.fireEvent("beforeclick", this.node, e) !== false){
37019 if(!this.disabled && this.node.attributes.href){
37020 this.fireEvent("click", this.node, e);
37023 e.preventDefault();
37028 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
37029 this.node.toggle();
37032 this.fireEvent("click", this.node, e);
37038 onDblClick : function(e){
37039 e.preventDefault();
37044 this.toggleCheck();
37046 if(!this.animating && this.node.hasChildNodes()){
37047 this.node.toggle();
37049 this.fireEvent("dblclick", this.node, e);
37052 onCheckChange : function(){
37053 var checked = this.checkbox.checked;
37054 this.node.attributes.checked = checked;
37055 this.fireEvent('checkchange', this.node, checked);
37058 ecClick : function(e){
37059 if(!this.animating && this.node.hasChildNodes()){
37060 this.node.toggle();
37064 startDrop : function(){
37065 this.dropping = true;
37068 // delayed drop so the click event doesn't get fired on a drop
37069 endDrop : function(){
37070 setTimeout(function(){
37071 this.dropping = false;
37072 }.createDelegate(this), 50);
37075 expand : function(){
37076 this.updateExpandIcon();
37077 this.ctNode.style.display = "";
37080 focus : function(){
37081 if(!this.node.preventHScroll){
37082 try{this.anchor.focus();
37084 }else if(!Roo.isIE){
37086 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
37087 var l = noscroll.scrollLeft;
37088 this.anchor.focus();
37089 noscroll.scrollLeft = l;
37094 toggleCheck : function(value){
37095 var cb = this.checkbox;
37097 cb.checked = (value === undefined ? !cb.checked : value);
37103 this.anchor.blur();
37107 animExpand : function(callback){
37108 var ct = Roo.get(this.ctNode);
37110 if(!this.node.hasChildNodes()){
37111 this.updateExpandIcon();
37112 this.ctNode.style.display = "";
37113 Roo.callback(callback);
37116 this.animating = true;
37117 this.updateExpandIcon();
37120 callback : function(){
37121 this.animating = false;
37122 Roo.callback(callback);
37125 duration: this.node.ownerTree.duration || .25
37129 highlight : function(){
37130 var tree = this.node.getOwnerTree();
37131 Roo.fly(this.wrap).highlight(
37132 tree.hlColor || "C3DAF9",
37133 {endColor: tree.hlBaseColor}
37137 collapse : function(){
37138 this.updateExpandIcon();
37139 this.ctNode.style.display = "none";
37142 animCollapse : function(callback){
37143 var ct = Roo.get(this.ctNode);
37144 ct.enableDisplayMode('block');
37147 this.animating = true;
37148 this.updateExpandIcon();
37151 callback : function(){
37152 this.animating = false;
37153 Roo.callback(callback);
37156 duration: this.node.ownerTree.duration || .25
37160 getContainer : function(){
37161 return this.ctNode;
37164 getEl : function(){
37168 appendDDGhost : function(ghostNode){
37169 ghostNode.appendChild(this.elNode.cloneNode(true));
37172 getDDRepairXY : function(){
37173 return Roo.lib.Dom.getXY(this.iconNode);
37176 onRender : function(){
37180 render : function(bulkRender){
37181 var n = this.node, a = n.attributes;
37182 var targetNode = n.parentNode ?
37183 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
37185 if(!this.rendered){
37186 this.rendered = true;
37188 this.renderElements(n, a, targetNode, bulkRender);
37191 if(this.textNode.setAttributeNS){
37192 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
37194 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
37197 this.textNode.setAttribute("ext:qtip", a.qtip);
37199 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
37202 }else if(a.qtipCfg){
37203 a.qtipCfg.target = Roo.id(this.textNode);
37204 Roo.QuickTips.register(a.qtipCfg);
37207 if(!this.node.expanded){
37208 this.updateExpandIcon();
37211 if(bulkRender === true) {
37212 targetNode.appendChild(this.wrap);
37217 renderElements : function(n, a, targetNode, bulkRender)
37219 // add some indent caching, this helps performance when rendering a large tree
37220 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
37221 var t = n.getOwnerTree();
37222 var txt = t && t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
37223 if (typeof(n.attributes.html) != 'undefined') {
37224 txt = n.attributes.html;
37226 var tip = t && t.rendererTip ? t.rendererTip(n.attributes) : txt;
37227 var cb = typeof a.checked == 'boolean';
37228 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
37229 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
37230 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
37231 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
37232 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
37233 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
37234 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
37235 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
37236 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
37237 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
37240 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
37241 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
37242 n.nextSibling.ui.getEl(), buf.join(""));
37244 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
37247 this.elNode = this.wrap.childNodes[0];
37248 this.ctNode = this.wrap.childNodes[1];
37249 var cs = this.elNode.childNodes;
37250 this.indentNode = cs[0];
37251 this.ecNode = cs[1];
37252 this.iconNode = cs[2];
37255 this.checkbox = cs[3];
37258 this.anchor = cs[index];
37259 this.textNode = cs[index].firstChild;
37262 getAnchor : function(){
37263 return this.anchor;
37266 getTextEl : function(){
37267 return this.textNode;
37270 getIconEl : function(){
37271 return this.iconNode;
37274 isChecked : function(){
37275 return this.checkbox ? this.checkbox.checked : false;
37278 updateExpandIcon : function(){
37280 var n = this.node, c1, c2;
37281 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
37282 var hasChild = n.hasChildNodes();
37286 c1 = "x-tree-node-collapsed";
37287 c2 = "x-tree-node-expanded";
37290 c1 = "x-tree-node-expanded";
37291 c2 = "x-tree-node-collapsed";
37294 this.removeClass("x-tree-node-leaf");
37295 this.wasLeaf = false;
37297 if(this.c1 != c1 || this.c2 != c2){
37298 Roo.fly(this.elNode).replaceClass(c1, c2);
37299 this.c1 = c1; this.c2 = c2;
37302 // this changes non-leafs into leafs if they have no children.
37303 // it's not very rational behaviour..
37305 if(!this.wasLeaf && this.node.leaf){
37306 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
37309 this.wasLeaf = true;
37312 var ecc = "x-tree-ec-icon "+cls;
37313 if(this.ecc != ecc){
37314 this.ecNode.className = ecc;
37320 getChildIndent : function(){
37321 if(!this.childIndent){
37325 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
37327 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
37329 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
37334 this.childIndent = buf.join("");
37336 return this.childIndent;
37339 renderIndent : function(){
37342 var p = this.node.parentNode;
37344 indent = p.ui.getChildIndent();
37346 if(this.indentMarkup != indent){ // don't rerender if not required
37347 this.indentNode.innerHTML = indent;
37348 this.indentMarkup = indent;
37350 this.updateExpandIcon();
37355 Roo.tree.RootTreeNodeUI = function(){
37356 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
37358 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
37359 render : function(){
37360 if(!this.rendered){
37361 var targetNode = this.node.ownerTree.innerCt.dom;
37362 this.node.expanded = true;
37363 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
37364 this.wrap = this.ctNode = targetNode.firstChild;
37367 collapse : function(){
37369 expand : function(){
37373 * Ext JS Library 1.1.1
37374 * Copyright(c) 2006-2007, Ext JS, LLC.
37376 * Originally Released Under LGPL - original licence link has changed is not relivant.
37379 * <script type="text/javascript">
37382 * @class Roo.tree.TreeLoader
37383 * @extends Roo.util.Observable
37384 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
37385 * nodes from a specified URL. The response must be a javascript Array definition
37386 * who's elements are node definition objects. eg:
37391 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
37392 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
37399 * The old style respose with just an array is still supported, but not recommended.
37402 * A server request is sent, and child nodes are loaded only when a node is expanded.
37403 * The loading node's id is passed to the server under the parameter name "node" to
37404 * enable the server to produce the correct child nodes.
37406 * To pass extra parameters, an event handler may be attached to the "beforeload"
37407 * event, and the parameters specified in the TreeLoader's baseParams property:
37409 myTreeLoader.on("beforeload", function(treeLoader, node) {
37410 this.baseParams.category = node.attributes.category;
37415 * This would pass an HTTP parameter called "category" to the server containing
37416 * the value of the Node's "category" attribute.
37418 * Creates a new Treeloader.
37419 * @param {Object} config A config object containing config properties.
37421 Roo.tree.TreeLoader = function(config){
37422 this.baseParams = {};
37423 this.requestMethod = "POST";
37424 Roo.apply(this, config);
37429 * @event beforeload
37430 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
37431 * @param {Object} This TreeLoader object.
37432 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
37433 * @param {Object} callback The callback function specified in the {@link #load} call.
37438 * Fires when the node has been successfuly loaded.
37439 * @param {Object} This TreeLoader object.
37440 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
37441 * @param {Object} response The response object containing the data from the server.
37445 * @event loadexception
37446 * Fires if the network request failed.
37447 * @param {Object} This TreeLoader object.
37448 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
37449 * @param {Object} response The response object containing the data from the server.
37451 loadexception : true,
37454 * Fires before a node is created, enabling you to return custom Node types
37455 * @param {Object} This TreeLoader object.
37456 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
37461 Roo.tree.TreeLoader.superclass.constructor.call(this);
37464 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
37466 * @cfg {String} dataUrl The URL from which to request a Json string which
37467 * specifies an array of node definition object representing the child nodes
37471 * @cfg {String} requestMethod either GET or POST
37472 * defaults to POST (due to BC)
37476 * @cfg {Object} baseParams (optional) An object containing properties which
37477 * specify HTTP parameters to be passed to each request for child nodes.
37480 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
37481 * created by this loader. If the attributes sent by the server have an attribute in this object,
37482 * they take priority.
37485 * @cfg {Object} uiProviders (optional) An object containing properties which
37487 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
37488 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
37489 * <i>uiProvider</i> attribute of a returned child node is a string rather
37490 * than a reference to a TreeNodeUI implementation, this that string value
37491 * is used as a property name in the uiProviders object. You can define the provider named
37492 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
37497 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
37498 * child nodes before loading.
37500 clearOnLoad : true,
37503 * @cfg {String} root (optional) Default to false. Use this to read data from an object
37504 * property on loading, rather than expecting an array. (eg. more compatible to a standard
37505 * Grid query { data : [ .....] }
37510 * @cfg {String} queryParam (optional)
37511 * Name of the query as it will be passed on the querystring (defaults to 'node')
37512 * eg. the request will be ?node=[id]
37519 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
37520 * This is called automatically when a node is expanded, but may be used to reload
37521 * a node (or append new children if the {@link #clearOnLoad} option is false.)
37522 * @param {Roo.tree.TreeNode} node
37523 * @param {Function} callback
37525 load : function(node, callback){
37526 if(this.clearOnLoad){
37527 while(node.firstChild){
37528 node.removeChild(node.firstChild);
37531 if(node.attributes.children){ // preloaded json children
37532 var cs = node.attributes.children;
37533 for(var i = 0, len = cs.length; i < len; i++){
37534 node.appendChild(this.createNode(cs[i]));
37536 if(typeof callback == "function"){
37539 }else if(this.dataUrl){
37540 this.requestData(node, callback);
37544 getParams: function(node){
37545 var buf = [], bp = this.baseParams;
37546 for(var key in bp){
37547 if(typeof bp[key] != "function"){
37548 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
37551 var n = this.queryParam === false ? 'node' : this.queryParam;
37552 buf.push(n + "=", encodeURIComponent(node.id));
37553 return buf.join("");
37556 requestData : function(node, callback){
37557 if(this.fireEvent("beforeload", this, node, callback) !== false){
37558 this.transId = Roo.Ajax.request({
37559 method:this.requestMethod,
37560 url: this.dataUrl||this.url,
37561 success: this.handleResponse,
37562 failure: this.handleFailure,
37564 argument: {callback: callback, node: node},
37565 params: this.getParams(node)
37568 // if the load is cancelled, make sure we notify
37569 // the node that we are done
37570 if(typeof callback == "function"){
37576 isLoading : function(){
37577 return this.transId ? true : false;
37580 abort : function(){
37581 if(this.isLoading()){
37582 Roo.Ajax.abort(this.transId);
37587 createNode : function(attr)
37589 // apply baseAttrs, nice idea Corey!
37590 if(this.baseAttrs){
37591 Roo.applyIf(attr, this.baseAttrs);
37593 if(this.applyLoader !== false){
37594 attr.loader = this;
37596 // uiProvider = depreciated..
37598 if(typeof(attr.uiProvider) == 'string'){
37599 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
37600 /** eval:var:attr */ eval(attr.uiProvider);
37602 if(typeof(this.uiProviders['default']) != 'undefined') {
37603 attr.uiProvider = this.uiProviders['default'];
37606 this.fireEvent('create', this, attr);
37608 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
37610 new Roo.tree.TreeNode(attr) :
37611 new Roo.tree.AsyncTreeNode(attr));
37614 processResponse : function(response, node, callback)
37616 var json = response.responseText;
37619 var o = Roo.decode(json);
37621 if (this.root === false && typeof(o.success) != undefined) {
37622 this.root = 'data'; // the default behaviour for list like data..
37625 if (this.root !== false && !o.success) {
37626 // it's a failure condition.
37627 var a = response.argument;
37628 this.fireEvent("loadexception", this, a.node, response);
37629 Roo.log("Load failed - should have a handler really");
37635 if (this.root !== false) {
37639 for(var i = 0, len = o.length; i < len; i++){
37640 var n = this.createNode(o[i]);
37642 node.appendChild(n);
37645 if(typeof callback == "function"){
37646 callback(this, node);
37649 this.handleFailure(response);
37653 handleResponse : function(response){
37654 this.transId = false;
37655 var a = response.argument;
37656 this.processResponse(response, a.node, a.callback);
37657 this.fireEvent("load", this, a.node, response);
37660 handleFailure : function(response)
37662 // should handle failure better..
37663 this.transId = false;
37664 var a = response.argument;
37665 this.fireEvent("loadexception", this, a.node, response);
37666 if(typeof a.callback == "function"){
37667 a.callback(this, a.node);
37672 * Ext JS Library 1.1.1
37673 * Copyright(c) 2006-2007, Ext JS, LLC.
37675 * Originally Released Under LGPL - original licence link has changed is not relivant.
37678 * <script type="text/javascript">
37682 * @class Roo.tree.TreeFilter
37683 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
37684 * @param {TreePanel} tree
37685 * @param {Object} config (optional)
37687 Roo.tree.TreeFilter = function(tree, config){
37689 this.filtered = {};
37690 Roo.apply(this, config);
37693 Roo.tree.TreeFilter.prototype = {
37700 * Filter the data by a specific attribute.
37701 * @param {String/RegExp} value Either string that the attribute value
37702 * should start with or a RegExp to test against the attribute
37703 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
37704 * @param {TreeNode} startNode (optional) The node to start the filter at.
37706 filter : function(value, attr, startNode){
37707 attr = attr || "text";
37709 if(typeof value == "string"){
37710 var vlen = value.length;
37711 // auto clear empty filter
37712 if(vlen == 0 && this.clearBlank){
37716 value = value.toLowerCase();
37718 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
37720 }else if(value.exec){ // regex?
37722 return value.test(n.attributes[attr]);
37725 throw 'Illegal filter type, must be string or regex';
37727 this.filterBy(f, null, startNode);
37731 * Filter by a function. The passed function will be called with each
37732 * node in the tree (or from the startNode). If the function returns true, the node is kept
37733 * otherwise it is filtered. If a node is filtered, its children are also filtered.
37734 * @param {Function} fn The filter function
37735 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
37737 filterBy : function(fn, scope, startNode){
37738 startNode = startNode || this.tree.root;
37739 if(this.autoClear){
37742 var af = this.filtered, rv = this.reverse;
37743 var f = function(n){
37744 if(n == startNode){
37750 var m = fn.call(scope || n, n);
37758 startNode.cascade(f);
37761 if(typeof id != "function"){
37763 if(n && n.parentNode){
37764 n.parentNode.removeChild(n);
37772 * Clears the current filter. Note: with the "remove" option
37773 * set a filter cannot be cleared.
37775 clear : function(){
37777 var af = this.filtered;
37779 if(typeof id != "function"){
37786 this.filtered = {};
37791 * Ext JS Library 1.1.1
37792 * Copyright(c) 2006-2007, Ext JS, LLC.
37794 * Originally Released Under LGPL - original licence link has changed is not relivant.
37797 * <script type="text/javascript">
37802 * @class Roo.tree.TreeSorter
37803 * Provides sorting of nodes in a TreePanel
37805 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
37806 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
37807 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
37808 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
37809 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
37810 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
37812 * @param {TreePanel} tree
37813 * @param {Object} config
37815 Roo.tree.TreeSorter = function(tree, config){
37816 Roo.apply(this, config);
37817 tree.on("beforechildrenrendered", this.doSort, this);
37818 tree.on("append", this.updateSort, this);
37819 tree.on("insert", this.updateSort, this);
37821 var dsc = this.dir && this.dir.toLowerCase() == "desc";
37822 var p = this.property || "text";
37823 var sortType = this.sortType;
37824 var fs = this.folderSort;
37825 var cs = this.caseSensitive === true;
37826 var leafAttr = this.leafAttr || 'leaf';
37828 this.sortFn = function(n1, n2){
37830 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
37833 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
37837 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
37838 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
37840 return dsc ? +1 : -1;
37842 return dsc ? -1 : +1;
37849 Roo.tree.TreeSorter.prototype = {
37850 doSort : function(node){
37851 node.sort(this.sortFn);
37854 compareNodes : function(n1, n2){
37855 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
37858 updateSort : function(tree, node){
37859 if(node.childrenRendered){
37860 this.doSort.defer(1, this, [node]);
37865 * Ext JS Library 1.1.1
37866 * Copyright(c) 2006-2007, Ext JS, LLC.
37868 * Originally Released Under LGPL - original licence link has changed is not relivant.
37871 * <script type="text/javascript">
37874 if(Roo.dd.DropZone){
37876 Roo.tree.TreeDropZone = function(tree, config){
37877 this.allowParentInsert = false;
37878 this.allowContainerDrop = false;
37879 this.appendOnly = false;
37880 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
37882 this.lastInsertClass = "x-tree-no-status";
37883 this.dragOverData = {};
37886 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
37887 ddGroup : "TreeDD",
37890 expandDelay : 1000,
37892 expandNode : function(node){
37893 if(node.hasChildNodes() && !node.isExpanded()){
37894 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
37898 queueExpand : function(node){
37899 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
37902 cancelExpand : function(){
37903 if(this.expandProcId){
37904 clearTimeout(this.expandProcId);
37905 this.expandProcId = false;
37909 isValidDropPoint : function(n, pt, dd, e, data){
37910 if(!n || !data){ return false; }
37911 var targetNode = n.node;
37912 var dropNode = data.node;
37913 // default drop rules
37914 if(!(targetNode && targetNode.isTarget && pt)){
37917 if(pt == "append" && targetNode.allowChildren === false){
37920 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
37923 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
37926 // reuse the object
37927 var overEvent = this.dragOverData;
37928 overEvent.tree = this.tree;
37929 overEvent.target = targetNode;
37930 overEvent.data = data;
37931 overEvent.point = pt;
37932 overEvent.source = dd;
37933 overEvent.rawEvent = e;
37934 overEvent.dropNode = dropNode;
37935 overEvent.cancel = false;
37936 var result = this.tree.fireEvent("nodedragover", overEvent);
37937 return overEvent.cancel === false && result !== false;
37940 getDropPoint : function(e, n, dd)
37944 return tn.allowChildren !== false ? "append" : false; // always append for root
37946 var dragEl = n.ddel;
37947 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
37948 var y = Roo.lib.Event.getPageY(e);
37949 //var noAppend = tn.allowChildren === false || tn.isLeaf();
37951 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
37952 var noAppend = tn.allowChildren === false;
37953 if(this.appendOnly || tn.parentNode.allowChildren === false){
37954 return noAppend ? false : "append";
37956 var noBelow = false;
37957 if(!this.allowParentInsert){
37958 noBelow = tn.hasChildNodes() && tn.isExpanded();
37960 var q = (b - t) / (noAppend ? 2 : 3);
37961 if(y >= t && y < (t + q)){
37963 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
37970 onNodeEnter : function(n, dd, e, data)
37972 this.cancelExpand();
37975 onNodeOver : function(n, dd, e, data)
37978 var pt = this.getDropPoint(e, n, dd);
37981 // auto node expand check
37982 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
37983 this.queueExpand(node);
37984 }else if(pt != "append"){
37985 this.cancelExpand();
37988 // set the insert point style on the target node
37989 var returnCls = this.dropNotAllowed;
37990 if(this.isValidDropPoint(n, pt, dd, e, data)){
37995 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
37996 cls = "x-tree-drag-insert-above";
37997 }else if(pt == "below"){
37998 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
37999 cls = "x-tree-drag-insert-below";
38001 returnCls = "x-tree-drop-ok-append";
38002 cls = "x-tree-drag-append";
38004 if(this.lastInsertClass != cls){
38005 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
38006 this.lastInsertClass = cls;
38013 onNodeOut : function(n, dd, e, data){
38015 this.cancelExpand();
38016 this.removeDropIndicators(n);
38019 onNodeDrop : function(n, dd, e, data){
38020 var point = this.getDropPoint(e, n, dd);
38021 var targetNode = n.node;
38022 targetNode.ui.startDrop();
38023 if(!this.isValidDropPoint(n, point, dd, e, data)){
38024 targetNode.ui.endDrop();
38027 // first try to find the drop node
38028 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
38031 target: targetNode,
38036 dropNode: dropNode,
38039 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
38040 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
38041 targetNode.ui.endDrop();
38044 // allow target changing
38045 targetNode = dropEvent.target;
38046 if(point == "append" && !targetNode.isExpanded()){
38047 targetNode.expand(false, null, function(){
38048 this.completeDrop(dropEvent);
38049 }.createDelegate(this));
38051 this.completeDrop(dropEvent);
38056 completeDrop : function(de){
38057 var ns = de.dropNode, p = de.point, t = de.target;
38058 if(!(ns instanceof Array)){
38062 for(var i = 0, len = ns.length; i < len; i++){
38065 t.parentNode.insertBefore(n, t);
38066 }else if(p == "below"){
38067 t.parentNode.insertBefore(n, t.nextSibling);
38073 if(this.tree.hlDrop){
38077 this.tree.fireEvent("nodedrop", de);
38080 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
38081 if(this.tree.hlDrop){
38082 dropNode.ui.focus();
38083 dropNode.ui.highlight();
38085 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
38088 getTree : function(){
38092 removeDropIndicators : function(n){
38095 Roo.fly(el).removeClass([
38096 "x-tree-drag-insert-above",
38097 "x-tree-drag-insert-below",
38098 "x-tree-drag-append"]);
38099 this.lastInsertClass = "_noclass";
38103 beforeDragDrop : function(target, e, id){
38104 this.cancelExpand();
38108 afterRepair : function(data){
38109 if(data && Roo.enableFx){
38110 data.node.ui.highlight();
38120 * Ext JS Library 1.1.1
38121 * Copyright(c) 2006-2007, Ext JS, LLC.
38123 * Originally Released Under LGPL - original licence link has changed is not relivant.
38126 * <script type="text/javascript">
38130 if(Roo.dd.DragZone){
38131 Roo.tree.TreeDragZone = function(tree, config){
38132 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
38136 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
38137 ddGroup : "TreeDD",
38139 onBeforeDrag : function(data, e){
38141 return n && n.draggable && !n.disabled;
38145 onInitDrag : function(e){
38146 var data = this.dragData;
38147 this.tree.getSelectionModel().select(data.node);
38148 this.proxy.update("");
38149 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
38150 this.tree.fireEvent("startdrag", this.tree, data.node, e);
38153 getRepairXY : function(e, data){
38154 return data.node.ui.getDDRepairXY();
38157 onEndDrag : function(data, e){
38158 this.tree.fireEvent("enddrag", this.tree, data.node, e);
38163 onValidDrop : function(dd, e, id){
38164 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
38168 beforeInvalidDrop : function(e, id){
38169 // this scrolls the original position back into view
38170 var sm = this.tree.getSelectionModel();
38171 sm.clearSelections();
38172 sm.select(this.dragData.node);
38177 * Ext JS Library 1.1.1
38178 * Copyright(c) 2006-2007, Ext JS, LLC.
38180 * Originally Released Under LGPL - original licence link has changed is not relivant.
38183 * <script type="text/javascript">
38186 * @class Roo.tree.TreeEditor
38187 * @extends Roo.Editor
38188 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
38189 * as the editor field.
38191 * @param {Object} config (used to be the tree panel.)
38192 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
38194 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
38195 * @cfg {Roo.form.TextField} field [required] The field configuration
38199 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
38202 if (oldconfig) { // old style..
38203 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
38206 tree = config.tree;
38207 config.field = config.field || {};
38208 config.field.xtype = 'TextField';
38209 field = Roo.factory(config.field, Roo.form);
38211 config = config || {};
38216 * @event beforenodeedit
38217 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
38218 * false from the handler of this event.
38219 * @param {Editor} this
38220 * @param {Roo.tree.Node} node
38222 "beforenodeedit" : true
38226 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
38230 tree.on('beforeclick', this.beforeNodeClick, this);
38231 tree.getTreeEl().on('mousedown', this.hide, this);
38232 this.on('complete', this.updateNode, this);
38233 this.on('beforestartedit', this.fitToTree, this);
38234 this.on('startedit', this.bindScroll, this, {delay:10});
38235 this.on('specialkey', this.onSpecialKey, this);
38238 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
38240 * @cfg {String} alignment
38241 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
38247 * @cfg {Boolean} hideEl
38248 * True to hide the bound element while the editor is displayed (defaults to false)
38252 * @cfg {String} cls
38253 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
38255 cls: "x-small-editor x-tree-editor",
38257 * @cfg {Boolean} shim
38258 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
38264 * @cfg {Number} maxWidth
38265 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
38266 * the containing tree element's size, it will be automatically limited for you to the container width, taking
38267 * scroll and client offsets into account prior to each edit.
38274 fitToTree : function(ed, el){
38275 var td = this.tree.getTreeEl().dom, nd = el.dom;
38276 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
38277 td.scrollLeft = nd.offsetLeft;
38281 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
38282 this.setSize(w, '');
38284 return this.fireEvent('beforenodeedit', this, this.editNode);
38289 triggerEdit : function(node){
38290 this.completeEdit();
38291 this.editNode = node;
38292 this.startEdit(node.ui.textNode, node.text);
38296 bindScroll : function(){
38297 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
38301 beforeNodeClick : function(node, e){
38302 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
38303 this.lastClick = new Date();
38304 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
38306 this.triggerEdit(node);
38313 updateNode : function(ed, value){
38314 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
38315 this.editNode.setText(value);
38319 onHide : function(){
38320 Roo.tree.TreeEditor.superclass.onHide.call(this);
38322 this.editNode.ui.focus();
38327 onSpecialKey : function(field, e){
38328 var k = e.getKey();
38332 }else if(k == e.ENTER && !e.hasModifier()){
38334 this.completeEdit();
38337 });//<Script type="text/javascript">
38340 * Ext JS Library 1.1.1
38341 * Copyright(c) 2006-2007, Ext JS, LLC.
38343 * Originally Released Under LGPL - original licence link has changed is not relivant.
38346 * <script type="text/javascript">
38350 * Not documented??? - probably should be...
38353 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
38354 //focus: Roo.emptyFn, // prevent odd scrolling behavior
38356 renderElements : function(n, a, targetNode, bulkRender){
38357 //consel.log("renderElements?");
38358 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
38360 var t = n.getOwnerTree();
38361 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
38363 var cols = t.columns;
38364 var bw = t.borderWidth;
38366 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
38367 var cb = typeof a.checked == "boolean";
38368 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
38369 var colcls = 'x-t-' + tid + '-c0';
38371 '<li class="x-tree-node">',
38374 '<div class="x-tree-node-el ', a.cls,'">',
38376 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
38379 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
38380 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
38381 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
38382 (a.icon ? ' x-tree-node-inline-icon' : ''),
38383 (a.iconCls ? ' '+a.iconCls : ''),
38384 '" unselectable="on" />',
38385 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
38386 (a.checked ? 'checked="checked" />' : ' />')) : ''),
38388 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
38389 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
38390 '<span unselectable="on" qtip="' + tx + '">',
38394 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
38395 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
38397 for(var i = 1, len = cols.length; i < len; i++){
38399 colcls = 'x-t-' + tid + '-c' +i;
38400 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
38401 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
38402 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
38408 '<div class="x-clear"></div></div>',
38409 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
38412 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
38413 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
38414 n.nextSibling.ui.getEl(), buf.join(""));
38416 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
38418 var el = this.wrap.firstChild;
38420 this.elNode = el.firstChild;
38421 this.ranchor = el.childNodes[1];
38422 this.ctNode = this.wrap.childNodes[1];
38423 var cs = el.firstChild.childNodes;
38424 this.indentNode = cs[0];
38425 this.ecNode = cs[1];
38426 this.iconNode = cs[2];
38429 this.checkbox = cs[3];
38432 this.anchor = cs[index];
38434 this.textNode = cs[index].firstChild;
38436 //el.on("click", this.onClick, this);
38437 //el.on("dblclick", this.onDblClick, this);
38440 // console.log(this);
38442 initEvents : function(){
38443 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
38446 var a = this.ranchor;
38448 var el = Roo.get(a);
38450 if(Roo.isOpera){ // opera render bug ignores the CSS
38451 el.setStyle("text-decoration", "none");
38454 el.on("click", this.onClick, this);
38455 el.on("dblclick", this.onDblClick, this);
38456 el.on("contextmenu", this.onContextMenu, this);
38460 /*onSelectedChange : function(state){
38463 this.addClass("x-tree-selected");
38466 this.removeClass("x-tree-selected");
38469 addClass : function(cls){
38471 Roo.fly(this.elRow).addClass(cls);
38477 removeClass : function(cls){
38479 Roo.fly(this.elRow).removeClass(cls);
38485 });//<Script type="text/javascript">
38489 * Ext JS Library 1.1.1
38490 * Copyright(c) 2006-2007, Ext JS, LLC.
38492 * Originally Released Under LGPL - original licence link has changed is not relivant.
38495 * <script type="text/javascript">
38500 * @class Roo.tree.ColumnTree
38501 * @extends Roo.tree.TreePanel
38502 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
38503 * @cfg {int} borderWidth compined right/left border allowance
38505 * @param {String/HTMLElement/Element} el The container element
38506 * @param {Object} config
38508 Roo.tree.ColumnTree = function(el, config)
38510 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
38514 * Fire this event on a container when it resizes
38515 * @param {int} w Width
38516 * @param {int} h Height
38520 this.on('resize', this.onResize, this);
38523 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
38527 borderWidth: Roo.isBorderBox ? 0 : 2,
38530 render : function(){
38531 // add the header.....
38533 Roo.tree.ColumnTree.superclass.render.apply(this);
38535 this.el.addClass('x-column-tree');
38537 this.headers = this.el.createChild(
38538 {cls:'x-tree-headers'},this.innerCt.dom);
38540 var cols = this.columns, c;
38541 var totalWidth = 0;
38543 var len = cols.length;
38544 for(var i = 0; i < len; i++){
38546 totalWidth += c.width;
38547 this.headEls.push(this.headers.createChild({
38548 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
38550 cls:'x-tree-hd-text',
38553 style:'width:'+(c.width-this.borderWidth)+'px;'
38556 this.headers.createChild({cls:'x-clear'});
38557 // prevent floats from wrapping when clipped
38558 this.headers.setWidth(totalWidth);
38559 //this.innerCt.setWidth(totalWidth);
38560 this.innerCt.setStyle({ overflow: 'auto' });
38561 this.onResize(this.width, this.height);
38565 onResize : function(w,h)
38570 this.innerCt.setWidth(this.width);
38571 this.innerCt.setHeight(this.height-20);
38574 var cols = this.columns, c;
38575 var totalWidth = 0;
38577 var len = cols.length;
38578 for(var i = 0; i < len; i++){
38580 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
38581 // it's the expander..
38582 expEl = this.headEls[i];
38585 totalWidth += c.width;
38589 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
38591 this.headers.setWidth(w-20);
38600 * Ext JS Library 1.1.1
38601 * Copyright(c) 2006-2007, Ext JS, LLC.
38603 * Originally Released Under LGPL - original licence link has changed is not relivant.
38606 * <script type="text/javascript">
38610 * @class Roo.menu.Menu
38611 * @extends Roo.util.Observable
38612 * @children Roo.menu.Item Roo.menu.Separator Roo.menu.TextItem
38613 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
38614 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
38616 * Creates a new Menu
38617 * @param {Object} config Configuration options
38619 Roo.menu.Menu = function(config){
38621 Roo.menu.Menu.superclass.constructor.call(this, config);
38623 this.id = this.id || Roo.id();
38626 * @event beforeshow
38627 * Fires before this menu is displayed
38628 * @param {Roo.menu.Menu} this
38632 * @event beforehide
38633 * Fires before this menu is hidden
38634 * @param {Roo.menu.Menu} this
38639 * Fires after this menu is displayed
38640 * @param {Roo.menu.Menu} this
38645 * Fires after this menu is hidden
38646 * @param {Roo.menu.Menu} this
38651 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
38652 * @param {Roo.menu.Menu} this
38653 * @param {Roo.menu.Item} menuItem The menu item that was clicked
38654 * @param {Roo.EventObject} e
38659 * Fires when the mouse is hovering over this menu
38660 * @param {Roo.menu.Menu} this
38661 * @param {Roo.EventObject} e
38662 * @param {Roo.menu.Item} menuItem The menu item that was clicked
38667 * Fires when the mouse exits this menu
38668 * @param {Roo.menu.Menu} this
38669 * @param {Roo.EventObject} e
38670 * @param {Roo.menu.Item} menuItem The menu item that was clicked
38675 * Fires when a menu item contained in this menu is clicked
38676 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
38677 * @param {Roo.EventObject} e
38681 if (this.registerMenu) {
38682 Roo.menu.MenuMgr.register(this);
38685 var mis = this.items;
38686 this.items = new Roo.util.MixedCollection();
38688 this.add.apply(this, mis);
38692 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
38694 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
38698 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
38699 * for bottom-right shadow (defaults to "sides")
38703 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
38704 * this menu (defaults to "tl-tr?")
38706 subMenuAlign : "tl-tr?",
38708 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
38709 * relative to its element of origin (defaults to "tl-bl?")
38711 defaultAlign : "tl-bl?",
38713 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
38715 allowOtherMenus : false,
38717 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
38719 registerMenu : true,
38724 render : function(){
38728 var el = this.el = new Roo.Layer({
38730 shadow:this.shadow,
38732 parentEl: this.parentEl || document.body,
38736 this.keyNav = new Roo.menu.MenuNav(this);
38739 el.addClass("x-menu-plain");
38742 el.addClass(this.cls);
38744 // generic focus element
38745 this.focusEl = el.createChild({
38746 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
38748 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
38749 //disabling touch- as it's causing issues ..
38750 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
38751 ul.on('click' , this.onClick, this);
38754 ul.on("mouseover", this.onMouseOver, this);
38755 ul.on("mouseout", this.onMouseOut, this);
38756 this.items.each(function(item){
38761 var li = document.createElement("li");
38762 li.className = "x-menu-list-item";
38763 ul.dom.appendChild(li);
38764 item.render(li, this);
38771 autoWidth : function(){
38772 var el = this.el, ul = this.ul;
38776 var w = this.width;
38779 }else if(Roo.isIE){
38780 el.setWidth(this.minWidth);
38781 var t = el.dom.offsetWidth; // force recalc
38782 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
38787 delayAutoWidth : function(){
38790 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
38792 this.awTask.delay(20);
38797 findTargetItem : function(e){
38798 var t = e.getTarget(".x-menu-list-item", this.ul, true);
38799 if(t && t.menuItemId){
38800 return this.items.get(t.menuItemId);
38805 onClick : function(e){
38806 Roo.log("menu.onClick");
38807 var t = this.findTargetItem(e);
38812 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
38813 if(t == this.activeItem && t.shouldDeactivate(e)){
38814 this.activeItem.deactivate();
38815 delete this.activeItem;
38819 this.setActiveItem(t, true);
38827 this.fireEvent("click", this, t, e);
38831 setActiveItem : function(item, autoExpand){
38832 if(item != this.activeItem){
38833 if(this.activeItem){
38834 this.activeItem.deactivate();
38836 this.activeItem = item;
38837 item.activate(autoExpand);
38838 }else if(autoExpand){
38844 tryActivate : function(start, step){
38845 var items = this.items;
38846 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
38847 var item = items.get(i);
38848 if(!item.disabled && item.canActivate){
38849 this.setActiveItem(item, false);
38857 onMouseOver : function(e){
38859 if(t = this.findTargetItem(e)){
38860 if(t.canActivate && !t.disabled){
38861 this.setActiveItem(t, true);
38864 this.fireEvent("mouseover", this, e, t);
38868 onMouseOut : function(e){
38870 if(t = this.findTargetItem(e)){
38871 if(t == this.activeItem && t.shouldDeactivate(e)){
38872 this.activeItem.deactivate();
38873 delete this.activeItem;
38876 this.fireEvent("mouseout", this, e, t);
38880 * Read-only. Returns true if the menu is currently displayed, else false.
38883 isVisible : function(){
38884 return this.el && !this.hidden;
38888 * Displays this menu relative to another element
38889 * @param {String/HTMLElement/Roo.Element} element The element to align to
38890 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
38891 * the element (defaults to this.defaultAlign)
38892 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
38894 show : function(el, pos, parentMenu){
38895 this.parentMenu = parentMenu;
38899 this.fireEvent("beforeshow", this);
38900 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
38904 * Displays this menu at a specific xy position
38905 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
38906 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
38908 showAt : function(xy, parentMenu, /* private: */_e){
38909 this.parentMenu = parentMenu;
38914 this.fireEvent("beforeshow", this);
38915 xy = this.el.adjustForConstraints(xy);
38919 this.hidden = false;
38921 this.fireEvent("show", this);
38924 focus : function(){
38926 this.doFocus.defer(50, this);
38930 doFocus : function(){
38932 this.focusEl.focus();
38937 * Hides this menu and optionally all parent menus
38938 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
38940 hide : function(deep){
38941 if(this.el && this.isVisible()){
38942 this.fireEvent("beforehide", this);
38943 if(this.activeItem){
38944 this.activeItem.deactivate();
38945 this.activeItem = null;
38948 this.hidden = true;
38949 this.fireEvent("hide", this);
38951 if(deep === true && this.parentMenu){
38952 this.parentMenu.hide(true);
38957 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
38958 * Any of the following are valid:
38960 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
38961 * <li>An HTMLElement object which will be converted to a menu item</li>
38962 * <li>A menu item config object that will be created as a new menu item</li>
38963 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
38964 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
38969 var menu = new Roo.menu.Menu();
38971 // Create a menu item to add by reference
38972 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
38974 // Add a bunch of items at once using different methods.
38975 // Only the last item added will be returned.
38976 var item = menu.add(
38977 menuItem, // add existing item by ref
38978 'Dynamic Item', // new TextItem
38979 '-', // new separator
38980 { text: 'Config Item' } // new item by config
38983 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
38984 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
38987 var a = arguments, l = a.length, item;
38988 for(var i = 0; i < l; i++){
38990 if ((typeof(el) == "object") && el.xtype && el.xns) {
38991 el = Roo.factory(el, Roo.menu);
38994 if(el.render){ // some kind of Item
38995 item = this.addItem(el);
38996 }else if(typeof el == "string"){ // string
38997 if(el == "separator" || el == "-"){
38998 item = this.addSeparator();
39000 item = this.addText(el);
39002 }else if(el.tagName || el.el){ // element
39003 item = this.addElement(el);
39004 }else if(typeof el == "object"){ // must be menu item config?
39005 item = this.addMenuItem(el);
39012 * Returns this menu's underlying {@link Roo.Element} object
39013 * @return {Roo.Element} The element
39015 getEl : function(){
39023 * Adds a separator bar to the menu
39024 * @return {Roo.menu.Item} The menu item that was added
39026 addSeparator : function(){
39027 return this.addItem(new Roo.menu.Separator());
39031 * Adds an {@link Roo.Element} object to the menu
39032 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
39033 * @return {Roo.menu.Item} The menu item that was added
39035 addElement : function(el){
39036 return this.addItem(new Roo.menu.BaseItem(el));
39040 * Adds an existing object based on {@link Roo.menu.Item} to the menu
39041 * @param {Roo.menu.Item} item The menu item to add
39042 * @return {Roo.menu.Item} The menu item that was added
39044 addItem : function(item){
39045 this.items.add(item);
39047 var li = document.createElement("li");
39048 li.className = "x-menu-list-item";
39049 this.ul.dom.appendChild(li);
39050 item.render(li, this);
39051 this.delayAutoWidth();
39057 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
39058 * @param {Object} config A MenuItem config object
39059 * @return {Roo.menu.Item} The menu item that was added
39061 addMenuItem : function(config){
39062 if(!(config instanceof Roo.menu.Item)){
39063 if(typeof config.checked == "boolean"){ // must be check menu item config?
39064 config = new Roo.menu.CheckItem(config);
39066 config = new Roo.menu.Item(config);
39069 return this.addItem(config);
39073 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
39074 * @param {String} text The text to display in the menu item
39075 * @return {Roo.menu.Item} The menu item that was added
39077 addText : function(text){
39078 return this.addItem(new Roo.menu.TextItem({ text : text }));
39082 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
39083 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
39084 * @param {Roo.menu.Item} item The menu item to add
39085 * @return {Roo.menu.Item} The menu item that was added
39087 insert : function(index, item){
39088 this.items.insert(index, item);
39090 var li = document.createElement("li");
39091 li.className = "x-menu-list-item";
39092 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
39093 item.render(li, this);
39094 this.delayAutoWidth();
39100 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
39101 * @param {Roo.menu.Item} item The menu item to remove
39103 remove : function(item){
39104 this.items.removeKey(item.id);
39109 * Removes and destroys all items in the menu
39111 removeAll : function(){
39113 while(f = this.items.first()){
39119 // MenuNav is a private utility class used internally by the Menu
39120 Roo.menu.MenuNav = function(menu){
39121 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
39122 this.scope = this.menu = menu;
39125 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
39126 doRelay : function(e, h){
39127 var k = e.getKey();
39128 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
39129 this.menu.tryActivate(0, 1);
39132 return h.call(this.scope || this, e, this.menu);
39135 up : function(e, m){
39136 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
39137 m.tryActivate(m.items.length-1, -1);
39141 down : function(e, m){
39142 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
39143 m.tryActivate(0, 1);
39147 right : function(e, m){
39149 m.activeItem.expandMenu(true);
39153 left : function(e, m){
39155 if(m.parentMenu && m.parentMenu.activeItem){
39156 m.parentMenu.activeItem.activate();
39160 enter : function(e, m){
39162 e.stopPropagation();
39163 m.activeItem.onClick(e);
39164 m.fireEvent("click", this, m.activeItem);
39170 * Ext JS Library 1.1.1
39171 * Copyright(c) 2006-2007, Ext JS, LLC.
39173 * Originally Released Under LGPL - original licence link has changed is not relivant.
39176 * <script type="text/javascript">
39180 * @class Roo.menu.MenuMgr
39181 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
39184 Roo.menu.MenuMgr = function(){
39185 var menus, active, groups = {}, attached = false, lastShow = new Date();
39187 // private - called when first menu is created
39190 active = new Roo.util.MixedCollection();
39191 Roo.get(document).addKeyListener(27, function(){
39192 if(active.length > 0){
39199 function hideAll(){
39200 if(active && active.length > 0){
39201 var c = active.clone();
39202 c.each(function(m){
39209 function onHide(m){
39211 if(active.length < 1){
39212 Roo.get(document).un("mousedown", onMouseDown);
39218 function onShow(m){
39219 var last = active.last();
39220 lastShow = new Date();
39223 Roo.get(document).on("mousedown", onMouseDown);
39227 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
39228 m.parentMenu.activeChild = m;
39229 }else if(last && last.isVisible()){
39230 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
39235 function onBeforeHide(m){
39237 m.activeChild.hide();
39239 if(m.autoHideTimer){
39240 clearTimeout(m.autoHideTimer);
39241 delete m.autoHideTimer;
39246 function onBeforeShow(m){
39247 var pm = m.parentMenu;
39248 if(!pm && !m.allowOtherMenus){
39250 }else if(pm && pm.activeChild && active != m){
39251 pm.activeChild.hide();
39256 function onMouseDown(e){
39257 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
39263 function onBeforeCheck(mi, state){
39265 var g = groups[mi.group];
39266 for(var i = 0, l = g.length; i < l; i++){
39268 g[i].setChecked(false);
39277 * Hides all menus that are currently visible
39279 hideAll : function(){
39284 register : function(menu){
39288 menus[menu.id] = menu;
39289 menu.on("beforehide", onBeforeHide);
39290 menu.on("hide", onHide);
39291 menu.on("beforeshow", onBeforeShow);
39292 menu.on("show", onShow);
39293 var g = menu.group;
39294 if(g && menu.events["checkchange"]){
39298 groups[g].push(menu);
39299 menu.on("checkchange", onCheck);
39304 * Returns a {@link Roo.menu.Menu} object
39305 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
39306 * be used to generate and return a new Menu instance.
39308 get : function(menu){
39309 if(typeof menu == "string"){ // menu id
39310 return menus[menu];
39311 }else if(menu.events){ // menu instance
39313 }else if(typeof menu.length == 'number'){ // array of menu items?
39314 return new Roo.menu.Menu({items:menu});
39315 }else{ // otherwise, must be a config
39316 return new Roo.menu.Menu(menu);
39321 unregister : function(menu){
39322 delete menus[menu.id];
39323 menu.un("beforehide", onBeforeHide);
39324 menu.un("hide", onHide);
39325 menu.un("beforeshow", onBeforeShow);
39326 menu.un("show", onShow);
39327 var g = menu.group;
39328 if(g && menu.events["checkchange"]){
39329 groups[g].remove(menu);
39330 menu.un("checkchange", onCheck);
39335 registerCheckable : function(menuItem){
39336 var g = menuItem.group;
39341 groups[g].push(menuItem);
39342 menuItem.on("beforecheckchange", onBeforeCheck);
39347 unregisterCheckable : function(menuItem){
39348 var g = menuItem.group;
39350 groups[g].remove(menuItem);
39351 menuItem.un("beforecheckchange", onBeforeCheck);
39357 * Ext JS Library 1.1.1
39358 * Copyright(c) 2006-2007, Ext JS, LLC.
39360 * Originally Released Under LGPL - original licence link has changed is not relivant.
39363 * <script type="text/javascript">
39368 * @class Roo.menu.BaseItem
39369 * @extends Roo.Component
39371 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
39372 * management and base configuration options shared by all menu components.
39374 * Creates a new BaseItem
39375 * @param {Object} config Configuration options
39377 Roo.menu.BaseItem = function(config){
39378 Roo.menu.BaseItem.superclass.constructor.call(this, config);
39383 * Fires when this item is clicked
39384 * @param {Roo.menu.BaseItem} this
39385 * @param {Roo.EventObject} e
39390 * Fires when this item is activated
39391 * @param {Roo.menu.BaseItem} this
39395 * @event deactivate
39396 * Fires when this item is deactivated
39397 * @param {Roo.menu.BaseItem} this
39403 this.on("click", this.handler, this.scope, true);
39407 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
39409 * @cfg {Function} handler
39410 * A function that will handle the click event of this menu item (defaults to undefined)
39413 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
39415 canActivate : false,
39418 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
39423 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
39425 activeClass : "x-menu-item-active",
39427 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
39429 hideOnClick : true,
39431 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
39436 ctype: "Roo.menu.BaseItem",
39439 actionMode : "container",
39442 render : function(container, parentMenu){
39443 this.parentMenu = parentMenu;
39444 Roo.menu.BaseItem.superclass.render.call(this, container);
39445 this.container.menuItemId = this.id;
39449 onRender : function(container, position){
39450 this.el = Roo.get(this.el);
39451 container.dom.appendChild(this.el.dom);
39455 onClick : function(e){
39456 if(!this.disabled && this.fireEvent("click", this, e) !== false
39457 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
39458 this.handleClick(e);
39465 activate : function(){
39469 var li = this.container;
39470 li.addClass(this.activeClass);
39471 this.region = li.getRegion().adjust(2, 2, -2, -2);
39472 this.fireEvent("activate", this);
39477 deactivate : function(){
39478 this.container.removeClass(this.activeClass);
39479 this.fireEvent("deactivate", this);
39483 shouldDeactivate : function(e){
39484 return !this.region || !this.region.contains(e.getPoint());
39488 handleClick : function(e){
39489 if(this.hideOnClick){
39490 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
39495 expandMenu : function(autoActivate){
39500 hideMenu : function(){
39505 * Ext JS Library 1.1.1
39506 * Copyright(c) 2006-2007, Ext JS, LLC.
39508 * Originally Released Under LGPL - original licence link has changed is not relivant.
39511 * <script type="text/javascript">
39515 * @class Roo.menu.Adapter
39516 * @extends Roo.menu.BaseItem
39518 * A base utility class that adapts a non-menu component so that it can be wrapped by a menu item and added to a menu.
39519 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
39521 * Creates a new Adapter
39522 * @param {Object} config Configuration options
39524 Roo.menu.Adapter = function(component, config){
39525 Roo.menu.Adapter.superclass.constructor.call(this, config);
39526 this.component = component;
39528 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
39530 canActivate : true,
39533 onRender : function(container, position){
39534 this.component.render(container);
39535 this.el = this.component.getEl();
39539 activate : function(){
39543 this.component.focus();
39544 this.fireEvent("activate", this);
39549 deactivate : function(){
39550 this.fireEvent("deactivate", this);
39554 disable : function(){
39555 this.component.disable();
39556 Roo.menu.Adapter.superclass.disable.call(this);
39560 enable : function(){
39561 this.component.enable();
39562 Roo.menu.Adapter.superclass.enable.call(this);
39566 * Ext JS Library 1.1.1
39567 * Copyright(c) 2006-2007, Ext JS, LLC.
39569 * Originally Released Under LGPL - original licence link has changed is not relivant.
39572 * <script type="text/javascript">
39576 * @class Roo.menu.TextItem
39577 * @extends Roo.menu.BaseItem
39578 * Adds a static text string to a menu, usually used as either a heading or group separator.
39579 * Note: old style constructor with text is still supported.
39582 * Creates a new TextItem
39583 * @param {Object} cfg Configuration
39585 Roo.menu.TextItem = function(cfg){
39586 if (typeof(cfg) == 'string') {
39589 Roo.apply(this,cfg);
39592 Roo.menu.TextItem.superclass.constructor.call(this);
39595 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
39597 * @cfg {String} text Text to show on item.
39602 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
39604 hideOnClick : false,
39606 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
39608 itemCls : "x-menu-text",
39611 onRender : function(){
39612 var s = document.createElement("span");
39613 s.className = this.itemCls;
39614 s.innerHTML = this.text;
39616 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
39620 * Ext JS Library 1.1.1
39621 * Copyright(c) 2006-2007, Ext JS, LLC.
39623 * Originally Released Under LGPL - original licence link has changed is not relivant.
39626 * <script type="text/javascript">
39630 * @class Roo.menu.Separator
39631 * @extends Roo.menu.BaseItem
39632 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
39633 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
39635 * @param {Object} config Configuration options
39637 Roo.menu.Separator = function(config){
39638 Roo.menu.Separator.superclass.constructor.call(this, config);
39641 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
39643 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
39645 itemCls : "x-menu-sep",
39647 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
39649 hideOnClick : false,
39652 onRender : function(li){
39653 var s = document.createElement("span");
39654 s.className = this.itemCls;
39655 s.innerHTML = " ";
39657 li.addClass("x-menu-sep-li");
39658 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
39662 * Ext JS Library 1.1.1
39663 * Copyright(c) 2006-2007, Ext JS, LLC.
39665 * Originally Released Under LGPL - original licence link has changed is not relivant.
39668 * <script type="text/javascript">
39671 * @class Roo.menu.Item
39672 * @extends Roo.menu.BaseItem
39673 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
39674 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
39675 * activation and click handling.
39677 * Creates a new Item
39678 * @param {Object} config Configuration options
39680 Roo.menu.Item = function(config){
39681 Roo.menu.Item.superclass.constructor.call(this, config);
39683 this.menu = Roo.menu.MenuMgr.get(this.menu);
39686 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
39688 * @cfg {Roo.menu.Menu} menu
39692 * @cfg {String} text
39693 * The text to show on the menu item.
39697 * @cfg {String} HTML to render in menu
39698 * The text to show on the menu item (HTML version).
39702 * @cfg {String} icon
39703 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
39707 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
39709 itemCls : "x-menu-item",
39711 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
39713 canActivate : true,
39715 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
39718 // doc'd in BaseItem
39722 ctype: "Roo.menu.Item",
39725 onRender : function(container, position){
39726 var el = document.createElement("a");
39727 el.hideFocus = true;
39728 el.unselectable = "on";
39729 el.href = this.href || "#";
39730 if(this.hrefTarget){
39731 el.target = this.hrefTarget;
39733 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
39735 var html = this.html.length ? this.html : String.format('{0}',this.text);
39737 el.innerHTML = String.format(
39738 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
39739 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
39741 Roo.menu.Item.superclass.onRender.call(this, container, position);
39745 * Sets the text to display in this menu item
39746 * @param {String} text The text to display
39747 * @param {Boolean} isHTML true to indicate text is pure html.
39749 setText : function(text, isHTML){
39757 var html = this.html.length ? this.html : String.format('{0}',this.text);
39759 this.el.update(String.format(
39760 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
39761 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
39762 this.parentMenu.autoWidth();
39767 handleClick : function(e){
39768 if(!this.href){ // if no link defined, stop the event automatically
39771 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
39775 activate : function(autoExpand){
39776 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
39786 shouldDeactivate : function(e){
39787 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
39788 if(this.menu && this.menu.isVisible()){
39789 return !this.menu.getEl().getRegion().contains(e.getPoint());
39797 deactivate : function(){
39798 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
39803 expandMenu : function(autoActivate){
39804 if(!this.disabled && this.menu){
39805 clearTimeout(this.hideTimer);
39806 delete this.hideTimer;
39807 if(!this.menu.isVisible() && !this.showTimer){
39808 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
39809 }else if (this.menu.isVisible() && autoActivate){
39810 this.menu.tryActivate(0, 1);
39816 deferExpand : function(autoActivate){
39817 delete this.showTimer;
39818 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
39820 this.menu.tryActivate(0, 1);
39825 hideMenu : function(){
39826 clearTimeout(this.showTimer);
39827 delete this.showTimer;
39828 if(!this.hideTimer && this.menu && this.menu.isVisible()){
39829 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
39834 deferHide : function(){
39835 delete this.hideTimer;
39840 * Ext JS Library 1.1.1
39841 * Copyright(c) 2006-2007, Ext JS, LLC.
39843 * Originally Released Under LGPL - original licence link has changed is not relivant.
39846 * <script type="text/javascript">
39850 * @class Roo.menu.CheckItem
39851 * @extends Roo.menu.Item
39852 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
39854 * Creates a new CheckItem
39855 * @param {Object} config Configuration options
39857 Roo.menu.CheckItem = function(config){
39858 Roo.menu.CheckItem.superclass.constructor.call(this, config);
39861 * @event beforecheckchange
39862 * Fires before the checked value is set, providing an opportunity to cancel if needed
39863 * @param {Roo.menu.CheckItem} this
39864 * @param {Boolean} checked The new checked value that will be set
39866 "beforecheckchange" : true,
39868 * @event checkchange
39869 * Fires after the checked value has been set
39870 * @param {Roo.menu.CheckItem} this
39871 * @param {Boolean} checked The checked value that was set
39873 "checkchange" : true
39875 if(this.checkHandler){
39876 this.on('checkchange', this.checkHandler, this.scope);
39879 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
39881 * @cfg {String} group
39882 * All check items with the same group name will automatically be grouped into a single-select
39883 * radio button group (defaults to '')
39886 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
39888 itemCls : "x-menu-item x-menu-check-item",
39890 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
39892 groupClass : "x-menu-group-item",
39895 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
39896 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
39897 * initialized with checked = true will be rendered as checked.
39902 ctype: "Roo.menu.CheckItem",
39905 onRender : function(c){
39906 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
39908 this.el.addClass(this.groupClass);
39910 Roo.menu.MenuMgr.registerCheckable(this);
39912 this.checked = false;
39913 this.setChecked(true, true);
39918 destroy : function(){
39920 Roo.menu.MenuMgr.unregisterCheckable(this);
39922 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
39926 * Set the checked state of this item
39927 * @param {Boolean} checked The new checked value
39928 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
39930 setChecked : function(state, suppressEvent){
39931 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
39932 if(this.container){
39933 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
39935 this.checked = state;
39936 if(suppressEvent !== true){
39937 this.fireEvent("checkchange", this, state);
39943 handleClick : function(e){
39944 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
39945 this.setChecked(!this.checked);
39947 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
39951 * Ext JS Library 1.1.1
39952 * Copyright(c) 2006-2007, Ext JS, LLC.
39954 * Originally Released Under LGPL - original licence link has changed is not relivant.
39957 * <script type="text/javascript">
39961 * @class Roo.menu.DateItem
39962 * @extends Roo.menu.Adapter
39963 * A menu item that wraps the {@link Roo.DatPicker} component.
39965 * Creates a new DateItem
39966 * @param {Object} config Configuration options
39968 Roo.menu.DateItem = function(config){
39969 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
39970 /** The Roo.DatePicker object @type Roo.DatePicker */
39971 this.picker = this.component;
39972 this.addEvents({select: true});
39974 this.picker.on("render", function(picker){
39975 picker.getEl().swallowEvent("click");
39976 picker.container.addClass("x-menu-date-item");
39979 this.picker.on("select", this.onSelect, this);
39982 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
39984 onSelect : function(picker, date){
39985 this.fireEvent("select", this, date, picker);
39986 Roo.menu.DateItem.superclass.handleClick.call(this);
39990 * Ext JS Library 1.1.1
39991 * Copyright(c) 2006-2007, Ext JS, LLC.
39993 * Originally Released Under LGPL - original licence link has changed is not relivant.
39996 * <script type="text/javascript">
40000 * @class Roo.menu.ColorItem
40001 * @extends Roo.menu.Adapter
40002 * A menu item that wraps the {@link Roo.ColorPalette} component.
40004 * Creates a new ColorItem
40005 * @param {Object} config Configuration options
40007 Roo.menu.ColorItem = function(config){
40008 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
40009 /** The Roo.ColorPalette object @type Roo.ColorPalette */
40010 this.palette = this.component;
40011 this.relayEvents(this.palette, ["select"]);
40012 if(this.selectHandler){
40013 this.on('select', this.selectHandler, this.scope);
40016 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
40018 * Ext JS Library 1.1.1
40019 * Copyright(c) 2006-2007, Ext JS, LLC.
40021 * Originally Released Under LGPL - original licence link has changed is not relivant.
40024 * <script type="text/javascript">
40029 * @class Roo.menu.DateMenu
40030 * @extends Roo.menu.Menu
40031 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
40033 * Creates a new DateMenu
40034 * @param {Object} config Configuration options
40036 Roo.menu.DateMenu = function(config){
40037 Roo.menu.DateMenu.superclass.constructor.call(this, config);
40039 var di = new Roo.menu.DateItem(config);
40042 * The {@link Roo.DatePicker} instance for this DateMenu
40045 this.picker = di.picker;
40048 * @param {DatePicker} picker
40049 * @param {Date} date
40051 this.relayEvents(di, ["select"]);
40052 this.on('beforeshow', function(){
40054 this.picker.hideMonthPicker(false);
40058 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
40062 * Ext JS Library 1.1.1
40063 * Copyright(c) 2006-2007, Ext JS, LLC.
40065 * Originally Released Under LGPL - original licence link has changed is not relivant.
40068 * <script type="text/javascript">
40073 * @class Roo.menu.ColorMenu
40074 * @extends Roo.menu.Menu
40075 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
40077 * Creates a new ColorMenu
40078 * @param {Object} config Configuration options
40080 Roo.menu.ColorMenu = function(config){
40081 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
40083 var ci = new Roo.menu.ColorItem(config);
40086 * The {@link Roo.ColorPalette} instance for this ColorMenu
40087 * @type ColorPalette
40089 this.palette = ci.palette;
40092 * @param {ColorPalette} palette
40093 * @param {String} color
40095 this.relayEvents(ci, ["select"]);
40097 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
40099 * Ext JS Library 1.1.1
40100 * Copyright(c) 2006-2007, Ext JS, LLC.
40102 * Originally Released Under LGPL - original licence link has changed is not relivant.
40105 * <script type="text/javascript">
40109 * @class Roo.form.TextItem
40110 * @extends Roo.BoxComponent
40111 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
40113 * Creates a new TextItem
40114 * @param {Object} config Configuration options
40116 Roo.form.TextItem = function(config){
40117 Roo.form.TextItem.superclass.constructor.call(this, config);
40120 Roo.extend(Roo.form.TextItem, Roo.BoxComponent, {
40123 * @cfg {String} tag the tag for this item (default div)
40127 * @cfg {String} html the content for this item
40131 getAutoCreate : function()
40144 onRender : function(ct, position)
40146 Roo.form.TextItem.superclass.onRender.call(this, ct, position);
40149 var cfg = this.getAutoCreate();
40151 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
40153 if (!cfg.name.length) {
40156 this.el = ct.createChild(cfg, position);
40161 * @param {String} html update the Contents of the element.
40163 setHTML : function(html)
40165 this.fieldEl.dom.innerHTML = html;
40170 * Ext JS Library 1.1.1
40171 * Copyright(c) 2006-2007, Ext JS, LLC.
40173 * Originally Released Under LGPL - original licence link has changed is not relivant.
40176 * <script type="text/javascript">
40180 * @class Roo.form.Field
40181 * @extends Roo.BoxComponent
40182 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
40184 * Creates a new Field
40185 * @param {Object} config Configuration options
40187 Roo.form.Field = function(config){
40188 Roo.form.Field.superclass.constructor.call(this, config);
40191 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
40193 * @cfg {String} fieldLabel Label to use when rendering a form.
40196 * @cfg {String} qtip Mouse over tip
40200 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
40202 invalidClass : "x-form-invalid",
40204 * @cfg {String} invalidText The error text to use when marking a field invalid and no message is provided (defaults to "The value in this field is invalid")
40206 invalidText : "The value in this field is invalid",
40208 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
40210 focusClass : "x-form-focus",
40212 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
40213 automatic validation (defaults to "keyup").
40215 validationEvent : "keyup",
40217 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
40219 validateOnBlur : true,
40221 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
40223 validationDelay : 250,
40225 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40226 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
40228 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
40230 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
40232 fieldClass : "x-form-field",
40234 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
40237 ----------- ----------------------------------------------------------------------
40238 qtip Display a quick tip when the user hovers over the field
40239 title Display a default browser title attribute popup
40240 under Add a block div beneath the field containing the error text
40241 side Add an error icon to the right of the field with a popup on hover
40242 [element id] Add the error text directly to the innerHTML of the specified element
40245 msgTarget : 'qtip',
40247 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
40252 * @cfg {Boolean} readOnly True to mark the field as readOnly in HTML (defaults to false) -- Note: this only sets the element's readOnly DOM attribute.
40257 * @cfg {Boolean} disabled True to disable the field (defaults to false).
40262 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
40264 inputType : undefined,
40267 * @cfg {Number} tabIndex The tabIndex for this field. Note this only applies to fields that are rendered, not those which are built via applyTo (defaults to undefined).
40269 tabIndex : undefined,
40272 isFormField : true,
40277 * @property {Roo.Element} fieldEl
40278 * Element Containing the rendered Field (with label etc.)
40281 * @cfg {Mixed} value A value to initialize this field with.
40286 * @cfg {String} name The field's HTML name attribute.
40289 * @cfg {String} cls A CSS class to apply to the field's underlying element.
40292 loadedValue : false,
40296 initComponent : function(){
40297 Roo.form.Field.superclass.initComponent.call(this);
40301 * Fires when this field receives input focus.
40302 * @param {Roo.form.Field} this
40307 * Fires when this field loses input focus.
40308 * @param {Roo.form.Field} this
40312 * @event specialkey
40313 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
40314 * {@link Roo.EventObject#getKey} to determine which key was pressed.
40315 * @param {Roo.form.Field} this
40316 * @param {Roo.EventObject} e The event object
40321 * Fires just before the field blurs if the field value has changed.
40322 * @param {Roo.form.Field} this
40323 * @param {Mixed} newValue The new value
40324 * @param {Mixed} oldValue The original value
40329 * Fires after the field has been marked as invalid.
40330 * @param {Roo.form.Field} this
40331 * @param {String} msg The validation message
40336 * Fires after the field has been validated with no errors.
40337 * @param {Roo.form.Field} this
40342 * Fires after the key up
40343 * @param {Roo.form.Field} this
40344 * @param {Roo.EventObject} e The event Object
40351 * Returns the name attribute of the field if available
40352 * @return {String} name The field name
40354 getName: function(){
40355 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40359 onRender : function(ct, position){
40360 Roo.form.Field.superclass.onRender.call(this, ct, position);
40362 var cfg = this.getAutoCreate();
40364 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
40366 if (!cfg.name.length) {
40369 if(this.inputType){
40370 cfg.type = this.inputType;
40372 this.el = ct.createChild(cfg, position);
40374 var type = this.el.dom.type;
40376 if(type == 'password'){
40379 this.el.addClass('x-form-'+type);
40382 this.el.dom.readOnly = true;
40384 if(this.tabIndex !== undefined){
40385 this.el.dom.setAttribute('tabIndex', this.tabIndex);
40388 this.el.addClass([this.fieldClass, this.cls]);
40393 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
40394 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
40395 * @return {Roo.form.Field} this
40397 applyTo : function(target){
40398 this.allowDomMove = false;
40399 this.el = Roo.get(target);
40400 this.render(this.el.dom.parentNode);
40405 initValue : function(){
40406 if(this.value !== undefined){
40407 this.setValue(this.value);
40408 }else if(this.el.dom.value.length > 0){
40409 this.setValue(this.el.dom.value);
40414 * Returns true if this field has been changed since it was originally loaded and is not disabled.
40415 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
40417 isDirty : function() {
40418 if(this.disabled) {
40421 return String(this.getValue()) !== String(this.originalValue);
40425 * stores the current value in loadedValue
40427 resetHasChanged : function()
40429 this.loadedValue = String(this.getValue());
40432 * checks the current value against the 'loaded' value.
40433 * Note - will return false if 'resetHasChanged' has not been called first.
40435 hasChanged : function()
40437 if(this.disabled || this.readOnly) {
40440 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
40446 afterRender : function(){
40447 Roo.form.Field.superclass.afterRender.call(this);
40452 fireKey : function(e){
40453 //Roo.log('field ' + e.getKey());
40454 if(e.isNavKeyPress()){
40455 this.fireEvent("specialkey", this, e);
40460 * Resets the current field value to the originally loaded value and clears any validation messages
40462 reset : function(){
40463 this.setValue(this.resetValue);
40464 this.originalValue = this.getValue();
40465 this.clearInvalid();
40469 initEvents : function(){
40470 // safari killled keypress - so keydown is now used..
40471 this.el.on("keydown" , this.fireKey, this);
40472 this.el.on("focus", this.onFocus, this);
40473 this.el.on("blur", this.onBlur, this);
40474 this.el.relayEvent('keyup', this);
40476 // reference to original value for reset
40477 this.originalValue = this.getValue();
40478 this.resetValue = this.getValue();
40482 onFocus : function(){
40483 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40484 this.el.addClass(this.focusClass);
40486 if(!this.hasFocus){
40487 this.hasFocus = true;
40488 this.startValue = this.getValue();
40489 this.fireEvent("focus", this);
40493 beforeBlur : Roo.emptyFn,
40496 onBlur : function(){
40498 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40499 this.el.removeClass(this.focusClass);
40501 this.hasFocus = false;
40502 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40505 var v = this.getValue();
40506 if(String(v) !== String(this.startValue)){
40507 this.fireEvent('change', this, v, this.startValue);
40509 this.fireEvent("blur", this);
40513 * Returns whether or not the field value is currently valid
40514 * @param {Boolean} preventMark True to disable marking the field invalid
40515 * @return {Boolean} True if the value is valid, else false
40517 isValid : function(preventMark){
40521 var restore = this.preventMark;
40522 this.preventMark = preventMark === true;
40523 var v = this.validateValue(this.processValue(this.getRawValue()));
40524 this.preventMark = restore;
40529 * Validates the field value
40530 * @return {Boolean} True if the value is valid, else false
40532 validate : function(){
40533 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
40534 this.clearInvalid();
40540 processValue : function(value){
40545 // Subclasses should provide the validation implementation by overriding this
40546 validateValue : function(value){
40551 * Mark this field as invalid
40552 * @param {String} msg The validation message
40554 markInvalid : function(msg){
40555 if(!this.rendered || this.preventMark){ // not rendered
40559 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
40561 obj.el.addClass(this.invalidClass);
40562 msg = msg || this.invalidText;
40563 switch(this.msgTarget){
40565 obj.el.dom.qtip = msg;
40566 obj.el.dom.qclass = 'x-form-invalid-tip';
40567 if(Roo.QuickTips){ // fix for floating editors interacting with DND
40568 Roo.QuickTips.enable();
40572 this.el.dom.title = msg;
40576 var elp = this.el.findParent('.x-form-element', 5, true);
40577 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
40578 this.errorEl.setWidth(elp.getWidth(true)-20);
40580 this.errorEl.update(msg);
40581 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
40584 if(!this.errorIcon){
40585 var elp = this.el.findParent('.x-form-element', 5, true);
40586 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
40588 this.alignErrorIcon();
40589 this.errorIcon.dom.qtip = msg;
40590 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
40591 this.errorIcon.show();
40592 this.on('resize', this.alignErrorIcon, this);
40595 var t = Roo.getDom(this.msgTarget);
40597 t.style.display = this.msgDisplay;
40600 this.fireEvent('invalid', this, msg);
40604 alignErrorIcon : function(){
40605 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
40609 * Clear any invalid styles/messages for this field
40611 clearInvalid : function(){
40612 if(!this.rendered || this.preventMark){ // not rendered
40615 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
40617 obj.el.removeClass(this.invalidClass);
40618 switch(this.msgTarget){
40620 obj.el.dom.qtip = '';
40623 this.el.dom.title = '';
40627 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
40631 if(this.errorIcon){
40632 this.errorIcon.dom.qtip = '';
40633 this.errorIcon.hide();
40634 this.un('resize', this.alignErrorIcon, this);
40638 var t = Roo.getDom(this.msgTarget);
40640 t.style.display = 'none';
40643 this.fireEvent('valid', this);
40647 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
40648 * @return {Mixed} value The field value
40650 getRawValue : function(){
40651 var v = this.el.getValue();
40657 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
40658 * @return {Mixed} value The field value
40660 getValue : function(){
40661 var v = this.el.getValue();
40667 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
40668 * @param {Mixed} value The value to set
40670 setRawValue : function(v){
40671 return this.el.dom.value = (v === null || v === undefined ? '' : v);
40675 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
40676 * @param {Mixed} value The value to set
40678 setValue : function(v){
40681 this.el.dom.value = (v === null || v === undefined ? '' : v);
40686 adjustSize : function(w, h){
40687 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
40688 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
40692 adjustWidth : function(tag, w){
40693 tag = tag.toLowerCase();
40694 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
40695 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
40696 if(tag == 'input'){
40699 if(tag == 'textarea'){
40702 }else if(Roo.isOpera){
40703 if(tag == 'input'){
40706 if(tag == 'textarea'){
40716 // anything other than normal should be considered experimental
40717 Roo.form.Field.msgFx = {
40719 show: function(msgEl, f){
40720 msgEl.setDisplayed('block');
40723 hide : function(msgEl, f){
40724 msgEl.setDisplayed(false).update('');
40729 show: function(msgEl, f){
40730 msgEl.slideIn('t', {stopFx:true});
40733 hide : function(msgEl, f){
40734 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
40739 show: function(msgEl, f){
40740 msgEl.fixDisplay();
40741 msgEl.alignTo(f.el, 'tl-tr');
40742 msgEl.slideIn('l', {stopFx:true});
40745 hide : function(msgEl, f){
40746 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
40751 * Ext JS Library 1.1.1
40752 * Copyright(c) 2006-2007, Ext JS, LLC.
40754 * Originally Released Under LGPL - original licence link has changed is not relivant.
40757 * <script type="text/javascript">
40762 * @class Roo.form.TextField
40763 * @extends Roo.form.Field
40764 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
40765 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
40767 * Creates a new TextField
40768 * @param {Object} config Configuration options
40770 Roo.form.TextField = function(config){
40771 Roo.form.TextField.superclass.constructor.call(this, config);
40775 * Fires when the autosize function is triggered. The field may or may not have actually changed size
40776 * according to the default logic, but this event provides a hook for the developer to apply additional
40777 * logic at runtime to resize the field if needed.
40778 * @param {Roo.form.Field} this This text field
40779 * @param {Number} width The new field width
40785 Roo.extend(Roo.form.TextField, Roo.form.Field, {
40787 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
40791 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
40795 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
40799 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
40803 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
40807 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
40809 disableKeyFilter : false,
40811 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
40815 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
40819 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
40821 maxLength : Number.MAX_VALUE,
40823 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
40825 minLengthText : "The minimum length for this field is {0}",
40827 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
40829 maxLengthText : "The maximum length for this field is {0}",
40831 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
40833 selectOnFocus : false,
40835 * @cfg {Boolean} allowLeadingSpace True to prevent the stripping of leading white space
40837 allowLeadingSpace : false,
40839 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
40841 blankText : "This field is required",
40843 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
40844 * If available, this function will be called only after the basic validators all return true, and will be passed the
40845 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
40849 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
40850 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
40851 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
40855 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
40859 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
40865 initEvents : function()
40867 if (this.emptyText) {
40868 this.el.attr('placeholder', this.emptyText);
40871 Roo.form.TextField.superclass.initEvents.call(this);
40872 if(this.validationEvent == 'keyup'){
40873 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40874 this.el.on('keyup', this.filterValidation, this);
40876 else if(this.validationEvent !== false){
40877 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40880 if(this.selectOnFocus){
40881 this.on("focus", this.preFocus, this);
40883 if (!this.allowLeadingSpace) {
40884 this.on('blur', this.cleanLeadingSpace, this);
40887 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40888 this.el.on("keypress", this.filterKeys, this);
40891 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
40892 this.el.on("click", this.autoSize, this);
40894 if(this.el.is('input[type=password]') && Roo.isSafari){
40895 this.el.on('keydown', this.SafariOnKeyDown, this);
40899 processValue : function(value){
40900 if(this.stripCharsRe){
40901 var newValue = value.replace(this.stripCharsRe, '');
40902 if(newValue !== value){
40903 this.setRawValue(newValue);
40910 filterValidation : function(e){
40911 if(!e.isNavKeyPress()){
40912 this.validationTask.delay(this.validationDelay);
40917 onKeyUp : function(e){
40918 if(!e.isNavKeyPress()){
40922 // private - clean the leading white space
40923 cleanLeadingSpace : function(e)
40925 if ( this.inputType == 'file') {
40929 this.setValue((this.getValue() + '').replace(/^\s+/,''));
40932 * Resets the current field value to the originally-loaded value and clears any validation messages.
40935 reset : function(){
40936 Roo.form.TextField.superclass.reset.call(this);
40940 preFocus : function(){
40942 if(this.selectOnFocus){
40943 this.el.dom.select();
40949 filterKeys : function(e){
40950 var k = e.getKey();
40951 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
40954 var c = e.getCharCode(), cc = String.fromCharCode(c);
40955 if(Roo.isIE && (e.isSpecialKey() || !cc)){
40958 if(!this.maskRe.test(cc)){
40963 setValue : function(v){
40965 Roo.form.TextField.superclass.setValue.apply(this, arguments);
40971 * Validates a value according to the field's validation rules and marks the field as invalid
40972 * if the validation fails
40973 * @param {Mixed} value The value to validate
40974 * @return {Boolean} True if the value is valid, else false
40976 validateValue : function(value){
40977 if(value.length < 1) { // if it's blank
40978 if(this.allowBlank){
40979 this.clearInvalid();
40982 this.markInvalid(this.blankText);
40986 if(value.length < this.minLength){
40987 this.markInvalid(String.format(this.minLengthText, this.minLength));
40990 if(value.length > this.maxLength){
40991 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
40995 var vt = Roo.form.VTypes;
40996 if(!vt[this.vtype](value, this)){
40997 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
41001 if(typeof this.validator == "function"){
41002 var msg = this.validator(value);
41004 this.markInvalid(msg);
41008 if(this.regex && !this.regex.test(value)){
41009 this.markInvalid(this.regexText);
41016 * Selects text in this field
41017 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
41018 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
41020 selectText : function(start, end){
41021 var v = this.getRawValue();
41023 start = start === undefined ? 0 : start;
41024 end = end === undefined ? v.length : end;
41025 var d = this.el.dom;
41026 if(d.setSelectionRange){
41027 d.setSelectionRange(start, end);
41028 }else if(d.createTextRange){
41029 var range = d.createTextRange();
41030 range.moveStart("character", start);
41031 range.moveEnd("character", v.length-end);
41038 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
41039 * This only takes effect if grow = true, and fires the autosize event.
41041 autoSize : function(){
41042 if(!this.grow || !this.rendered){
41046 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
41049 var v = el.dom.value;
41050 var d = document.createElement('div');
41051 d.appendChild(document.createTextNode(v));
41055 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
41056 this.el.setWidth(w);
41057 this.fireEvent("autosize", this, w);
41061 SafariOnKeyDown : function(event)
41063 // this is a workaround for a password hang bug on chrome/ webkit.
41065 var isSelectAll = false;
41067 if(this.el.dom.selectionEnd > 0){
41068 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
41070 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
41071 event.preventDefault();
41076 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
41078 event.preventDefault();
41079 // this is very hacky as keydown always get's upper case.
41081 var cc = String.fromCharCode(event.getCharCode());
41084 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
41092 * Ext JS Library 1.1.1
41093 * Copyright(c) 2006-2007, Ext JS, LLC.
41095 * Originally Released Under LGPL - original licence link has changed is not relivant.
41098 * <script type="text/javascript">
41102 * @class Roo.form.Hidden
41103 * @extends Roo.form.TextField
41104 * Simple Hidden element used on forms
41106 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
41109 * Creates a new Hidden form element.
41110 * @param {Object} config Configuration options
41115 // easy hidden field...
41116 Roo.form.Hidden = function(config){
41117 Roo.form.Hidden.superclass.constructor.call(this, config);
41120 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
41122 inputType: 'hidden',
41125 labelSeparator: '',
41127 itemCls : 'x-form-item-display-none'
41135 * Ext JS Library 1.1.1
41136 * Copyright(c) 2006-2007, Ext JS, LLC.
41138 * Originally Released Under LGPL - original licence link has changed is not relivant.
41141 * <script type="text/javascript">
41145 * @class Roo.form.TriggerField
41146 * @extends Roo.form.TextField
41147 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
41148 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
41149 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
41150 * for which you can provide a custom implementation. For example:
41152 var trigger = new Roo.form.TriggerField();
41153 trigger.onTriggerClick = myTriggerFn;
41154 trigger.applyTo('my-field');
41157 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
41158 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
41159 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
41160 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
41162 * Create a new TriggerField.
41163 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
41164 * to the base TextField)
41166 Roo.form.TriggerField = function(config){
41167 this.mimicing = false;
41168 Roo.form.TriggerField.superclass.constructor.call(this, config);
41171 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
41173 * @cfg {String} triggerClass A CSS class to apply to the trigger
41176 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
41177 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
41179 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
41181 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
41185 /** @cfg {Boolean} grow @hide */
41186 /** @cfg {Number} growMin @hide */
41187 /** @cfg {Number} growMax @hide */
41193 autoSize: Roo.emptyFn,
41197 deferHeight : true,
41200 actionMode : 'wrap',
41202 onResize : function(w, h){
41203 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
41204 if(typeof w == 'number'){
41205 var x = w - this.trigger.getWidth();
41206 this.el.setWidth(this.adjustWidth('input', x));
41207 this.trigger.setStyle('left', x+'px');
41212 adjustSize : Roo.BoxComponent.prototype.adjustSize,
41215 getResizeEl : function(){
41220 getPositionEl : function(){
41225 alignErrorIcon : function(){
41226 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
41230 onRender : function(ct, position){
41231 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
41232 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
41233 this.trigger = this.wrap.createChild(this.triggerConfig ||
41234 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
41235 if(this.hideTrigger){
41236 this.trigger.setDisplayed(false);
41238 this.initTrigger();
41240 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
41245 initTrigger : function(){
41246 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
41247 this.trigger.addClassOnOver('x-form-trigger-over');
41248 this.trigger.addClassOnClick('x-form-trigger-click');
41252 onDestroy : function(){
41254 this.trigger.removeAllListeners();
41255 this.trigger.remove();
41258 this.wrap.remove();
41260 Roo.form.TriggerField.superclass.onDestroy.call(this);
41264 onFocus : function(){
41265 Roo.form.TriggerField.superclass.onFocus.call(this);
41266 if(!this.mimicing){
41267 this.wrap.addClass('x-trigger-wrap-focus');
41268 this.mimicing = true;
41269 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
41270 if(this.monitorTab){
41271 this.el.on("keydown", this.checkTab, this);
41277 checkTab : function(e){
41278 if(e.getKey() == e.TAB){
41279 this.triggerBlur();
41284 onBlur : function(){
41289 mimicBlur : function(e, t){
41290 if(!this.wrap.contains(t) && this.validateBlur()){
41291 this.triggerBlur();
41296 triggerBlur : function(){
41297 this.mimicing = false;
41298 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
41299 if(this.monitorTab){
41300 this.el.un("keydown", this.checkTab, this);
41302 this.wrap.removeClass('x-trigger-wrap-focus');
41303 Roo.form.TriggerField.superclass.onBlur.call(this);
41307 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
41308 validateBlur : function(e, t){
41313 onDisable : function(){
41314 Roo.form.TriggerField.superclass.onDisable.call(this);
41316 this.wrap.addClass('x-item-disabled');
41321 onEnable : function(){
41322 Roo.form.TriggerField.superclass.onEnable.call(this);
41324 this.wrap.removeClass('x-item-disabled');
41329 onShow : function(){
41330 var ae = this.getActionEl();
41333 ae.dom.style.display = '';
41334 ae.dom.style.visibility = 'visible';
41340 onHide : function(){
41341 var ae = this.getActionEl();
41342 ae.dom.style.display = 'none';
41346 * The function that should handle the trigger's click event. This method does nothing by default until overridden
41347 * by an implementing function.
41349 * @param {EventObject} e
41351 onTriggerClick : Roo.emptyFn
41354 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
41355 // to be extended by an implementing class. For an example of implementing this class, see the custom
41356 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
41357 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
41358 initComponent : function(){
41359 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
41361 this.triggerConfig = {
41362 tag:'span', cls:'x-form-twin-triggers', cn:[
41363 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
41364 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
41368 getTrigger : function(index){
41369 return this.triggers[index];
41372 initTrigger : function(){
41373 var ts = this.trigger.select('.x-form-trigger', true);
41374 this.wrap.setStyle('overflow', 'hidden');
41375 var triggerField = this;
41376 ts.each(function(t, all, index){
41377 t.hide = function(){
41378 var w = triggerField.wrap.getWidth();
41379 this.dom.style.display = 'none';
41380 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
41382 t.show = function(){
41383 var w = triggerField.wrap.getWidth();
41384 this.dom.style.display = '';
41385 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
41387 var triggerIndex = 'Trigger'+(index+1);
41389 if(this['hide'+triggerIndex]){
41390 t.dom.style.display = 'none';
41392 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
41393 t.addClassOnOver('x-form-trigger-over');
41394 t.addClassOnClick('x-form-trigger-click');
41396 this.triggers = ts.elements;
41399 onTrigger1Click : Roo.emptyFn,
41400 onTrigger2Click : Roo.emptyFn
41403 * Ext JS Library 1.1.1
41404 * Copyright(c) 2006-2007, Ext JS, LLC.
41406 * Originally Released Under LGPL - original licence link has changed is not relivant.
41409 * <script type="text/javascript">
41413 * @class Roo.form.TextArea
41414 * @extends Roo.form.TextField
41415 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
41416 * support for auto-sizing.
41418 * Creates a new TextArea
41419 * @param {Object} config Configuration options
41421 Roo.form.TextArea = function(config){
41422 Roo.form.TextArea.superclass.constructor.call(this, config);
41423 // these are provided exchanges for backwards compat
41424 // minHeight/maxHeight were replaced by growMin/growMax to be
41425 // compatible with TextField growing config values
41426 if(this.minHeight !== undefined){
41427 this.growMin = this.minHeight;
41429 if(this.maxHeight !== undefined){
41430 this.growMax = this.maxHeight;
41434 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
41436 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
41440 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
41444 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
41445 * in the field (equivalent to setting overflow: hidden, defaults to false)
41447 preventScrollbars: false,
41449 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
41450 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
41454 onRender : function(ct, position){
41456 this.defaultAutoCreate = {
41458 style:"width:300px;height:60px;",
41459 autocomplete: "new-password"
41462 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
41464 this.textSizeEl = Roo.DomHelper.append(document.body, {
41465 tag: "pre", cls: "x-form-grow-sizer"
41467 if(this.preventScrollbars){
41468 this.el.setStyle("overflow", "hidden");
41470 this.el.setHeight(this.growMin);
41474 onDestroy : function(){
41475 if(this.textSizeEl){
41476 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
41478 Roo.form.TextArea.superclass.onDestroy.call(this);
41482 onKeyUp : function(e){
41483 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
41489 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
41490 * This only takes effect if grow = true, and fires the autosize event if the height changes.
41492 autoSize : function(){
41493 if(!this.grow || !this.textSizeEl){
41497 var v = el.dom.value;
41498 var ts = this.textSizeEl;
41501 ts.appendChild(document.createTextNode(v));
41504 Roo.fly(ts).setWidth(this.el.getWidth());
41506 v = "  ";
41509 v = v.replace(/\n/g, '<p> </p>');
41511 v += " \n ";
41514 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
41515 if(h != this.lastHeight){
41516 this.lastHeight = h;
41517 this.el.setHeight(h);
41518 this.fireEvent("autosize", this, h);
41523 * Ext JS Library 1.1.1
41524 * Copyright(c) 2006-2007, Ext JS, LLC.
41526 * Originally Released Under LGPL - original licence link has changed is not relivant.
41529 * <script type="text/javascript">
41534 * @class Roo.form.NumberField
41535 * @extends Roo.form.TextField
41536 * Numeric text field that provides automatic keystroke filtering and numeric validation.
41538 * Creates a new NumberField
41539 * @param {Object} config Configuration options
41541 Roo.form.NumberField = function(config){
41542 Roo.form.NumberField.superclass.constructor.call(this, config);
41545 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
41547 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
41549 fieldClass: "x-form-field x-form-num-field",
41551 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
41553 allowDecimals : true,
41555 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
41557 decimalSeparator : ".",
41559 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
41561 decimalPrecision : 2,
41563 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
41565 allowNegative : true,
41567 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
41569 minValue : Number.NEGATIVE_INFINITY,
41571 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
41573 maxValue : Number.MAX_VALUE,
41575 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
41577 minText : "The minimum value for this field is {0}",
41579 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
41581 maxText : "The maximum value for this field is {0}",
41583 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
41584 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
41586 nanText : "{0} is not a valid number",
41589 initEvents : function(){
41590 Roo.form.NumberField.superclass.initEvents.call(this);
41591 var allowed = "0123456789";
41592 if(this.allowDecimals){
41593 allowed += this.decimalSeparator;
41595 if(this.allowNegative){
41598 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41599 var keyPress = function(e){
41600 var k = e.getKey();
41601 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41604 var c = e.getCharCode();
41605 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41609 this.el.on("keypress", keyPress, this);
41613 validateValue : function(value){
41614 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
41617 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
41620 var num = this.parseValue(value);
41622 this.markInvalid(String.format(this.nanText, value));
41625 if(num < this.minValue){
41626 this.markInvalid(String.format(this.minText, this.minValue));
41629 if(num > this.maxValue){
41630 this.markInvalid(String.format(this.maxText, this.maxValue));
41636 getValue : function(){
41637 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
41641 parseValue : function(value){
41642 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41643 return isNaN(value) ? '' : value;
41647 fixPrecision : function(value){
41648 var nan = isNaN(value);
41649 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41650 return nan ? '' : value;
41652 return parseFloat(value).toFixed(this.decimalPrecision);
41655 setValue : function(v){
41656 v = this.fixPrecision(v);
41657 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
41661 decimalPrecisionFcn : function(v){
41662 return Math.floor(v);
41665 beforeBlur : function(){
41666 var v = this.parseValue(this.getRawValue());
41673 * Ext JS Library 1.1.1
41674 * Copyright(c) 2006-2007, Ext JS, LLC.
41676 * Originally Released Under LGPL - original licence link has changed is not relivant.
41679 * <script type="text/javascript">
41683 * @class Roo.form.DateField
41684 * @extends Roo.form.TriggerField
41685 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
41687 * Create a new DateField
41688 * @param {Object} config
41690 Roo.form.DateField = function(config)
41692 Roo.form.DateField.superclass.constructor.call(this, config);
41698 * Fires when a date is selected
41699 * @param {Roo.form.DateField} combo This combo box
41700 * @param {Date} date The date selected
41707 if(typeof this.minValue == "string") {
41708 this.minValue = this.parseDate(this.minValue);
41710 if(typeof this.maxValue == "string") {
41711 this.maxValue = this.parseDate(this.maxValue);
41713 this.ddMatch = null;
41714 if(this.disabledDates){
41715 var dd = this.disabledDates;
41717 for(var i = 0; i < dd.length; i++){
41719 if(i != dd.length-1) {
41723 this.ddMatch = new RegExp(re + ")");
41727 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
41729 * @cfg {String} format
41730 * The default date format string which can be overriden for localization support. The format must be
41731 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
41735 * @cfg {String} altFormats
41736 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
41737 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
41739 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
41741 * @cfg {Array} disabledDays
41742 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
41744 disabledDays : null,
41746 * @cfg {String} disabledDaysText
41747 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
41749 disabledDaysText : "Disabled",
41751 * @cfg {Array} disabledDates
41752 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
41753 * expression so they are very powerful. Some examples:
41755 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
41756 * <li>["03/08", "09/16"] would disable those days for every year</li>
41757 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
41758 * <li>["03/../2006"] would disable every day in March 2006</li>
41759 * <li>["^03"] would disable every day in every March</li>
41761 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
41762 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
41764 disabledDates : null,
41766 * @cfg {String} disabledDatesText
41767 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
41769 disabledDatesText : "Disabled",
41773 * @cfg {Date/String} zeroValue
41774 * if the date is less that this number, then the field is rendered as empty
41777 zeroValue : '1800-01-01',
41781 * @cfg {Date/String} minValue
41782 * The minimum allowed date. Can be either a Javascript date object or a string date in a
41783 * valid format (defaults to null).
41787 * @cfg {Date/String} maxValue
41788 * The maximum allowed date. Can be either a Javascript date object or a string date in a
41789 * valid format (defaults to null).
41793 * @cfg {String} minText
41794 * The error text to display when the date in the cell is before minValue (defaults to
41795 * 'The date in this field must be after {minValue}').
41797 minText : "The date in this field must be equal to or after {0}",
41799 * @cfg {String} maxText
41800 * The error text to display when the date in the cell is after maxValue (defaults to
41801 * 'The date in this field must be before {maxValue}').
41803 maxText : "The date in this field must be equal to or before {0}",
41805 * @cfg {String} invalidText
41806 * The error text to display when the date in the field is invalid (defaults to
41807 * '{value} is not a valid date - it must be in the format {format}').
41809 invalidText : "{0} is not a valid date - it must be in the format {1}",
41811 * @cfg {String} triggerClass
41812 * An additional CSS class used to style the trigger button. The trigger will always get the
41813 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
41814 * which displays a calendar icon).
41816 triggerClass : 'x-form-date-trigger',
41820 * @cfg {Boolean} useIso
41821 * if enabled, then the date field will use a hidden field to store the
41822 * real value as iso formated date. default (false)
41826 * @cfg {String/Object} autoCreate
41827 * A DomHelper element spec, or true for a default element spec (defaults to
41828 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
41831 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
41834 hiddenField: false,
41836 onRender : function(ct, position)
41838 Roo.form.DateField.superclass.onRender.call(this, ct, position);
41840 //this.el.dom.removeAttribute('name');
41841 Roo.log("Changing name?");
41842 this.el.dom.setAttribute('name', this.name + '____hidden___' );
41843 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
41845 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
41846 // prevent input submission
41847 this.hiddenName = this.name;
41854 validateValue : function(value)
41856 value = this.formatDate(value);
41857 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
41858 Roo.log('super failed');
41861 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
41864 var svalue = value;
41865 value = this.parseDate(value);
41867 Roo.log('parse date failed' + svalue);
41868 this.markInvalid(String.format(this.invalidText, svalue, this.format));
41871 var time = value.getTime();
41872 if(this.minValue && time < this.minValue.getTime()){
41873 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
41876 if(this.maxValue && time > this.maxValue.getTime()){
41877 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
41880 if(this.disabledDays){
41881 var day = value.getDay();
41882 for(var i = 0; i < this.disabledDays.length; i++) {
41883 if(day === this.disabledDays[i]){
41884 this.markInvalid(this.disabledDaysText);
41889 var fvalue = this.formatDate(value);
41890 if(this.ddMatch && this.ddMatch.test(fvalue)){
41891 this.markInvalid(String.format(this.disabledDatesText, fvalue));
41898 // Provides logic to override the default TriggerField.validateBlur which just returns true
41899 validateBlur : function(){
41900 return !this.menu || !this.menu.isVisible();
41903 getName: function()
41905 // returns hidden if it's set..
41906 if (!this.rendered) {return ''};
41907 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
41912 * Returns the current date value of the date field.
41913 * @return {Date} The date value
41915 getValue : function(){
41917 return this.hiddenField ?
41918 this.hiddenField.value :
41919 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
41923 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
41924 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
41925 * (the default format used is "m/d/y").
41928 //All of these calls set the same date value (May 4, 2006)
41930 //Pass a date object:
41931 var dt = new Date('5/4/06');
41932 dateField.setValue(dt);
41934 //Pass a date string (default format):
41935 dateField.setValue('5/4/06');
41937 //Pass a date string (custom format):
41938 dateField.format = 'Y-m-d';
41939 dateField.setValue('2006-5-4');
41941 * @param {String/Date} date The date or valid date string
41943 setValue : function(date){
41944 if (this.hiddenField) {
41945 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
41947 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
41948 // make sure the value field is always stored as a date..
41949 this.value = this.parseDate(date);
41955 parseDate : function(value){
41957 if (value instanceof Date) {
41958 if (value < Date.parseDate(this.zeroValue, 'Y-m-d') ) {
41965 if(!value || value instanceof Date){
41968 var v = Date.parseDate(value, this.format);
41969 if (!v && this.useIso) {
41970 v = Date.parseDate(value, 'Y-m-d');
41972 if(!v && this.altFormats){
41973 if(!this.altFormatsArray){
41974 this.altFormatsArray = this.altFormats.split("|");
41976 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
41977 v = Date.parseDate(value, this.altFormatsArray[i]);
41980 if (v < Date.parseDate(this.zeroValue, 'Y-m-d') ) {
41987 formatDate : function(date, fmt){
41988 return (!date || !(date instanceof Date)) ?
41989 date : date.dateFormat(fmt || this.format);
41994 select: function(m, d){
41997 this.fireEvent('select', this, d);
41999 show : function(){ // retain focus styling
42003 this.focus.defer(10, this);
42004 var ml = this.menuListeners;
42005 this.menu.un("select", ml.select, this);
42006 this.menu.un("show", ml.show, this);
42007 this.menu.un("hide", ml.hide, this);
42012 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
42013 onTriggerClick : function(){
42017 if(this.menu == null){
42018 this.menu = new Roo.menu.DateMenu();
42020 Roo.apply(this.menu.picker, {
42021 showClear: this.allowBlank,
42022 minDate : this.minValue,
42023 maxDate : this.maxValue,
42024 disabledDatesRE : this.ddMatch,
42025 disabledDatesText : this.disabledDatesText,
42026 disabledDays : this.disabledDays,
42027 disabledDaysText : this.disabledDaysText,
42028 format : this.useIso ? 'Y-m-d' : this.format,
42029 minText : String.format(this.minText, this.formatDate(this.minValue)),
42030 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
42032 this.menu.on(Roo.apply({}, this.menuListeners, {
42035 this.menu.picker.setValue(this.getValue() || new Date());
42036 this.menu.show(this.el, "tl-bl?");
42039 beforeBlur : function(){
42040 var v = this.parseDate(this.getRawValue());
42050 isDirty : function() {
42051 if(this.disabled) {
42055 if(typeof(this.startValue) === 'undefined'){
42059 return String(this.getValue()) !== String(this.startValue);
42063 cleanLeadingSpace : function(e)
42070 * Ext JS Library 1.1.1
42071 * Copyright(c) 2006-2007, Ext JS, LLC.
42073 * Originally Released Under LGPL - original licence link has changed is not relivant.
42076 * <script type="text/javascript">
42080 * @class Roo.form.MonthField
42081 * @extends Roo.form.TriggerField
42082 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
42084 * Create a new MonthField
42085 * @param {Object} config
42087 Roo.form.MonthField = function(config){
42089 Roo.form.MonthField.superclass.constructor.call(this, config);
42095 * Fires when a date is selected
42096 * @param {Roo.form.MonthFieeld} combo This combo box
42097 * @param {Date} date The date selected
42104 if(typeof this.minValue == "string") {
42105 this.minValue = this.parseDate(this.minValue);
42107 if(typeof this.maxValue == "string") {
42108 this.maxValue = this.parseDate(this.maxValue);
42110 this.ddMatch = null;
42111 if(this.disabledDates){
42112 var dd = this.disabledDates;
42114 for(var i = 0; i < dd.length; i++){
42116 if(i != dd.length-1) {
42120 this.ddMatch = new RegExp(re + ")");
42124 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
42126 * @cfg {String} format
42127 * The default date format string which can be overriden for localization support. The format must be
42128 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
42132 * @cfg {String} altFormats
42133 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
42134 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
42136 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
42138 * @cfg {Array} disabledDays
42139 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
42141 disabledDays : [0,1,2,3,4,5,6],
42143 * @cfg {String} disabledDaysText
42144 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
42146 disabledDaysText : "Disabled",
42148 * @cfg {Array} disabledDates
42149 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
42150 * expression so they are very powerful. Some examples:
42152 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
42153 * <li>["03/08", "09/16"] would disable those days for every year</li>
42154 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
42155 * <li>["03/../2006"] would disable every day in March 2006</li>
42156 * <li>["^03"] would disable every day in every March</li>
42158 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
42159 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
42161 disabledDates : null,
42163 * @cfg {String} disabledDatesText
42164 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
42166 disabledDatesText : "Disabled",
42168 * @cfg {Date/String} minValue
42169 * The minimum allowed date. Can be either a Javascript date object or a string date in a
42170 * valid format (defaults to null).
42174 * @cfg {Date/String} maxValue
42175 * The maximum allowed date. Can be either a Javascript date object or a string date in a
42176 * valid format (defaults to null).
42180 * @cfg {String} minText
42181 * The error text to display when the date in the cell is before minValue (defaults to
42182 * 'The date in this field must be after {minValue}').
42184 minText : "The date in this field must be equal to or after {0}",
42186 * @cfg {String} maxTextf
42187 * The error text to display when the date in the cell is after maxValue (defaults to
42188 * 'The date in this field must be before {maxValue}').
42190 maxText : "The date in this field must be equal to or before {0}",
42192 * @cfg {String} invalidText
42193 * The error text to display when the date in the field is invalid (defaults to
42194 * '{value} is not a valid date - it must be in the format {format}').
42196 invalidText : "{0} is not a valid date - it must be in the format {1}",
42198 * @cfg {String} triggerClass
42199 * An additional CSS class used to style the trigger button. The trigger will always get the
42200 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
42201 * which displays a calendar icon).
42203 triggerClass : 'x-form-date-trigger',
42207 * @cfg {Boolean} useIso
42208 * if enabled, then the date field will use a hidden field to store the
42209 * real value as iso formated date. default (true)
42213 * @cfg {String/Object} autoCreate
42214 * A DomHelper element spec, or true for a default element spec (defaults to
42215 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
42218 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
42221 hiddenField: false,
42223 hideMonthPicker : false,
42225 onRender : function(ct, position)
42227 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
42229 this.el.dom.removeAttribute('name');
42230 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
42232 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
42233 // prevent input submission
42234 this.hiddenName = this.name;
42241 validateValue : function(value)
42243 value = this.formatDate(value);
42244 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
42247 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
42250 var svalue = value;
42251 value = this.parseDate(value);
42253 this.markInvalid(String.format(this.invalidText, svalue, this.format));
42256 var time = value.getTime();
42257 if(this.minValue && time < this.minValue.getTime()){
42258 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
42261 if(this.maxValue && time > this.maxValue.getTime()){
42262 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
42265 /*if(this.disabledDays){
42266 var day = value.getDay();
42267 for(var i = 0; i < this.disabledDays.length; i++) {
42268 if(day === this.disabledDays[i]){
42269 this.markInvalid(this.disabledDaysText);
42275 var fvalue = this.formatDate(value);
42276 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
42277 this.markInvalid(String.format(this.disabledDatesText, fvalue));
42285 // Provides logic to override the default TriggerField.validateBlur which just returns true
42286 validateBlur : function(){
42287 return !this.menu || !this.menu.isVisible();
42291 * Returns the current date value of the date field.
42292 * @return {Date} The date value
42294 getValue : function(){
42298 return this.hiddenField ?
42299 this.hiddenField.value :
42300 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
42304 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
42305 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
42306 * (the default format used is "m/d/y").
42309 //All of these calls set the same date value (May 4, 2006)
42311 //Pass a date object:
42312 var dt = new Date('5/4/06');
42313 monthField.setValue(dt);
42315 //Pass a date string (default format):
42316 monthField.setValue('5/4/06');
42318 //Pass a date string (custom format):
42319 monthField.format = 'Y-m-d';
42320 monthField.setValue('2006-5-4');
42322 * @param {String/Date} date The date or valid date string
42324 setValue : function(date){
42325 Roo.log('month setValue' + date);
42326 // can only be first of month..
42328 var val = this.parseDate(date);
42330 if (this.hiddenField) {
42331 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
42333 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
42334 this.value = this.parseDate(date);
42338 parseDate : function(value){
42339 if(!value || value instanceof Date){
42340 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
42343 var v = Date.parseDate(value, this.format);
42344 if (!v && this.useIso) {
42345 v = Date.parseDate(value, 'Y-m-d');
42349 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
42353 if(!v && this.altFormats){
42354 if(!this.altFormatsArray){
42355 this.altFormatsArray = this.altFormats.split("|");
42357 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
42358 v = Date.parseDate(value, this.altFormatsArray[i]);
42365 formatDate : function(date, fmt){
42366 return (!date || !(date instanceof Date)) ?
42367 date : date.dateFormat(fmt || this.format);
42372 select: function(m, d){
42374 this.fireEvent('select', this, d);
42376 show : function(){ // retain focus styling
42380 this.focus.defer(10, this);
42381 var ml = this.menuListeners;
42382 this.menu.un("select", ml.select, this);
42383 this.menu.un("show", ml.show, this);
42384 this.menu.un("hide", ml.hide, this);
42388 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
42389 onTriggerClick : function(){
42393 if(this.menu == null){
42394 this.menu = new Roo.menu.DateMenu();
42398 Roo.apply(this.menu.picker, {
42400 showClear: this.allowBlank,
42401 minDate : this.minValue,
42402 maxDate : this.maxValue,
42403 disabledDatesRE : this.ddMatch,
42404 disabledDatesText : this.disabledDatesText,
42406 format : this.useIso ? 'Y-m-d' : this.format,
42407 minText : String.format(this.minText, this.formatDate(this.minValue)),
42408 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
42411 this.menu.on(Roo.apply({}, this.menuListeners, {
42419 // hide month picker get's called when we called by 'before hide';
42421 var ignorehide = true;
42422 p.hideMonthPicker = function(disableAnim){
42426 if(this.monthPicker){
42427 Roo.log("hideMonthPicker called");
42428 if(disableAnim === true){
42429 this.monthPicker.hide();
42431 this.monthPicker.slideOut('t', {duration:.2});
42432 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
42433 p.fireEvent("select", this, this.value);
42439 Roo.log('picker set value');
42440 Roo.log(this.getValue());
42441 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
42442 m.show(this.el, 'tl-bl?');
42443 ignorehide = false;
42444 // this will trigger hideMonthPicker..
42447 // hidden the day picker
42448 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
42454 p.showMonthPicker.defer(100, p);
42460 beforeBlur : function(){
42461 var v = this.parseDate(this.getRawValue());
42467 /** @cfg {Boolean} grow @hide */
42468 /** @cfg {Number} growMin @hide */
42469 /** @cfg {Number} growMax @hide */
42476 * Ext JS Library 1.1.1
42477 * Copyright(c) 2006-2007, Ext JS, LLC.
42479 * Originally Released Under LGPL - original licence link has changed is not relivant.
42482 * <script type="text/javascript">
42487 * @class Roo.form.ComboBox
42488 * @extends Roo.form.TriggerField
42489 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
42491 * Create a new ComboBox.
42492 * @param {Object} config Configuration options
42494 Roo.form.ComboBox = function(config){
42495 Roo.form.ComboBox.superclass.constructor.call(this, config);
42499 * Fires when the dropdown list is expanded
42500 * @param {Roo.form.ComboBox} combo This combo box
42505 * Fires when the dropdown list is collapsed
42506 * @param {Roo.form.ComboBox} combo This combo box
42510 * @event beforeselect
42511 * Fires before a list item is selected. Return false to cancel the selection.
42512 * @param {Roo.form.ComboBox} combo This combo box
42513 * @param {Roo.data.Record} record The data record returned from the underlying store
42514 * @param {Number} index The index of the selected item in the dropdown list
42516 'beforeselect' : true,
42519 * Fires when a list item is selected
42520 * @param {Roo.form.ComboBox} combo This combo box
42521 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
42522 * @param {Number} index The index of the selected item in the dropdown list
42526 * @event beforequery
42527 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
42528 * The event object passed has these properties:
42529 * @param {Roo.form.ComboBox} combo This combo box
42530 * @param {String} query The query
42531 * @param {Boolean} forceAll true to force "all" query
42532 * @param {Boolean} cancel true to cancel the query
42533 * @param {Object} e The query event object
42535 'beforequery': true,
42538 * Fires when the 'add' icon is pressed (add a listener to enable add button)
42539 * @param {Roo.form.ComboBox} combo This combo box
42544 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
42545 * @param {Roo.form.ComboBox} combo This combo box
42546 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
42552 if(this.transform){
42553 this.allowDomMove = false;
42554 var s = Roo.getDom(this.transform);
42555 if(!this.hiddenName){
42556 this.hiddenName = s.name;
42559 this.mode = 'local';
42560 var d = [], opts = s.options;
42561 for(var i = 0, len = opts.length;i < len; i++){
42563 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
42565 this.value = value;
42567 d.push([value, o.text]);
42569 this.store = new Roo.data.SimpleStore({
42571 fields: ['value', 'text'],
42574 this.valueField = 'value';
42575 this.displayField = 'text';
42577 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
42578 if(!this.lazyRender){
42579 this.target = true;
42580 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
42581 s.parentNode.removeChild(s); // remove it
42582 this.render(this.el.parentNode);
42584 s.parentNode.removeChild(s); // remove it
42589 this.store = Roo.factory(this.store, Roo.data);
42592 this.selectedIndex = -1;
42593 if(this.mode == 'local'){
42594 if(config.queryDelay === undefined){
42595 this.queryDelay = 10;
42597 if(config.minChars === undefined){
42603 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
42605 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
42608 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
42609 * rendering into an Roo.Editor, defaults to false)
42612 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
42613 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
42616 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
42619 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
42620 * the dropdown list (defaults to undefined, with no header element)
42624 * @cfg {String/Roo.Template} tpl The template to use to render the output
42628 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
42630 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
42632 listWidth: undefined,
42634 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
42635 * mode = 'remote' or 'text' if mode = 'local')
42637 displayField: undefined,
42639 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
42640 * mode = 'remote' or 'value' if mode = 'local').
42641 * Note: use of a valueField requires the user make a selection
42642 * in order for a value to be mapped.
42644 valueField: undefined,
42648 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
42649 * field's data value (defaults to the underlying DOM element's name)
42651 hiddenName: undefined,
42653 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
42657 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
42659 selectedClass: 'x-combo-selected',
42661 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
42662 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
42663 * which displays a downward arrow icon).
42665 triggerClass : 'x-form-arrow-trigger',
42667 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
42671 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
42672 * anchor positions (defaults to 'tl-bl')
42674 listAlign: 'tl-bl?',
42676 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
42680 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
42681 * query specified by the allQuery config option (defaults to 'query')
42683 triggerAction: 'query',
42685 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
42686 * (defaults to 4, does not apply if editable = false)
42690 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
42691 * delay (typeAheadDelay) if it matches a known value (defaults to false)
42695 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
42696 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
42700 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
42701 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
42705 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
42706 * when editable = true (defaults to false)
42708 selectOnFocus:false,
42710 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
42712 queryParam: 'query',
42714 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
42715 * when mode = 'remote' (defaults to 'Loading...')
42717 loadingText: 'Loading...',
42719 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
42723 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
42727 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
42728 * traditional select (defaults to true)
42732 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
42736 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
42740 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
42741 * listWidth has a higher value)
42745 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
42746 * allow the user to set arbitrary text into the field (defaults to false)
42748 forceSelection:false,
42750 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
42751 * if typeAhead = true (defaults to 250)
42753 typeAheadDelay : 250,
42755 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
42756 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
42758 valueNotFoundText : undefined,
42760 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
42762 blockFocus : false,
42765 * @cfg {Boolean} disableClear Disable showing of clear button.
42767 disableClear : false,
42769 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
42771 alwaysQuery : false,
42777 // element that contains real text value.. (when hidden is used..)
42780 onRender : function(ct, position)
42782 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
42784 if(this.hiddenName){
42785 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
42787 this.hiddenField.value =
42788 this.hiddenValue !== undefined ? this.hiddenValue :
42789 this.value !== undefined ? this.value : '';
42791 // prevent input submission
42792 this.el.dom.removeAttribute('name');
42798 this.el.dom.setAttribute('autocomplete', 'off');
42801 var cls = 'x-combo-list';
42803 this.list = new Roo.Layer({
42804 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
42807 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
42808 this.list.setWidth(lw);
42809 this.list.swallowEvent('mousewheel');
42810 this.assetHeight = 0;
42813 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
42814 this.assetHeight += this.header.getHeight();
42817 this.innerList = this.list.createChild({cls:cls+'-inner'});
42818 this.innerList.on('mouseover', this.onViewOver, this);
42819 this.innerList.on('mousemove', this.onViewMove, this);
42820 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42822 if(this.allowBlank && !this.pageSize && !this.disableClear){
42823 this.footer = this.list.createChild({cls:cls+'-ft'});
42824 this.pageTb = new Roo.Toolbar(this.footer);
42828 this.footer = this.list.createChild({cls:cls+'-ft'});
42829 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
42830 {pageSize: this.pageSize});
42834 if (this.pageTb && this.allowBlank && !this.disableClear) {
42836 this.pageTb.add(new Roo.Toolbar.Fill(), {
42837 cls: 'x-btn-icon x-btn-clear',
42839 handler: function()
42842 _this.clearValue();
42843 _this.onSelect(false, -1);
42848 this.assetHeight += this.footer.getHeight();
42853 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
42856 this.view = new Roo.View(this.innerList, this.tpl, {
42859 selectedClass: this.selectedClass
42862 this.view.on('click', this.onViewClick, this);
42864 this.store.on('beforeload', this.onBeforeLoad, this);
42865 this.store.on('load', this.onLoad, this);
42866 this.store.on('loadexception', this.onLoadException, this);
42868 if(this.resizable){
42869 this.resizer = new Roo.Resizable(this.list, {
42870 pinned:true, handles:'se'
42872 this.resizer.on('resize', function(r, w, h){
42873 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
42874 this.listWidth = w;
42875 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
42876 this.restrictHeight();
42878 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
42880 if(!this.editable){
42881 this.editable = true;
42882 this.setEditable(false);
42886 if (typeof(this.events.add.listeners) != 'undefined') {
42888 this.addicon = this.wrap.createChild(
42889 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
42891 this.addicon.on('click', function(e) {
42892 this.fireEvent('add', this);
42895 if (typeof(this.events.edit.listeners) != 'undefined') {
42897 this.editicon = this.wrap.createChild(
42898 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
42899 if (this.addicon) {
42900 this.editicon.setStyle('margin-left', '40px');
42902 this.editicon.on('click', function(e) {
42904 // we fire even if inothing is selected..
42905 this.fireEvent('edit', this, this.lastData );
42915 initEvents : function(){
42916 Roo.form.ComboBox.superclass.initEvents.call(this);
42918 this.keyNav = new Roo.KeyNav(this.el, {
42919 "up" : function(e){
42920 this.inKeyMode = true;
42924 "down" : function(e){
42925 if(!this.isExpanded()){
42926 this.onTriggerClick();
42928 this.inKeyMode = true;
42933 "enter" : function(e){
42934 this.onViewClick();
42938 "esc" : function(e){
42942 "tab" : function(e){
42943 this.onViewClick(false);
42944 this.fireEvent("specialkey", this, e);
42950 doRelay : function(foo, bar, hname){
42951 if(hname == 'down' || this.scope.isExpanded()){
42952 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
42959 this.queryDelay = Math.max(this.queryDelay || 10,
42960 this.mode == 'local' ? 10 : 250);
42961 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
42962 if(this.typeAhead){
42963 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
42965 if(this.editable !== false){
42966 this.el.on("keyup", this.onKeyUp, this);
42968 if(this.forceSelection){
42969 this.on('blur', this.doForce, this);
42973 onDestroy : function(){
42975 this.view.setStore(null);
42976 this.view.el.removeAllListeners();
42977 this.view.el.remove();
42978 this.view.purgeListeners();
42981 this.list.destroy();
42984 this.store.un('beforeload', this.onBeforeLoad, this);
42985 this.store.un('load', this.onLoad, this);
42986 this.store.un('loadexception', this.onLoadException, this);
42988 Roo.form.ComboBox.superclass.onDestroy.call(this);
42992 fireKey : function(e){
42993 if(e.isNavKeyPress() && !this.list.isVisible()){
42994 this.fireEvent("specialkey", this, e);
42999 onResize: function(w, h){
43000 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
43002 if(typeof w != 'number'){
43003 // we do not handle it!?!?
43006 var tw = this.trigger.getWidth();
43007 tw += this.addicon ? this.addicon.getWidth() : 0;
43008 tw += this.editicon ? this.editicon.getWidth() : 0;
43010 this.el.setWidth( this.adjustWidth('input', x));
43012 this.trigger.setStyle('left', x+'px');
43014 if(this.list && this.listWidth === undefined){
43015 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
43016 this.list.setWidth(lw);
43017 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
43025 * Allow or prevent the user from directly editing the field text. If false is passed,
43026 * the user will only be able to select from the items defined in the dropdown list. This method
43027 * is the runtime equivalent of setting the 'editable' config option at config time.
43028 * @param {Boolean} value True to allow the user to directly edit the field text
43030 setEditable : function(value){
43031 if(value == this.editable){
43034 this.editable = value;
43036 this.el.dom.setAttribute('readOnly', true);
43037 this.el.on('mousedown', this.onTriggerClick, this);
43038 this.el.addClass('x-combo-noedit');
43040 this.el.dom.setAttribute('readOnly', false);
43041 this.el.un('mousedown', this.onTriggerClick, this);
43042 this.el.removeClass('x-combo-noedit');
43047 onBeforeLoad : function(){
43048 if(!this.hasFocus){
43051 this.innerList.update(this.loadingText ?
43052 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
43053 this.restrictHeight();
43054 this.selectedIndex = -1;
43058 onLoad : function(){
43059 if(!this.hasFocus){
43062 if(this.store.getCount() > 0){
43064 this.restrictHeight();
43065 if(this.lastQuery == this.allQuery){
43067 this.el.dom.select();
43069 if(!this.selectByValue(this.value, true)){
43070 this.select(0, true);
43074 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
43075 this.taTask.delay(this.typeAheadDelay);
43079 this.onEmptyResults();
43084 onLoadException : function()
43087 Roo.log(this.store.reader.jsonData);
43088 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
43089 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
43095 onTypeAhead : function(){
43096 if(this.store.getCount() > 0){
43097 var r = this.store.getAt(0);
43098 var newValue = r.data[this.displayField];
43099 var len = newValue.length;
43100 var selStart = this.getRawValue().length;
43101 if(selStart != len){
43102 this.setRawValue(newValue);
43103 this.selectText(selStart, newValue.length);
43109 onSelect : function(record, index){
43110 if(this.fireEvent('beforeselect', this, record, index) !== false){
43111 this.setFromData(index > -1 ? record.data : false);
43113 this.fireEvent('select', this, record, index);
43118 * Returns the currently selected field value or empty string if no value is set.
43119 * @return {String} value The selected value
43121 getValue : function(){
43122 if(this.valueField){
43123 return typeof this.value != 'undefined' ? this.value : '';
43125 return Roo.form.ComboBox.superclass.getValue.call(this);
43129 * Clears any text/value currently set in the field
43131 clearValue : function(){
43132 if(this.hiddenField){
43133 this.hiddenField.value = '';
43136 this.setRawValue('');
43137 this.lastSelectionText = '';
43142 * Sets the specified value into the field. If the value finds a match, the corresponding record text
43143 * will be displayed in the field. If the value does not match the data value of an existing item,
43144 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
43145 * Otherwise the field will be blank (although the value will still be set).
43146 * @param {String} value The value to match
43148 setValue : function(v){
43150 if(this.valueField){
43151 var r = this.findRecord(this.valueField, v);
43153 text = r.data[this.displayField];
43154 }else if(this.valueNotFoundText !== undefined){
43155 text = this.valueNotFoundText;
43158 this.lastSelectionText = text;
43159 if(this.hiddenField){
43160 this.hiddenField.value = v;
43162 Roo.form.ComboBox.superclass.setValue.call(this, text);
43166 * @property {Object} the last set data for the element
43171 * Sets the value of the field based on a object which is related to the record format for the store.
43172 * @param {Object} value the value to set as. or false on reset?
43174 setFromData : function(o){
43175 var dv = ''; // display value
43176 var vv = ''; // value value..
43178 if (this.displayField) {
43179 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
43181 // this is an error condition!!!
43182 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
43185 if(this.valueField){
43186 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
43188 if(this.hiddenField){
43189 this.hiddenField.value = vv;
43191 this.lastSelectionText = dv;
43192 Roo.form.ComboBox.superclass.setValue.call(this, dv);
43196 // no hidden field.. - we store the value in 'value', but still display
43197 // display field!!!!
43198 this.lastSelectionText = dv;
43199 Roo.form.ComboBox.superclass.setValue.call(this, dv);
43205 reset : function(){
43206 // overridden so that last data is reset..
43207 this.setValue(this.resetValue);
43208 this.originalValue = this.getValue();
43209 this.clearInvalid();
43210 this.lastData = false;
43212 this.view.clearSelections();
43216 findRecord : function(prop, value){
43218 if(this.store.getCount() > 0){
43219 this.store.each(function(r){
43220 if(r.data[prop] == value){
43230 getName: function()
43232 // returns hidden if it's set..
43233 if (!this.rendered) {return ''};
43234 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
43238 onViewMove : function(e, t){
43239 this.inKeyMode = false;
43243 onViewOver : function(e, t){
43244 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
43247 var item = this.view.findItemFromChild(t);
43249 var index = this.view.indexOf(item);
43250 this.select(index, false);
43255 onViewClick : function(doFocus)
43257 var index = this.view.getSelectedIndexes()[0];
43258 var r = this.store.getAt(index);
43260 this.onSelect(r, index);
43262 if(doFocus !== false && !this.blockFocus){
43268 restrictHeight : function(){
43269 this.innerList.dom.style.height = '';
43270 var inner = this.innerList.dom;
43271 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
43272 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
43273 this.list.beginUpdate();
43274 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
43275 this.list.alignTo(this.el, this.listAlign);
43276 this.list.endUpdate();
43280 onEmptyResults : function(){
43285 * Returns true if the dropdown list is expanded, else false.
43287 isExpanded : function(){
43288 return this.list.isVisible();
43292 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
43293 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
43294 * @param {String} value The data value of the item to select
43295 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
43296 * selected item if it is not currently in view (defaults to true)
43297 * @return {Boolean} True if the value matched an item in the list, else false
43299 selectByValue : function(v, scrollIntoView){
43300 if(v !== undefined && v !== null){
43301 var r = this.findRecord(this.valueField || this.displayField, v);
43303 this.select(this.store.indexOf(r), scrollIntoView);
43311 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
43312 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
43313 * @param {Number} index The zero-based index of the list item to select
43314 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
43315 * selected item if it is not currently in view (defaults to true)
43317 select : function(index, scrollIntoView){
43318 this.selectedIndex = index;
43319 this.view.select(index);
43320 if(scrollIntoView !== false){
43321 var el = this.view.getNode(index);
43323 this.innerList.scrollChildIntoView(el, false);
43329 selectNext : function(){
43330 var ct = this.store.getCount();
43332 if(this.selectedIndex == -1){
43334 }else if(this.selectedIndex < ct-1){
43335 this.select(this.selectedIndex+1);
43341 selectPrev : function(){
43342 var ct = this.store.getCount();
43344 if(this.selectedIndex == -1){
43346 }else if(this.selectedIndex != 0){
43347 this.select(this.selectedIndex-1);
43353 onKeyUp : function(e){
43354 if(this.editable !== false && !e.isSpecialKey()){
43355 this.lastKey = e.getKey();
43356 this.dqTask.delay(this.queryDelay);
43361 validateBlur : function(){
43362 return !this.list || !this.list.isVisible();
43366 initQuery : function(){
43367 this.doQuery(this.getRawValue());
43371 doForce : function(){
43372 if(this.el.dom.value.length > 0){
43373 this.el.dom.value =
43374 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
43380 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
43381 * query allowing the query action to be canceled if needed.
43382 * @param {String} query The SQL query to execute
43383 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
43384 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
43385 * saved in the current store (defaults to false)
43387 doQuery : function(q, forceAll){
43388 if(q === undefined || q === null){
43393 forceAll: forceAll,
43397 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
43401 forceAll = qe.forceAll;
43402 if(forceAll === true || (q.length >= this.minChars)){
43403 if(this.lastQuery != q || this.alwaysQuery){
43404 this.lastQuery = q;
43405 if(this.mode == 'local'){
43406 this.selectedIndex = -1;
43408 this.store.clearFilter();
43410 this.store.filter(this.displayField, q);
43414 this.store.baseParams[this.queryParam] = q;
43416 params: this.getParams(q)
43421 this.selectedIndex = -1;
43428 getParams : function(q){
43430 //p[this.queryParam] = q;
43433 p.limit = this.pageSize;
43439 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
43441 collapse : function(){
43442 if(!this.isExpanded()){
43446 Roo.get(document).un('mousedown', this.collapseIf, this);
43447 Roo.get(document).un('mousewheel', this.collapseIf, this);
43448 if (!this.editable) {
43449 Roo.get(document).un('keydown', this.listKeyPress, this);
43451 this.fireEvent('collapse', this);
43455 collapseIf : function(e){
43456 if(!e.within(this.wrap) && !e.within(this.list)){
43462 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
43464 expand : function(){
43465 if(this.isExpanded() || !this.hasFocus){
43468 this.list.alignTo(this.el, this.listAlign);
43470 Roo.get(document).on('mousedown', this.collapseIf, this);
43471 Roo.get(document).on('mousewheel', this.collapseIf, this);
43472 if (!this.editable) {
43473 Roo.get(document).on('keydown', this.listKeyPress, this);
43476 this.fireEvent('expand', this);
43480 // Implements the default empty TriggerField.onTriggerClick function
43481 onTriggerClick : function(){
43485 if(this.isExpanded()){
43487 if (!this.blockFocus) {
43492 this.hasFocus = true;
43493 if(this.triggerAction == 'all') {
43494 this.doQuery(this.allQuery, true);
43496 this.doQuery(this.getRawValue());
43498 if (!this.blockFocus) {
43503 listKeyPress : function(e)
43505 //Roo.log('listkeypress');
43506 // scroll to first matching element based on key pres..
43507 if (e.isSpecialKey()) {
43510 var k = String.fromCharCode(e.getKey()).toUpperCase();
43513 var csel = this.view.getSelectedNodes();
43514 var cselitem = false;
43516 var ix = this.view.indexOf(csel[0]);
43517 cselitem = this.store.getAt(ix);
43518 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
43524 this.store.each(function(v) {
43526 // start at existing selection.
43527 if (cselitem.id == v.id) {
43533 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
43534 match = this.store.indexOf(v);
43539 if (match === false) {
43540 return true; // no more action?
43543 this.view.select(match);
43544 var sn = Roo.get(this.view.getSelectedNodes()[0]);
43545 sn.scrollIntoView(sn.dom.parentNode, false);
43549 * @cfg {Boolean} grow
43553 * @cfg {Number} growMin
43557 * @cfg {Number} growMax
43565 * Copyright(c) 2010-2012, Roo J Solutions Limited
43572 * @class Roo.form.ComboBoxArray
43573 * @extends Roo.form.TextField
43574 * A facebook style adder... for lists of email / people / countries etc...
43575 * pick multiple items from a combo box, and shows each one.
43577 * Fred [x] Brian [x] [Pick another |v]
43580 * For this to work: it needs various extra information
43581 * - normal combo problay has
43583 * + displayField, valueField
43585 * For our purpose...
43588 * If we change from 'extends' to wrapping...
43595 * Create a new ComboBoxArray.
43596 * @param {Object} config Configuration options
43600 Roo.form.ComboBoxArray = function(config)
43604 * @event beforeremove
43605 * Fires before remove the value from the list
43606 * @param {Roo.form.ComboBoxArray} _self This combo box array
43607 * @param {Roo.form.ComboBoxArray.Item} item removed item
43609 'beforeremove' : true,
43612 * Fires when remove the value from the list
43613 * @param {Roo.form.ComboBoxArray} _self This combo box array
43614 * @param {Roo.form.ComboBoxArray.Item} item removed item
43621 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
43623 this.items = new Roo.util.MixedCollection(false);
43625 // construct the child combo...
43635 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
43638 * @cfg {Roo.form.ComboBox} combo [required] The combo box that is wrapped
43643 // behavies liek a hiddne field
43644 inputType: 'hidden',
43646 * @cfg {Number} width The width of the box that displays the selected element
43653 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
43657 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
43659 hiddenName : false,
43661 * @cfg {String} seperator The value seperator normally ','
43665 // private the array of items that are displayed..
43667 // private - the hidden field el.
43669 // private - the filed el..
43672 //validateValue : function() { return true; }, // all values are ok!
43673 //onAddClick: function() { },
43675 onRender : function(ct, position)
43678 // create the standard hidden element
43679 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
43682 // give fake names to child combo;
43683 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
43684 this.combo.name = this.name ? (this.name+'-subcombo') : this.name;
43686 this.combo = Roo.factory(this.combo, Roo.form);
43687 this.combo.onRender(ct, position);
43688 if (typeof(this.combo.width) != 'undefined') {
43689 this.combo.onResize(this.combo.width,0);
43692 this.combo.initEvents();
43694 // assigned so form know we need to do this..
43695 this.store = this.combo.store;
43696 this.valueField = this.combo.valueField;
43697 this.displayField = this.combo.displayField ;
43700 this.combo.wrap.addClass('x-cbarray-grp');
43702 var cbwrap = this.combo.wrap.createChild(
43703 {tag: 'div', cls: 'x-cbarray-cb'},
43708 this.hiddenEl = this.combo.wrap.createChild({
43709 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
43711 this.el = this.combo.wrap.createChild({
43712 tag: 'input', type:'hidden' , name: this.name, value : ''
43714 // this.el.dom.removeAttribute("name");
43717 this.outerWrap = this.combo.wrap;
43718 this.wrap = cbwrap;
43720 this.outerWrap.setWidth(this.width);
43721 this.outerWrap.dom.removeChild(this.el.dom);
43723 this.wrap.dom.appendChild(this.el.dom);
43724 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
43725 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
43727 this.combo.trigger.setStyle('position','relative');
43728 this.combo.trigger.setStyle('left', '0px');
43729 this.combo.trigger.setStyle('top', '2px');
43731 this.combo.el.setStyle('vertical-align', 'text-bottom');
43733 //this.trigger.setStyle('vertical-align', 'top');
43735 // this should use the code from combo really... on('add' ....)
43739 this.adder = this.outerWrap.createChild(
43740 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
43742 this.adder.on('click', function(e) {
43743 _t.fireEvent('adderclick', this, e);
43747 //this.adder.on('click', this.onAddClick, _t);
43750 this.combo.on('select', function(cb, rec, ix) {
43751 this.addItem(rec.data);
43754 cb.el.dom.value = '';
43755 //cb.lastData = rec.data;
43764 getName: function()
43766 // returns hidden if it's set..
43767 if (!this.rendered) {return ''};
43768 return this.hiddenName ? this.hiddenName : this.name;
43773 onResize: function(w, h){
43776 // not sure if this is needed..
43777 //this.combo.onResize(w,h);
43779 if(typeof w != 'number'){
43780 // we do not handle it!?!?
43783 var tw = this.combo.trigger.getWidth();
43784 tw += this.addicon ? this.addicon.getWidth() : 0;
43785 tw += this.editicon ? this.editicon.getWidth() : 0;
43787 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
43789 this.combo.trigger.setStyle('left', '0px');
43791 if(this.list && this.listWidth === undefined){
43792 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
43793 this.list.setWidth(lw);
43794 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
43801 addItem: function(rec)
43803 var valueField = this.combo.valueField;
43804 var displayField = this.combo.displayField;
43806 if (this.items.indexOfKey(rec[valueField]) > -1) {
43807 //console.log("GOT " + rec.data.id);
43811 var x = new Roo.form.ComboBoxArray.Item({
43812 //id : rec[this.idField],
43814 displayField : displayField ,
43815 tipField : displayField ,
43819 this.items.add(rec[valueField],x);
43820 // add it before the element..
43821 this.updateHiddenEl();
43822 x.render(this.outerWrap, this.wrap.dom);
43823 // add the image handler..
43826 updateHiddenEl : function()
43829 if (!this.hiddenEl) {
43833 var idField = this.combo.valueField;
43835 this.items.each(function(f) {
43836 ar.push(f.data[idField]);
43838 this.hiddenEl.dom.value = ar.join(this.seperator);
43844 this.items.clear();
43846 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
43850 this.el.dom.value = '';
43851 if (this.hiddenEl) {
43852 this.hiddenEl.dom.value = '';
43856 getValue: function()
43858 return this.hiddenEl ? this.hiddenEl.dom.value : '';
43860 setValue: function(v) // not a valid action - must use addItems..
43865 if (this.store.isLocal && (typeof(v) == 'string')) {
43866 // then we can use the store to find the values..
43867 // comma seperated at present.. this needs to allow JSON based encoding..
43868 this.hiddenEl.value = v;
43870 Roo.each(v.split(this.seperator), function(k) {
43871 Roo.log("CHECK " + this.valueField + ',' + k);
43872 var li = this.store.query(this.valueField, k);
43877 add[this.valueField] = k;
43878 add[this.displayField] = li.item(0).data[this.displayField];
43884 if (typeof(v) == 'object' ) {
43885 // then let's assume it's an array of objects..
43886 Roo.each(v, function(l) {
43888 if (typeof(l) == 'string') {
43890 add[this.valueField] = l;
43891 add[this.displayField] = l
43900 setFromData: function(v)
43902 // this recieves an object, if setValues is called.
43904 this.el.dom.value = v[this.displayField];
43905 this.hiddenEl.dom.value = v[this.valueField];
43906 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
43909 var kv = v[this.valueField];
43910 var dv = v[this.displayField];
43911 kv = typeof(kv) != 'string' ? '' : kv;
43912 dv = typeof(dv) != 'string' ? '' : dv;
43915 var keys = kv.split(this.seperator);
43916 var display = dv.split(this.seperator);
43917 for (var i = 0 ; i < keys.length; i++) {
43919 add[this.valueField] = keys[i];
43920 add[this.displayField] = display[i];
43928 * Validates the combox array value
43929 * @return {Boolean} True if the value is valid, else false
43931 validate : function(){
43932 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
43933 this.clearInvalid();
43939 validateValue : function(value){
43940 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
43948 isDirty : function() {
43949 if(this.disabled) {
43954 var d = Roo.decode(String(this.originalValue));
43956 return String(this.getValue()) !== String(this.originalValue);
43959 var originalValue = [];
43961 for (var i = 0; i < d.length; i++){
43962 originalValue.push(d[i][this.valueField]);
43965 return String(this.getValue()) !== String(originalValue.join(this.seperator));
43974 * @class Roo.form.ComboBoxArray.Item
43975 * @extends Roo.BoxComponent
43976 * A selected item in the list
43977 * Fred [x] Brian [x] [Pick another |v]
43980 * Create a new item.
43981 * @param {Object} config Configuration options
43984 Roo.form.ComboBoxArray.Item = function(config) {
43985 config.id = Roo.id();
43986 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
43989 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
43992 displayField : false,
43996 defaultAutoCreate : {
43998 cls: 'x-cbarray-item',
44005 src : Roo.BLANK_IMAGE_URL ,
44013 onRender : function(ct, position)
44015 Roo.form.Field.superclass.onRender.call(this, ct, position);
44018 var cfg = this.getAutoCreate();
44019 this.el = ct.createChild(cfg, position);
44022 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
44024 this.el.child('div').dom.innerHTML = this.cb.renderer ?
44025 this.cb.renderer(this.data) :
44026 String.format('{0}',this.data[this.displayField]);
44029 this.el.child('div').dom.setAttribute('qtip',
44030 String.format('{0}',this.data[this.tipField])
44033 this.el.child('img').on('click', this.remove, this);
44037 remove : function()
44039 if(this.cb.disabled){
44043 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
44044 this.cb.items.remove(this);
44045 this.el.child('img').un('click', this.remove, this);
44047 this.cb.updateHiddenEl();
44049 this.cb.fireEvent('remove', this.cb, this);
44054 * RooJS Library 1.1.1
44055 * Copyright(c) 2008-2011 Alan Knowles
44062 * @class Roo.form.ComboNested
44063 * @extends Roo.form.ComboBox
44064 * A combobox for that allows selection of nested items in a list,
44079 * Create a new ComboNested
44080 * @param {Object} config Configuration options
44082 Roo.form.ComboNested = function(config){
44083 Roo.form.ComboCheck.superclass.constructor.call(this, config);
44084 // should verify some data...
44086 // hiddenName = required..
44087 // displayField = required
44088 // valudField == required
44089 var req= [ 'hiddenName', 'displayField', 'valueField' ];
44091 Roo.each(req, function(e) {
44092 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
44093 throw "Roo.form.ComboNested : missing value for: " + e;
44100 Roo.extend(Roo.form.ComboNested, Roo.form.ComboBox, {
44103 * @config {Number} max Number of columns to show
44108 list : null, // the outermost div..
44109 innerLists : null, // the
44113 loadingChildren : false,
44115 onRender : function(ct, position)
44117 Roo.form.ComboBox.superclass.onRender.call(this, ct, position); // skip parent call - got to above..
44119 if(this.hiddenName){
44120 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
44122 this.hiddenField.value =
44123 this.hiddenValue !== undefined ? this.hiddenValue :
44124 this.value !== undefined ? this.value : '';
44126 // prevent input submission
44127 this.el.dom.removeAttribute('name');
44133 this.el.dom.setAttribute('autocomplete', 'off');
44136 var cls = 'x-combo-list';
44138 this.list = new Roo.Layer({
44139 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
44142 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
44143 this.list.setWidth(lw);
44144 this.list.swallowEvent('mousewheel');
44145 this.assetHeight = 0;
44148 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
44149 this.assetHeight += this.header.getHeight();
44151 this.innerLists = [];
44154 for (var i =0 ; i < this.maxColumns; i++) {
44155 this.onRenderList( cls, i);
44158 // always needs footer, as we are going to have an 'OK' button.
44159 this.footer = this.list.createChild({cls:cls+'-ft'});
44160 this.pageTb = new Roo.Toolbar(this.footer);
44165 handler: function()
44171 if ( this.allowBlank && !this.disableClear) {
44173 this.pageTb.add(new Roo.Toolbar.Fill(), {
44174 cls: 'x-btn-icon x-btn-clear',
44176 handler: function()
44179 _this.clearValue();
44180 _this.onSelect(false, -1);
44185 this.assetHeight += this.footer.getHeight();
44189 onRenderList : function ( cls, i)
44192 var lw = Math.floor(
44193 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
44196 this.list.setWidth(lw); // default to '1'
44198 var il = this.innerLists[i] = this.list.createChild({cls:cls+'-inner'});
44199 //il.on('mouseover', this.onViewOver, this, { list: i });
44200 //il.on('mousemove', this.onViewMove, this, { list: i });
44202 il.setStyle({ 'overflow-x' : 'hidden'});
44205 this.tpl = new Roo.Template({
44206 html : '<div class="'+cls+'-item '+cls+'-item-{cn:this.isEmpty}">{' + this.displayField + '}</div>',
44207 isEmpty: function (value, allValues) {
44209 var dl = typeof(value.data) != 'undefined' ? value.data.length : value.length; ///json is a nested response..
44210 return dl ? 'has-children' : 'no-children'
44215 var store = this.store;
44217 store = new Roo.data.SimpleStore({
44218 //fields : this.store.reader.meta.fields,
44219 reader : this.store.reader,
44223 this.stores[i] = store;
44225 var view = this.views[i] = new Roo.View(
44231 selectedClass: this.selectedClass
44234 view.getEl().setWidth(lw);
44235 view.getEl().setStyle({
44236 position: i < 1 ? 'relative' : 'absolute',
44238 left: (i * lw ) + 'px',
44239 display : i > 0 ? 'none' : 'block'
44241 view.on('selectionchange', this.onSelectChange.createDelegate(this, {list : i }, true));
44242 view.on('dblclick', this.onDoubleClick.createDelegate(this, {list : i }, true));
44243 //view.on('click', this.onViewClick, this, { list : i });
44245 store.on('beforeload', this.onBeforeLoad, this);
44246 store.on('load', this.onLoad, this, { list : i});
44247 store.on('loadexception', this.onLoadException, this);
44249 // hide the other vies..
44255 restrictHeight : function()
44258 Roo.each(this.innerLists, function(il,i) {
44259 var el = this.views[i].getEl();
44260 el.dom.style.height = '';
44261 var inner = el.dom;
44262 var h = Math.max(il.clientHeight, il.offsetHeight, il.scrollHeight);
44263 // only adjust heights on other ones..
44264 mh = Math.max(h, mh);
44267 el.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
44268 il.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
44275 this.list.beginUpdate();
44276 this.list.setHeight(mh+this.list.getFrameWidth('tb')+this.assetHeight);
44277 this.list.alignTo(this.el, this.listAlign);
44278 this.list.endUpdate();
44283 // -- store handlers..
44285 onBeforeLoad : function()
44287 if(!this.hasFocus){
44290 this.innerLists[0].update(this.loadingText ?
44291 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
44292 this.restrictHeight();
44293 this.selectedIndex = -1;
44296 onLoad : function(a,b,c,d)
44298 if (!this.loadingChildren) {
44299 // then we are loading the top level. - hide the children
44300 for (var i = 1;i < this.views.length; i++) {
44301 this.views[i].getEl().setStyle({ display : 'none' });
44303 var lw = Math.floor(
44304 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
44307 this.list.setWidth(lw); // default to '1'
44311 if(!this.hasFocus){
44315 if(this.store.getCount() > 0) {
44317 this.restrictHeight();
44319 this.onEmptyResults();
44322 if (!this.loadingChildren) {
44323 this.selectActive();
44326 this.stores[1].loadData([]);
44327 this.stores[2].loadData([]);
44336 onLoadException : function()
44339 Roo.log(this.store.reader.jsonData);
44340 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
44341 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
44346 // no cleaning of leading spaces on blur here.
44347 cleanLeadingSpace : function(e) { },
44350 onSelectChange : function (view, sels, opts )
44352 var ix = view.getSelectedIndexes();
44354 if (opts.list > this.maxColumns - 2) {
44355 if (view.store.getCount()< 1) {
44356 this.views[opts.list ].getEl().setStyle({ display : 'none' });
44360 // used to clear ?? but if we are loading unselected
44361 this.setFromData(view.store.getAt(ix[0]).data);
44370 // this get's fired when trigger opens..
44371 // this.setFromData({});
44372 var str = this.stores[opts.list+1];
44373 str.data.clear(); // removeall wihtout the fire events..
44377 var rec = view.store.getAt(ix[0]);
44379 this.setFromData(rec.data);
44380 this.fireEvent('select', this, rec, ix[0]);
44382 var lw = Math.floor(
44384 (this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')
44385 ) / this.maxColumns
44387 this.loadingChildren = true;
44388 this.stores[opts.list+1].loadDataFromChildren( rec );
44389 this.loadingChildren = false;
44390 var dl = this.stores[opts.list+1]. getTotalCount();
44392 this.views[opts.list+1].getEl().setHeight( this.innerLists[0].getHeight());
44394 this.views[opts.list+1].getEl().setStyle({ display : dl ? 'block' : 'none' });
44395 for (var i = opts.list+2; i < this.views.length;i++) {
44396 this.views[i].getEl().setStyle({ display : 'none' });
44399 this.innerLists[opts.list+1].setHeight( this.innerLists[0].getHeight());
44400 this.list.setWidth(lw * (opts.list + (dl ? 2 : 1)));
44402 if (this.isLoading) {
44403 // this.selectActive(opts.list);
44411 onDoubleClick : function()
44413 this.collapse(); //??
44421 recordToStack : function(store, prop, value, stack)
44423 var cstore = new Roo.data.SimpleStore({
44424 //fields : this.store.reader.meta.fields, // we need array reader.. for
44425 reader : this.store.reader,
44429 var record = false;
44431 if(store.getCount() < 1){
44434 store.each(function(r){
44435 if(r.data[prop] == value){
44440 if (r.data.cn && r.data.cn.length) {
44441 cstore.loadDataFromChildren( r);
44442 var cret = _this.recordToStack(cstore, prop, value, stack);
44443 if (cret !== false) {
44452 if (record == false) {
44455 stack.unshift(srec);
44460 * find the stack of stores that match our value.
44465 selectActive : function ()
44467 // if store is not loaded, then we will need to wait for that to happen first.
44469 this.recordToStack(this.store, this.valueField, this.getValue(), stack);
44470 for (var i = 0; i < stack.length; i++ ) {
44471 this.views[i].select(stack[i].store.indexOf(stack[i]), false, false );
44483 * Ext JS Library 1.1.1
44484 * Copyright(c) 2006-2007, Ext JS, LLC.
44486 * Originally Released Under LGPL - original licence link has changed is not relivant.
44489 * <script type="text/javascript">
44492 * @class Roo.form.Checkbox
44493 * @extends Roo.form.Field
44494 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
44496 * Creates a new Checkbox
44497 * @param {Object} config Configuration options
44499 Roo.form.Checkbox = function(config){
44500 Roo.form.Checkbox.superclass.constructor.call(this, config);
44504 * Fires when the checkbox is checked or unchecked.
44505 * @param {Roo.form.Checkbox} this This checkbox
44506 * @param {Boolean} checked The new checked value
44512 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
44514 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
44516 focusClass : undefined,
44518 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
44520 fieldClass: "x-form-field",
44522 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
44526 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
44527 * {tag: "input", type: "checkbox", autocomplete: "off"})
44529 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
44531 * @cfg {String} boxLabel The text that appears beside the checkbox
44535 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
44539 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
44541 valueOff: '0', // value when not checked..
44543 actionMode : 'viewEl',
44546 itemCls : 'x-menu-check-item x-form-item',
44547 groupClass : 'x-menu-group-item',
44548 inputType : 'hidden',
44551 inSetChecked: false, // check that we are not calling self...
44553 inputElement: false, // real input element?
44554 basedOn: false, // ????
44556 isFormField: true, // not sure where this is needed!!!!
44558 onResize : function(){
44559 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
44560 if(!this.boxLabel){
44561 this.el.alignTo(this.wrap, 'c-c');
44565 initEvents : function(){
44566 Roo.form.Checkbox.superclass.initEvents.call(this);
44567 this.el.on("click", this.onClick, this);
44568 this.el.on("change", this.onClick, this);
44572 getResizeEl : function(){
44576 getPositionEl : function(){
44581 onRender : function(ct, position){
44582 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
44584 if(this.inputValue !== undefined){
44585 this.el.dom.value = this.inputValue;
44588 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
44589 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
44590 var viewEl = this.wrap.createChild({
44591 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
44592 this.viewEl = viewEl;
44593 this.wrap.on('click', this.onClick, this);
44595 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
44596 this.el.on('propertychange', this.setFromHidden, this); //ie
44601 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
44602 // viewEl.on('click', this.onClick, this);
44604 //if(this.checked){
44605 this.setChecked(this.checked);
44607 //this.checked = this.el.dom;
44613 initValue : Roo.emptyFn,
44616 * Returns the checked state of the checkbox.
44617 * @return {Boolean} True if checked, else false
44619 getValue : function(){
44621 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
44623 return this.valueOff;
44628 onClick : function(){
44629 if (this.disabled) {
44632 this.setChecked(!this.checked);
44634 //if(this.el.dom.checked != this.checked){
44635 // this.setValue(this.el.dom.checked);
44640 * Sets the checked state of the checkbox.
44641 * On is always based on a string comparison between inputValue and the param.
44642 * @param {Boolean/String} value - the value to set
44643 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
44645 setValue : function(v,suppressEvent){
44648 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
44649 //if(this.el && this.el.dom){
44650 // this.el.dom.checked = this.checked;
44651 // this.el.dom.defaultChecked = this.checked;
44653 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
44654 //this.fireEvent("check", this, this.checked);
44657 setChecked : function(state,suppressEvent)
44659 if (this.inSetChecked) {
44660 this.checked = state;
44666 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
44668 this.checked = state;
44669 if(suppressEvent !== true){
44670 this.fireEvent('check', this, state);
44672 this.inSetChecked = true;
44673 this.el.dom.value = state ? this.inputValue : this.valueOff;
44674 this.inSetChecked = false;
44677 // handle setting of hidden value by some other method!!?!?
44678 setFromHidden: function()
44683 //console.log("SET FROM HIDDEN");
44684 //alert('setFrom hidden');
44685 this.setValue(this.el.dom.value);
44688 onDestroy : function()
44691 Roo.get(this.viewEl).remove();
44694 Roo.form.Checkbox.superclass.onDestroy.call(this);
44697 setBoxLabel : function(str)
44699 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
44704 * Ext JS Library 1.1.1
44705 * Copyright(c) 2006-2007, Ext JS, LLC.
44707 * Originally Released Under LGPL - original licence link has changed is not relivant.
44710 * <script type="text/javascript">
44714 * @class Roo.form.Radio
44715 * @extends Roo.form.Checkbox
44716 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
44717 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
44719 * Creates a new Radio
44720 * @param {Object} config Configuration options
44722 Roo.form.Radio = function(){
44723 Roo.form.Radio.superclass.constructor.apply(this, arguments);
44725 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
44726 inputType: 'radio',
44729 * If this radio is part of a group, it will return the selected value
44732 getGroupValue : function(){
44733 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
44737 onRender : function(ct, position){
44738 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
44740 if(this.inputValue !== undefined){
44741 this.el.dom.value = this.inputValue;
44744 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
44745 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
44746 //var viewEl = this.wrap.createChild({
44747 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
44748 //this.viewEl = viewEl;
44749 //this.wrap.on('click', this.onClick, this);
44751 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
44752 //this.el.on('propertychange', this.setFromHidden, this); //ie
44757 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
44758 // viewEl.on('click', this.onClick, this);
44761 this.el.dom.checked = 'checked' ;
44767 });Roo.rtf = {}; // namespace
44768 Roo.rtf.Hex = function(hex)
44772 Roo.rtf.Paragraph = function(opts)
44774 this.content = []; ///??? is that used?
44775 };Roo.rtf.Span = function(opts)
44777 this.value = opts.value;
44780 Roo.rtf.Group = function(parent)
44782 // we dont want to acutally store parent - it will make debug a nightmare..
44790 Roo.rtf.Group.prototype = {
44794 addContent : function(node) {
44795 // could set styles...
44796 this.content.push(node);
44798 addChild : function(cn)
44802 // only for images really...
44803 toDataURL : function()
44805 var mimetype = false;
44807 case this.content.filter(function(a) { return a.value == 'pngblip' } ).length > 0:
44808 mimetype = "image/png";
44810 case this.content.filter(function(a) { return a.value == 'jpegblip' } ).length > 0:
44811 mimetype = "image/jpeg";
44814 return 'about:blank'; // ?? error?
44818 var hexstring = this.content[this.content.length-1].value;
44820 return 'data:' + mimetype + ';base64,' + btoa(hexstring.match(/\w{2}/g).map(function(a) {
44821 return String.fromCharCode(parseInt(a, 16));
44826 // this looks like it's normally the {rtf{ .... }}
44827 Roo.rtf.Document = function()
44829 // we dont want to acutally store parent - it will make debug a nightmare..
44835 Roo.extend(Roo.rtf.Document, Roo.rtf.Group, {
44836 addChild : function(cn)
44840 case 'rtlch': // most content seems to be inside this??
44843 this.rtlch.push(cn);
44846 this[cn.type] = cn;
44851 getElementsByType : function(type)
44854 this._getElementsByType(type, ret, this.cn, 'rtf');
44857 _getElementsByType : function (type, ret, search_array, path)
44859 search_array.forEach(function(n,i) {
44860 if (n.type == type) {
44861 n.path = path + '/' + n.type + ':' + i;
44864 if (n.cn.length > 0) {
44865 this._getElementsByType(type, ret, n.cn, path + '/' + n.type+':'+i);
44872 Roo.rtf.Ctrl = function(opts)
44874 this.value = opts.value;
44875 this.param = opts.param;
44880 * based on this https://github.com/iarna/rtf-parser
44881 * it's really only designed to extract pict from pasted RTF
44885 * var images = new Roo.rtf.Parser().parse(a_string).filter(function(g) { return g.type == 'pict'; });
44894 Roo.rtf.Parser = function(text) {
44895 //super({objectMode: true})
44897 this.parserState = this.parseText;
44899 // these are for interpeter...
44901 ///this.parserState = this.parseTop
44902 this.groupStack = [];
44903 this.hexStore = [];
44906 this.groups = []; // where we put the return.
44908 for (var ii = 0; ii < text.length; ++ii) {
44911 if (text[ii] === '\n') {
44917 this.parserState(text[ii]);
44923 Roo.rtf.Parser.prototype = {
44924 text : '', // string being parsed..
44926 controlWordParam : '',
44930 groupStack : false,
44935 row : 1, // reportin?
44939 push : function (el)
44941 var m = 'cmd'+ el.type;
44942 if (typeof(this[m]) == 'undefined') {
44943 Roo.log('invalid cmd:' + el.type);
44949 flushHexStore : function()
44951 if (this.hexStore.length < 1) {
44954 var hexstr = this.hexStore.map(
44959 this.group.addContent( new Roo.rtf.Hex( hexstr ));
44962 this.hexStore.splice(0)
44966 cmdgroupstart : function()
44968 this.flushHexStore();
44970 this.groupStack.push(this.group);
44973 if (this.doc === false) {
44974 this.group = this.doc = new Roo.rtf.Document();
44978 this.group = new Roo.rtf.Group(this.group);
44980 cmdignorable : function()
44982 this.flushHexStore();
44983 this.group.ignorable = true;
44985 cmdendparagraph : function()
44987 this.flushHexStore();
44988 this.group.addContent(new Roo.rtf.Paragraph());
44990 cmdgroupend : function ()
44992 this.flushHexStore();
44993 var endingGroup = this.group;
44996 this.group = this.groupStack.pop();
44998 this.group.addChild(endingGroup);
45003 var doc = this.group || this.doc;
45004 //if (endingGroup instanceof FontTable) {
45005 // doc.fonts = endingGroup.table
45006 //} else if (endingGroup instanceof ColorTable) {
45007 // doc.colors = endingGroup.table
45008 //} else if (endingGroup !== this.doc && !endingGroup.get('ignorable')) {
45009 if (endingGroup.ignorable === false) {
45011 this.groups.push(endingGroup);
45012 // Roo.log( endingGroup );
45014 //Roo.each(endingGroup.content, function(item)) {
45015 // doc.addContent(item);
45017 //process.emit('debug', 'GROUP END', endingGroup.type, endingGroup.get('ignorable'))
45020 cmdtext : function (cmd)
45022 this.flushHexStore();
45023 if (!this.group) { // an RTF fragment, missing the {\rtf1 header
45024 //this.group = this.doc
45026 this.group.addContent(new Roo.rtf.Span(cmd));
45028 cmdcontrolword : function (cmd)
45030 this.flushHexStore();
45031 if (!this.group.type) {
45032 this.group.type = cmd.value;
45035 this.group.addContent(new Roo.rtf.Ctrl(cmd));
45036 // we actually don't care about ctrl words...
45039 var method = 'ctrl$' + cmd.value.replace(/-(.)/g, (_, char) => char.toUpperCase())
45040 if (this[method]) {
45041 this[method](cmd.param)
45043 if (!this.group.get('ignorable')) process.emit('debug', method, cmd.param)
45047 cmdhexchar : function(cmd) {
45048 this.hexStore.push(cmd);
45050 cmderror : function(cmd) {
45051 throw new Exception (cmd.value);
45056 if (this.text !== '\u0000') this.emitText()
45062 parseText : function(c)
45065 this.parserState = this.parseEscapes;
45066 } else if (c === '{') {
45067 this.emitStartGroup();
45068 } else if (c === '}') {
45069 this.emitEndGroup();
45070 } else if (c === '\x0A' || c === '\x0D') {
45071 // cr/lf are noise chars
45077 parseEscapes: function (c)
45079 if (c === '\\' || c === '{' || c === '}') {
45081 this.parserState = this.parseText;
45083 this.parserState = this.parseControlSymbol;
45084 this.parseControlSymbol(c);
45087 parseControlSymbol: function(c)
45090 this.text += '\u00a0'; // nbsp
45091 this.parserState = this.parseText
45092 } else if (c === '-') {
45093 this.text += '\u00ad'; // soft hyphen
45094 } else if (c === '_') {
45095 this.text += '\u2011'; // non-breaking hyphen
45096 } else if (c === '*') {
45097 this.emitIgnorable();
45098 this.parserState = this.parseText;
45099 } else if (c === "'") {
45100 this.parserState = this.parseHexChar;
45101 } else if (c === '|') { // formula cacter
45102 this.emitFormula();
45103 this.parserState = this.parseText;
45104 } else if (c === ':') { // subentry in an index entry
45105 this.emitIndexSubEntry();
45106 this.parserState = this.parseText;
45107 } else if (c === '\x0a') {
45108 this.emitEndParagraph();
45109 this.parserState = this.parseText;
45110 } else if (c === '\x0d') {
45111 this.emitEndParagraph();
45112 this.parserState = this.parseText;
45114 this.parserState = this.parseControlWord;
45115 this.parseControlWord(c);
45118 parseHexChar: function (c)
45120 if (/^[A-Fa-f0-9]$/.test(c)) {
45122 if (this.hexChar.length >= 2) {
45123 this.emitHexChar();
45124 this.parserState = this.parseText;
45128 this.emitError("Invalid character \"" + c + "\" in hex literal.");
45129 this.parserState = this.parseText;
45132 parseControlWord : function(c)
45135 this.emitControlWord();
45136 this.parserState = this.parseText;
45137 } else if (/^[-\d]$/.test(c)) {
45138 this.parserState = this.parseControlWordParam;
45139 this.controlWordParam += c;
45140 } else if (/^[A-Za-z]$/.test(c)) {
45141 this.controlWord += c;
45143 this.emitControlWord();
45144 this.parserState = this.parseText;
45148 parseControlWordParam : function (c) {
45149 if (/^\d$/.test(c)) {
45150 this.controlWordParam += c;
45151 } else if (c === ' ') {
45152 this.emitControlWord();
45153 this.parserState = this.parseText;
45155 this.emitControlWord();
45156 this.parserState = this.parseText;
45164 emitText : function () {
45165 if (this.text === '') {
45177 emitControlWord : function ()
45180 if (this.controlWord === '') {
45181 this.emitError('empty control word');
45184 type: 'controlword',
45185 value: this.controlWord,
45186 param: this.controlWordParam !== '' && Number(this.controlWordParam),
45192 this.controlWord = '';
45193 this.controlWordParam = '';
45195 emitStartGroup : function ()
45199 type: 'groupstart',
45205 emitEndGroup : function ()
45215 emitIgnorable : function ()
45225 emitHexChar : function ()
45230 value: this.hexChar,
45237 emitError : function (message)
45245 char: this.cpos //,
45246 //stack: new Error().stack
45249 emitEndParagraph : function () {
45252 type: 'endparagraph',
45260 Roo.htmleditor = {};
45263 * @class Roo.htmleditor.Filter
45264 * Base Class for filtering htmleditor stuff. - do not use this directly - extend it.
45265 * @cfg {DomElement} node The node to iterate and filter
45266 * @cfg {boolean|String|Array} tag Tags to replace
45268 * Create a new Filter.
45269 * @param {Object} config Configuration options
45274 Roo.htmleditor.Filter = function(cfg) {
45275 Roo.apply(this.cfg);
45276 // this does not actually call walk as it's really just a abstract class
45280 Roo.htmleditor.Filter.prototype = {
45286 // overrride to do replace comments.
45287 replaceComment : false,
45289 // overrride to do replace or do stuff with tags..
45290 replaceTag : false,
45292 walk : function(dom)
45294 Roo.each( Array.from(dom.childNodes), function( e ) {
45297 case e.nodeType == 8 && typeof(this.replaceComment) != 'undefined': // comment
45298 this.replaceComment(e);
45301 case e.nodeType != 1: //not a node.
45304 case this.tag === true: // everything
45305 case typeof(this.tag) == 'object' && this.tag.indexOf(e.tagName) > -1: // array and it matches.
45306 case typeof(this.tag) == 'string' && this.tag == e.tagName: // array and it matches.
45307 if (this.replaceTag && false === this.replaceTag(e)) {
45310 if (e.hasChildNodes()) {
45315 default: // tags .. that do not match.
45316 if (e.hasChildNodes()) {
45327 * @class Roo.htmleditor.FilterAttributes
45328 * clean attributes and styles including http:// etc.. in attribute
45330 * Run a new Attribute Filter
45331 * @param {Object} config Configuration options
45333 Roo.htmleditor.FilterAttributes = function(cfg)
45335 Roo.apply(this, cfg);
45336 this.attrib_black = this.attrib_black || [];
45337 this.attrib_white = this.attrib_white || [];
45339 this.attrib_clean = this.attrib_clean || [];
45340 this.style_white = this.style_white || [];
45341 this.style_black = this.style_black || [];
45342 this.walk(cfg.node);
45345 Roo.extend(Roo.htmleditor.FilterAttributes, Roo.htmleditor.Filter,
45347 tag: true, // all tags
45349 attrib_black : false, // array
45350 attrib_clean : false,
45351 attrib_white : false,
45353 style_white : false,
45354 style_black : false,
45357 replaceTag : function(node)
45359 if (!node.attributes || !node.attributes.length) {
45363 for (var i = node.attributes.length-1; i > -1 ; i--) {
45364 var a = node.attributes[i];
45366 if (this.attrib_white.length && this.attrib_white.indexOf(a.name.toLowerCase()) < 0) {
45367 node.removeAttribute(a.name);
45373 if (a.name.toLowerCase().substr(0,2)=='on') {
45374 node.removeAttribute(a.name);
45379 if (this.attrib_black.indexOf(a.name.toLowerCase()) > -1) {
45380 node.removeAttribute(a.name);
45383 if (this.attrib_clean.indexOf(a.name.toLowerCase()) > -1) {
45384 this.cleanAttr(node,a.name,a.value); // fixme..
45387 if (a.name == 'style') {
45388 this.cleanStyle(node,a.name,a.value);
45391 /// clean up MS crap..
45392 // tecnically this should be a list of valid class'es..
45395 if (a.name == 'class') {
45396 if (a.value.match(/^Mso/)) {
45397 node.removeAttribute('class');
45400 if (a.value.match(/^body$/)) {
45401 node.removeAttribute('class');
45411 return true; // clean children
45414 cleanAttr: function(node, n,v)
45417 if (v.match(/^\./) || v.match(/^\//)) {
45420 if (v.match(/^(http|https):\/\//)
45421 || v.match(/^mailto:/)
45422 || v.match(/^ftp:/)
45423 || v.match(/^data:/)
45427 if (v.match(/^#/)) {
45430 if (v.match(/^\{/)) { // allow template editing.
45433 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
45434 node.removeAttribute(n);
45437 cleanStyle : function(node, n,v)
45439 if (v.match(/expression/)) { //XSS?? should we even bother..
45440 node.removeAttribute(n);
45444 var parts = v.split(/;/);
45447 Roo.each(parts, function(p) {
45448 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
45452 var l = p.split(':').shift().replace(/\s+/g,'');
45453 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
45455 if ( this.style_black.length && (this.style_black.indexOf(l) > -1 || this.style_black.indexOf(l.toLowerCase()) > -1)) {
45459 // only allow 'c whitelisted system attributes'
45460 if ( this.style_white.length && style_white.indexOf(l) < 0 && style_white.indexOf(l.toLowerCase()) < 0 ) {
45468 if (clean.length) {
45469 node.setAttribute(n, clean.join(';'));
45471 node.removeAttribute(n);
45480 * @class Roo.htmleditor.FilterBlack
45481 * remove blacklisted elements.
45483 * Run a new Blacklisted Filter
45484 * @param {Object} config Configuration options
45487 Roo.htmleditor.FilterBlack = function(cfg)
45489 Roo.apply(this, cfg);
45490 this.walk(cfg.node);
45493 Roo.extend(Roo.htmleditor.FilterBlack, Roo.htmleditor.Filter,
45495 tag : true, // all elements.
45497 replace : function(n)
45499 n.parentNode.removeChild(n);
45503 * @class Roo.htmleditor.FilterComment
45506 * Run a new Comments Filter
45507 * @param {Object} config Configuration options
45509 Roo.htmleditor.FilterComment = function(cfg)
45511 this.walk(cfg.node);
45514 Roo.extend(Roo.htmleditor.FilterComment, Roo.htmleditor.Filter,
45517 replaceComment : function(n)
45519 n.parentNode.removeChild(n);
45522 * @class Roo.htmleditor.FilterKeepChildren
45523 * remove tags but keep children
45525 * Run a new Keep Children Filter
45526 * @param {Object} config Configuration options
45529 Roo.htmleditor.FilterKeepChildren = function(cfg)
45531 Roo.apply(this, cfg);
45532 if (this.tag === false) {
45533 return; // dont walk.. (you can use this to use this just to do a child removal on a single tag )
45535 this.walk(cfg.node);
45538 Roo.extend(Roo.htmleditor.FilterKeepChildren, Roo.htmleditor.FilterBlack,
45542 replaceTag : function(node)
45544 // walk children...
45546 var ar = Array.from(node.childNodes);
45548 for (var i = 0; i < ar.length; i++) {
45549 if (ar[i].nodeType == 1) {
45551 (typeof(this.tag) == 'object' && this.tag.indexOf(ar[i].tagName) > -1)
45552 || // array and it matches
45553 (typeof(this.tag) == 'string' && this.tag == ar[i].tagName)
45555 this.replaceTag(ar[i]); // child is blacklisted as well...
45560 ar = Array.from(node.childNodes);
45561 for (var i = 0; i < ar.length; i++) {
45563 node.removeChild(ar[i]);
45564 // what if we need to walk these???
45565 node.parentNode.insertBefore(ar[i], node);
45566 if (this.tag !== false) {
45571 node.parentNode.removeChild(node);
45572 return false; // don't walk children
45577 * @class Roo.htmleditor.FilterParagraph
45578 * paragraphs cause a nightmare for shared content - this filter is designed to be called ? at various points when editing
45579 * like on 'push' to remove the <p> tags and replace them with line breaks.
45581 * Run a new Paragraph Filter
45582 * @param {Object} config Configuration options
45585 Roo.htmleditor.FilterParagraph = function(cfg)
45587 // no need to apply config.
45588 this.walk(cfg.node);
45591 Roo.extend(Roo.htmleditor.FilterParagraph, Roo.htmleditor.Filter,
45598 replaceTag : function(node)
45601 if (node.childNodes.length == 1 &&
45602 node.childNodes[0].nodeType == 3 &&
45603 node.childNodes[0].textContent.trim().length < 1
45605 // remove and replace with '<BR>';
45606 node.parentNode.replaceChild(node.ownerDocument.createElement('BR'),node);
45607 return false; // no need to walk..
45609 var ar = Array.from(node.childNodes);
45610 for (var i = 0; i < ar.length; i++) {
45611 node.removeChild(ar[i]);
45612 // what if we need to walk these???
45613 node.parentNode.insertBefore(ar[i], node);
45615 // now what about this?
45619 node.parentNode.insertBefore(node.ownerDocument.createElement('BR'), node);
45620 node.parentNode.insertBefore(node.ownerDocument.createElement('BR'), node);
45621 node.parentNode.removeChild(node);
45628 * @class Roo.htmleditor.FilterSpan
45629 * filter span's with no attributes out..
45631 * Run a new Span Filter
45632 * @param {Object} config Configuration options
45635 Roo.htmleditor.FilterSpan = function(cfg)
45637 // no need to apply config.
45638 this.walk(cfg.node);
45641 Roo.extend(Roo.htmleditor.FilterSpan, Roo.htmleditor.FilterKeepChildren,
45647 replaceTag : function(node)
45649 if (node.attributes && node.attributes.length > 0) {
45650 return true; // walk if there are any.
45652 Roo.htmleditor.FilterKeepChildren.prototype.replaceTag.call(this, node);
45658 * @class Roo.htmleditor.FilterTableWidth
45659 try and remove table width data - as that frequently messes up other stuff.
45661 * was cleanTableWidths.
45663 * Quite often pasting from word etc.. results in tables with column and widths.
45664 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
45667 * Run a new Table Filter
45668 * @param {Object} config Configuration options
45671 Roo.htmleditor.FilterTableWidth = function(cfg)
45673 // no need to apply config.
45674 this.tag = ['TABLE', 'TD', 'TR', 'TH', 'THEAD', 'TBODY' ];
45675 this.walk(cfg.node);
45678 Roo.extend(Roo.htmleditor.FilterTableWidth, Roo.htmleditor.Filter,
45683 replaceTag: function(node) {
45687 if (node.hasAttribute('width')) {
45688 node.removeAttribute('width');
45692 if (node.hasAttribute("style")) {
45695 var styles = node.getAttribute("style").split(";");
45697 Roo.each(styles, function(s) {
45698 if (!s.match(/:/)) {
45701 var kv = s.split(":");
45702 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
45705 // what ever is left... we allow.
45708 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
45709 if (!nstyle.length) {
45710 node.removeAttribute('style');
45714 return true; // continue doing children..
45717 * @class Roo.htmleditor.FilterWord
45718 * try and clean up all the mess that Word generates.
45720 * This is the 'nice version' - see 'Heavy' that white lists a very short list of elements, and multi-filters
45723 * Run a new Span Filter
45724 * @param {Object} config Configuration options
45727 Roo.htmleditor.FilterWord = function(cfg)
45729 // no need to apply config.
45730 this.walk(cfg.node);
45733 Roo.extend(Roo.htmleditor.FilterWord, Roo.htmleditor.Filter,
45739 * Clean up MS wordisms...
45741 replaceTag : function(node)
45744 // no idea what this does - span with text, replaceds with just text.
45746 node.nodeName == 'SPAN' &&
45747 !node.hasAttributes() &&
45748 node.childNodes.length == 1 &&
45749 node.firstChild.nodeName == "#text"
45751 var textNode = node.firstChild;
45752 node.removeChild(textNode);
45753 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
45754 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
45756 node.parentNode.insertBefore(textNode, node);
45757 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
45758 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
45761 node.parentNode.removeChild(node);
45762 return false; // dont do chidren - we have remove our node - so no need to do chdhilren?
45767 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
45768 node.parentNode.removeChild(node);
45769 return false; // dont do chidlren
45771 //Roo.log(node.tagName);
45772 // remove - but keep children..
45773 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
45774 //Roo.log('-- removed');
45775 while (node.childNodes.length) {
45776 var cn = node.childNodes[0];
45777 node.removeChild(cn);
45778 node.parentNode.insertBefore(cn, node);
45779 // move node to parent - and clean it..
45780 this.replaceTag(cn);
45782 node.parentNode.removeChild(node);
45783 /// no need to iterate chidlren = it's got none..
45784 //this.iterateChildren(node, this.cleanWord);
45785 return false; // no need to iterate children.
45788 if (node.className.length) {
45790 var cn = node.className.split(/\W+/);
45792 Roo.each(cn, function(cls) {
45793 if (cls.match(/Mso[a-zA-Z]+/)) {
45798 node.className = cna.length ? cna.join(' ') : '';
45800 node.removeAttribute("class");
45804 if (node.hasAttribute("lang")) {
45805 node.removeAttribute("lang");
45808 if (node.hasAttribute("style")) {
45810 var styles = node.getAttribute("style").split(";");
45812 Roo.each(styles, function(s) {
45813 if (!s.match(/:/)) {
45816 var kv = s.split(":");
45817 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
45820 // what ever is left... we allow.
45823 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
45824 if (!nstyle.length) {
45825 node.removeAttribute('style');
45828 return true; // do children
45835 * @class Roo.htmleditor.FilterStyleToTag
45836 * part of the word stuff... - certain 'styles' should be converted to tags.
45838 * font-weight: bold -> bold
45839 * ?? super / subscrit etc..
45842 * Run a new style to tag filter.
45843 * @param {Object} config Configuration options
45845 Roo.htmleditor.FilterStyleToTag = function(cfg)
45849 B : [ 'fontWeight' , 'bold'],
45850 I : [ 'fontStyle' , 'italic'],
45851 //pre : [ 'font-style' , 'italic'],
45852 // h1.. h6 ?? font-size?
45853 SUP : [ 'verticalAlign' , 'super' ],
45854 SUB : [ 'verticalAlign' , 'sub' ]
45859 Roo.apply(this, cfg);
45862 this.walk(cfg.node);
45869 Roo.extend(Roo.htmleditor.FilterStyleToTag, Roo.htmleditor.Filter,
45871 tag: true, // all tags
45876 replaceTag : function(node)
45880 if (node.getAttribute("style") === null) {
45884 for (var k in this.tags) {
45885 if (node.style[this.tags[k][0]] == this.tags[k][1]) {
45887 node.style.removeProperty(this.tags[k][0]);
45890 if (!inject.length) {
45893 var cn = Array.from(node.childNodes);
45895 Roo.each(inject, function(t) {
45896 var nc = node.ownerDocument.createelement(t);
45897 nn.appendChild(nc);
45900 for(var i = 0;i < cn.length;cn++) {
45901 node.removeChild(cn[i]);
45902 nn.appendChild(cn[i]);
45904 return true /// iterate thru
45908 * @class Roo.htmleditor.FilterLongBr
45909 * BR/BR/BR - keep a maximum of 2...
45911 * Run a new Long BR Filter
45912 * @param {Object} config Configuration options
45915 Roo.htmleditor.FilterLongBr = function(cfg)
45917 // no need to apply config.
45918 this.walk(cfg.node);
45921 Roo.extend(Roo.htmleditor.FilterLongBr, Roo.htmleditor.Filter,
45928 replaceTag : function(node)
45931 var ps = node.nextSibling;
45932 while (ps && ps.nodeType == 3 && ps.nodeValue.trim().length < 1) {
45933 ps = ps.nextSibling;
45936 if (!ps && [ 'TD', 'TH', 'LI', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6' ].indexOf(node.parentNode.tagName) > -1) {
45937 node.parentNode.removeChild(node); // remove last BR inside one fo these tags
45941 if (!ps || ps.nodeType != 1) {
45945 if (!ps || ps.tagName != 'BR') {
45954 if (!node.previousSibling) {
45957 var ps = node.previousSibling;
45959 while (ps && ps.nodeType == 3 && ps.nodeValue.trim().length < 1) {
45960 ps = ps.previousSibling;
45962 if (!ps || ps.nodeType != 1) {
45965 // if header or BR before.. then it's a candidate for removal.. - as we only want '2' of these..
45966 if (!ps || [ 'BR', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6' ].indexOf(ps.tagName) < 0) {
45970 node.parentNode.removeChild(node); // remove me...
45972 return false; // no need to do children
45978 * @class Roo.htmleditor.Tidy
45980 * @cfg {Roo.HtmlEditorCore} core the editor.
45982 * Create a new Filter.
45983 * @param {Object} config Configuration options
45987 Roo.htmleditor.Tidy = function(cfg) {
45988 Roo.apply(this, cfg);
45990 this.core.doc.body.innerHTML = this.tidy(this.core.doc.body, '');
45994 Roo.htmleditor.Tidy.toString = function(node)
45996 return Roo.htmleditor.Tidy.prototype.tidy(node, '');
45999 Roo.htmleditor.Tidy.prototype = {
46002 wrap : function(s) {
46003 return s.replace(/\n/g, " ").replace(/(?![^\n]{1,80}$)([^\n]{1,80})\s/g, '$1\n');
46007 tidy : function(node, indent) {
46009 if (node.nodeType == 3) {
46013 return indent === false ? node.nodeValue : this.wrap(node.nodeValue.trim()).split("\n").join("\n" + indent);
46018 if (node.nodeType != 1) {
46024 if (node.tagName == 'BODY') {
46026 return this.cn(node, '');
46029 // Prints the node tagName, such as <A>, <IMG>, etc
46030 var ret = "<" + node.tagName + this.attr(node) ;
46032 // elements with no children..
46033 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(node.tagName) > -1) {
46039 var cindent = indent === false ? '' : (indent + ' ');
46040 // tags where we will not pad the children.. (inline text tags etc..)
46041 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN', 'B', 'I', 'S'].indexOf(node.tagName) > -1) { // or code?
46047 var cn = this.cn(node, cindent );
46049 return ret + cn + '</' + node.tagName + '>';
46052 cn: function(node, indent)
46056 var ar = Array.from(node.childNodes);
46057 for (var i = 0 ; i < ar.length ; i++) {
46061 if (indent !== false // indent==false preservies everything
46063 && ar[i].nodeType == 3
46064 && ar[i].nodeValue.length > 0
46065 && ar[i].nodeValue.match(/^\s+/)
46067 if (ret.length && ret[ret.length-1] == "\n" + indent) {
46068 ret.pop(); // remove line break from last?
46071 ret.push(" "); // add a space if i'm a text item with a space at the front, as tidy will strip spaces.
46073 if (indent !== false
46074 && ar[i].nodeType == 1 // element - and indent is not set...
46076 ret.push("\n" + indent);
46079 ret.push(this.tidy(ar[i], indent));
46080 // text + trailing indent
46081 if (indent !== false
46082 && ar[i].nodeType == 3
46083 && ar[i].nodeValue.length > 0
46084 && ar[i].nodeValue.match(/\s+$/)
46086 ret.push("\n" + indent);
46093 // what if all text?
46096 return ret.join('');
46101 attr : function(node)
46104 for(i = 0; i < node.attributes.length;i++) {
46106 // skip empty values?
46107 if (!node.attributes.item(i).value.length) {
46110 attr.push( node.attributes.item(i).name + '="' +
46111 Roo.util.Format.htmlEncode(node.attributes.item(i).value) + '"'
46114 return attr.length ? (' ' + attr.join(' ') ) : '';
46122 * @class Roo.htmleditor.KeyEnter
46123 * Handle Enter press..
46124 * @cfg {Roo.HtmlEditorCore} core the editor.
46126 * Create a new Filter.
46127 * @param {Object} config Configuration options
46132 Roo.htmleditor.KeyEnter = function(cfg) {
46133 Roo.apply(this, cfg);
46134 // this does not actually call walk as it's really just a abstract class
46136 Roo.get(this.core.doc.body).on('keypress', this.keypress, this);
46140 Roo.htmleditor.KeyEnter.prototype = {
46144 keypress : function(e) {
46145 if (e.charCode != 13) {
46148 e.preventDefault();
46149 // https://stackoverflow.com/questions/18552336/prevent-contenteditable-adding-div-on-enter-chrome
46150 var doc = this.core.doc;
46152 var docFragment = doc.createDocumentFragment();
46155 var newEle = doc.createTextNode('\n');
46156 docFragment.appendChild(newEle);
46159 var range = this.core.win.getSelection().getRangeAt(0);
46160 var n = range.commonAncestorContainer ;
46161 while (n && n.nodeType != 1) {
46165 if (n && n.tagName == 'UL') {
46166 li = doc.createElement('LI');
46170 if (n && n.tagName == 'LI') {
46171 li = doc.createElement('LI');
46172 if (n.nextSibling) {
46173 n.parentNode.insertBefore(li, n.firstSibling);
46176 n.parentNode.appendChild(li);
46180 range = doc.createRange();
46181 range.setStartAfter(li);
46182 range.collapse(true);
46184 //make the cursor there
46185 var sel = this.core.win.getSelection();
46186 sel.removeAllRanges();
46187 sel.addRange(range);
46192 //add the br, or p, or something else
46193 newEle = doc.createElement('br');
46194 docFragment.appendChild(newEle);
46196 //make the br replace selection
46198 range.deleteContents();
46200 range.insertNode(docFragment);
46202 //create a new range
46203 range = doc.createRange();
46204 range.setStartAfter(newEle);
46205 range.collapse(true);
46207 //make the cursor there
46208 var sel = this.core.win.getSelection();
46209 sel.removeAllRanges();
46210 sel.addRange(range);
46218 * @class Roo.htmleditor.Block
46219 * Base class for html editor blocks - do not use it directly .. extend it..
46220 * @cfg {DomElement} node The node to apply stuff to.
46221 * @cfg {String} friendly_name the name that appears in the context bar about this block
46222 * @cfg {Object} Context menu - see Roo.form.HtmlEditor.ToolbarContext
46225 * Create a new Filter.
46226 * @param {Object} config Configuration options
46229 Roo.htmleditor.Block = function(cfg)
46231 // do nothing .. should not be called really.
46234 Roo.htmleditor.Block.factory = function(node)
46237 var id = Roo.get(node).id;
46238 if (typeof(Roo.htmleditor.Block.cache[id]) != 'undefined') {
46239 Roo.htmleditor.Block.cache[id].readElement();
46240 return Roo.htmleditor.Block.cache[id];
46243 var cls = Roo.htmleditor['Block' + Roo.get(node).attr('data-block')];
46244 if (typeof(cls) == 'undefined') {
46245 Roo.log("OOps missing block : " + 'Block' + Roo.get(node).attr('data-block'));
46248 Roo.htmleditor.Block.cache[id] = new cls({ node: node });
46249 return Roo.htmleditor.Block.cache[id]; /// should trigger update element
46251 // question goes here... do we need to clear out this cache sometimes?
46252 // or show we make it relivant to the htmleditor.
46253 Roo.htmleditor.Block.cache = {};
46255 Roo.htmleditor.Block.prototype = {
46259 // used by context menu
46260 friendly_name : 'Image with caption',
46264 * Update a node with values from this object
46265 * @param {DomElement} node
46267 updateElement : function(node)
46269 Roo.DomHelper.update(node === undefined ? this.node : node, this.toObject());
46272 * convert to plain HTML for calling insertAtCursor..
46274 toHTML : function()
46276 return Roo.DomHelper.markup(this.toObject());
46279 * used by readEleemnt to extract data from a node
46280 * may need improving as it's pretty basic
46282 * @param {DomElement} node
46283 * @param {String} tag - tag to find, eg. IMG ?? might be better to use DomQuery ?
46284 * @param {String} attribute (use html - for contents, or style for using next param as style)
46285 * @param {String} style the style property - eg. text-align
46287 getVal : function(node, tag, attr, style)
46290 if (tag !== true && n.tagName != tag.toUpperCase()) {
46291 // in theory we could do figure[3] << 3rd figure? or some more complex search..?
46292 // but kiss for now.
46293 n = node.getElementsByTagName(tag).item(0);
46295 if (attr == 'html') {
46296 return n.innerHTML;
46298 if (attr == 'style') {
46299 return Roo.get(n).getStyle(style);
46302 return Roo.get(n).attr(attr);
46306 * create a DomHelper friendly object - for use with
46307 * Roo.DomHelper.markup / overwrite / etc..
46310 toObject : function()
46315 * Read a node that has a 'data-block' property - and extract the values from it.
46316 * @param {DomElement} node - the node
46318 readElement : function(node)
46329 * @class Roo.htmleditor.BlockFigure
46330 * Block that has an image and a figcaption
46331 * @cfg {String} image_src the url for the image
46332 * @cfg {String} align (left|right) alignment for the block default left
46333 * @cfg {String} text_align (left|right) alignment for the text caption default left.
46334 * @cfg {String} caption the text to appear below (and in the alt tag)
46335 * @cfg {String|number} image_width the width of the image number or %?
46336 * @cfg {String|number} image_height the height of the image number or %?
46339 * Create a new Filter.
46340 * @param {Object} config Configuration options
46343 Roo.htmleditor.BlockFigure = function(cfg)
46346 this.readElement(cfg.node);
46347 this.updateElement(cfg.node);
46349 Roo.apply(this, cfg);
46351 Roo.extend(Roo.htmleditor.BlockFigure, Roo.htmleditor.Block, {
46359 text_align: 'left',
46364 // used by context menu
46365 friendly_name : 'Image with caption',
46367 context : { // ?? static really
46380 opts : [[ "left"],[ "right"]],
46385 title: "Caption Align",
46386 opts : [ [ "left"],[ "right"],[ "center"]],
46397 * create a DomHelper friendly object - for use with
46398 * Roo.DomHelper.markup / overwrite / etc..
46400 toObject : function()
46402 var d = document.createElement('div');
46403 d.innerHTML = this.caption;
46407 'data-block' : 'Figure',
46408 contenteditable : 'false',
46411 float : this.align ,
46412 width : this.width,
46413 margin: this.margin
46418 src : this.image_src,
46419 alt : d.innerText.replace(/\n/g, " "), // removeHTML..
46426 contenteditable : true,
46428 'text-align': this.text_align
46430 html : this.caption
46437 readElement : function(node)
46439 this.image_src = this.getVal(node, 'img', 'src');
46440 this.align = this.getVal(node, 'figure', 'style', 'float');
46441 this.caption = this.getVal(node, 'figcaption', 'html');
46442 this.text_align = this.getVal(node, 'figcaption', 'style','text-align');
46443 this.width = this.getVal(node, 'figure', 'style', 'width');
46444 this.margin = this.getVal(node, 'figure', 'style', 'margin');
46457 //<script type="text/javascript">
46460 * Based Ext JS Library 1.1.1
46461 * Copyright(c) 2006-2007, Ext JS, LLC.
46467 * @class Roo.HtmlEditorCore
46468 * @extends Roo.Component
46469 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
46471 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
46474 Roo.HtmlEditorCore = function(config){
46477 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
46482 * @event initialize
46483 * Fires when the editor is fully initialized (including the iframe)
46484 * @param {Roo.HtmlEditorCore} this
46489 * Fires when the editor is first receives the focus. Any insertion must wait
46490 * until after this event.
46491 * @param {Roo.HtmlEditorCore} this
46495 * @event beforesync
46496 * Fires before the textarea is updated with content from the editor iframe. Return false
46497 * to cancel the sync.
46498 * @param {Roo.HtmlEditorCore} this
46499 * @param {String} html
46503 * @event beforepush
46504 * Fires before the iframe editor is updated with content from the textarea. Return false
46505 * to cancel the push.
46506 * @param {Roo.HtmlEditorCore} this
46507 * @param {String} html
46512 * Fires when the textarea is updated with content from the editor iframe.
46513 * @param {Roo.HtmlEditorCore} this
46514 * @param {String} html
46519 * Fires when the iframe editor is updated with content from the textarea.
46520 * @param {Roo.HtmlEditorCore} this
46521 * @param {String} html
46526 * @event editorevent
46527 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
46528 * @param {Roo.HtmlEditorCore} this
46534 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
46536 // defaults : white / black...
46537 this.applyBlacklists();
46544 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
46548 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
46554 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
46559 * @cfg {Number} height (in pixels)
46563 * @cfg {Number} width (in pixels)
46568 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
46571 stylesheets: false,
46574 * @cfg {boolean} allowComments - default false - allow comments in HTML source - by default they are stripped - if you are editing email you may need this.
46576 allowComments: false,
46580 // private properties
46581 validationEvent : false,
46583 initialized : false,
46585 sourceEditMode : false,
46586 onFocus : Roo.emptyFn,
46588 hideMode:'offsets',
46592 // blacklist + whitelisted elements..
46599 * Protected method that will not generally be called directly. It
46600 * is called when the editor initializes the iframe with HTML contents. Override this method if you
46601 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
46603 getDocMarkup : function(){
46607 // inherit styels from page...??
46608 if (this.stylesheets === false) {
46610 Roo.get(document.head).select('style').each(function(node) {
46611 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
46614 Roo.get(document.head).select('link').each(function(node) {
46615 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
46618 } else if (!this.stylesheets.length) {
46620 st = '<style type="text/css">' +
46621 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
46624 for (var i in this.stylesheets) {
46625 if (typeof(this.stylesheets[i]) != 'string') {
46628 st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
46633 st += '<style type="text/css">' +
46634 'IMG { cursor: pointer } ' +
46637 var cls = 'roo-htmleditor-body';
46639 if(this.bodyCls.length){
46640 cls += ' ' + this.bodyCls;
46643 return '<html><head>' + st +
46644 //<style type="text/css">' +
46645 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
46647 ' </head><body contenteditable="true" data-enable-grammerly="true" class="' + cls + '"></body></html>';
46651 onRender : function(ct, position)
46654 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
46655 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
46658 this.el.dom.style.border = '0 none';
46659 this.el.dom.setAttribute('tabIndex', -1);
46660 this.el.addClass('x-hidden hide');
46664 if(Roo.isIE){ // fix IE 1px bogus margin
46665 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
46669 this.frameId = Roo.id();
46673 var iframe = this.owner.wrap.createChild({
46675 cls: 'form-control', // bootstrap..
46677 name: this.frameId,
46678 frameBorder : 'no',
46679 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
46684 this.iframe = iframe.dom;
46686 this.assignDocWin();
46688 this.doc.designMode = 'on';
46691 this.doc.write(this.getDocMarkup());
46695 var task = { // must defer to wait for browser to be ready
46697 //console.log("run task?" + this.doc.readyState);
46698 this.assignDocWin();
46699 if(this.doc.body || this.doc.readyState == 'complete'){
46701 this.doc.designMode="on";
46705 Roo.TaskMgr.stop(task);
46706 this.initEditor.defer(10, this);
46713 Roo.TaskMgr.start(task);
46718 onResize : function(w, h)
46720 Roo.log('resize: ' +w + ',' + h );
46721 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
46725 if(typeof w == 'number'){
46727 this.iframe.style.width = w + 'px';
46729 if(typeof h == 'number'){
46731 this.iframe.style.height = h + 'px';
46733 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
46740 * Toggles the editor between standard and source edit mode.
46741 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
46743 toggleSourceEdit : function(sourceEditMode){
46745 this.sourceEditMode = sourceEditMode === true;
46747 if(this.sourceEditMode){
46749 Roo.get(this.iframe).addClass(['x-hidden','hide', 'd-none']); //FIXME - what's the BS styles for these
46752 Roo.get(this.iframe).removeClass(['x-hidden','hide', 'd-none']);
46753 //this.iframe.className = '';
46756 //this.setSize(this.owner.wrap.getSize());
46757 //this.fireEvent('editmodechange', this, this.sourceEditMode);
46764 * Protected method that will not generally be called directly. If you need/want
46765 * custom HTML cleanup, this is the method you should override.
46766 * @param {String} html The HTML to be cleaned
46767 * return {String} The cleaned HTML
46769 cleanHtml : function(html){
46770 html = String(html);
46771 if(html.length > 5){
46772 if(Roo.isSafari){ // strip safari nonsense
46773 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
46776 if(html == ' '){
46783 * HTML Editor -> Textarea
46784 * Protected method that will not generally be called directly. Syncs the contents
46785 * of the editor iframe with the textarea.
46787 syncValue : function()
46789 Roo.log("HtmlEditorCore:syncValue (EDITOR->TEXT)");
46790 if(this.initialized){
46791 var bd = (this.doc.body || this.doc.documentElement);
46792 //this.cleanUpPaste(); -- this is done else where and causes havoc..
46794 // not sure if this is really the place for this
46795 // the blocks are synced occasionaly - since we currently dont add listeners on the blocks
46796 // this has to update attributes that get duped.. like alt and caption..
46799 //Roo.each(Roo.get(this.doc.body).query('*[data-block]'), function(e) {
46800 // Roo.htmleditor.Block.factory(e);
46804 var div = document.createElement('div');
46805 div.innerHTML = bd.innerHTML;
46806 // remove content editable. (blocks)
46809 new Roo.htmleditor.FilterAttributes({node : div, attrib_black: [ 'contenteditable' ] });
46811 var html = div.innerHTML;
46813 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
46814 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
46816 html = '<div style="'+m[0]+'">' + html + '</div>';
46819 html = this.cleanHtml(html);
46820 // fix up the special chars.. normaly like back quotes in word...
46821 // however we do not want to do this with chinese..
46822 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
46824 var cc = match.charCodeAt();
46826 // Get the character value, handling surrogate pairs
46827 if (match.length == 2) {
46828 // It's a surrogate pair, calculate the Unicode code point
46829 var high = match.charCodeAt(0) - 0xD800;
46830 var low = match.charCodeAt(1) - 0xDC00;
46831 cc = (high * 0x400) + low + 0x10000;
46833 (cc >= 0x4E00 && cc < 0xA000 ) ||
46834 (cc >= 0x3400 && cc < 0x4E00 ) ||
46835 (cc >= 0xf900 && cc < 0xfb00 )
46840 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
46841 return "&#" + cc + ";";
46848 if(this.owner.fireEvent('beforesync', this, html) !== false){
46849 this.el.dom.value = html;
46850 this.owner.fireEvent('sync', this, html);
46856 * TEXTAREA -> EDITABLE
46857 * Protected method that will not generally be called directly. Pushes the value of the textarea
46858 * into the iframe editor.
46860 pushValue : function()
46862 Roo.log("HtmlEditorCore:pushValue (TEXT->EDITOR)");
46863 if(this.initialized){
46864 var v = this.el.dom.value.trim();
46867 if(this.owner.fireEvent('beforepush', this, v) !== false){
46868 var d = (this.doc.body || this.doc.documentElement);
46871 this.el.dom.value = d.innerHTML;
46872 this.owner.fireEvent('push', this, v);
46875 Roo.each(Roo.get(this.doc.body).query('*[data-block]'), function(e) {
46877 Roo.htmleditor.Block.factory(e);
46880 var lc = this.doc.body.lastChild;
46881 if (lc && lc.nodeType == 1 && lc.getAttribute("contenteditable") == "false") {
46882 // add an extra line at the end.
46883 this.doc.body.appendChild(this.doc.createElement('br'));
46891 deferFocus : function(){
46892 this.focus.defer(10, this);
46896 focus : function(){
46897 if(this.win && !this.sourceEditMode){
46904 assignDocWin: function()
46906 var iframe = this.iframe;
46909 this.doc = iframe.contentWindow.document;
46910 this.win = iframe.contentWindow;
46912 // if (!Roo.get(this.frameId)) {
46915 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
46916 // this.win = Roo.get(this.frameId).dom.contentWindow;
46918 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
46922 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
46923 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
46928 initEditor : function(){
46929 //console.log("INIT EDITOR");
46930 this.assignDocWin();
46934 this.doc.designMode="on";
46936 this.doc.write(this.getDocMarkup());
46939 var dbody = (this.doc.body || this.doc.documentElement);
46940 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
46941 // this copies styles from the containing element into thsi one..
46942 // not sure why we need all of this..
46943 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
46945 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
46946 //ss['background-attachment'] = 'fixed'; // w3c
46947 dbody.bgProperties = 'fixed'; // ie
46948 //Roo.DomHelper.applyStyles(dbody, ss);
46949 Roo.EventManager.on(this.doc, {
46950 //'mousedown': this.onEditorEvent,
46951 'mouseup': this.onEditorEvent,
46952 'dblclick': this.onEditorEvent,
46953 'click': this.onEditorEvent,
46954 'keyup': this.onEditorEvent,
46959 Roo.EventManager.on(this.doc, {
46960 'paste': this.onPasteEvent,
46964 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
46966 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
46967 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
46969 this.initialized = true;
46972 // initialize special key events - enter
46973 new Roo.htmleditor.KeyEnter({core : this});
46977 this.owner.fireEvent('initialize', this);
46981 onPasteEvent : function(e,v)
46983 // I think we better assume paste is going to be a dirty load of rubish from word..
46985 // even pasting into a 'email version' of this widget will have to clean up that mess.
46986 var cd = (e.browserEvent.clipboardData || window.clipboardData);
46988 // check what type of paste - if it's an image, then handle it differently.
46989 if (cd.files.length > 0) {
46991 var urlAPI = (window.createObjectURL && window) ||
46992 (window.URL && URL.revokeObjectURL && URL) ||
46993 (window.webkitURL && webkitURL);
46995 var url = urlAPI.createObjectURL( cd.files[0]);
46996 this.insertAtCursor('<img src=" + url + ">');
47000 var html = cd.getData('text/html'); // clipboard event
47001 var parser = new Roo.rtf.Parser(cd.getData('text/rtf'));
47002 var images = parser.doc.getElementsByType('pict');
47006 images = images.filter(function(g) { return !g.path.match(/^rtf\/(head|pgdsctbl|listtable)/); }) // ignore headers
47007 .map(function(g) { return g.toDataURL(); });
47010 html = this.cleanWordChars(html);
47012 var d = (new DOMParser().parseFromString(html, 'text/html')).body;
47014 if (images.length > 0) {
47015 Roo.each(d.getElementsByTagName('img'), function(img, i) {
47016 img.setAttribute('src', images[i]);
47021 new Roo.htmleditor.FilterStyleToTag({ node : d });
47022 new Roo.htmleditor.FilterAttributes({
47024 attrib_white : ['href', 'src', 'name', 'align'],
47025 attrib_clean : ['href', 'src' ]
47027 new Roo.htmleditor.FilterBlack({ node : d, tag : this.black});
47028 // should be fonts..
47029 new Roo.htmleditor.FilterKeepChildren({node : d, tag : [ 'FONT' ]} );
47030 new Roo.htmleditor.FilterParagraph({ node : d });
47031 new Roo.htmleditor.FilterSpan({ node : d });
47032 new Roo.htmleditor.FilterLongBr({ node : d });
47036 this.insertAtCursor(d.innerHTML);
47038 e.preventDefault();
47040 // default behaveiour should be our local cleanup paste? (optional?)
47041 // for simple editor - we want to hammer the paste and get rid of everything... - so over-rideable..
47042 //this.owner.fireEvent('paste', e, v);
47045 onDestroy : function(){
47051 //for (var i =0; i < this.toolbars.length;i++) {
47052 // // fixme - ask toolbars for heights?
47053 // this.toolbars[i].onDestroy();
47056 //this.wrap.dom.innerHTML = '';
47057 //this.wrap.remove();
47062 onFirstFocus : function(){
47064 this.assignDocWin();
47067 this.activated = true;
47070 if(Roo.isGecko){ // prevent silly gecko errors
47072 var s = this.win.getSelection();
47073 if(!s.focusNode || s.focusNode.nodeType != 3){
47074 var r = s.getRangeAt(0);
47075 r.selectNodeContents((this.doc.body || this.doc.documentElement));
47080 this.execCmd('useCSS', true);
47081 this.execCmd('styleWithCSS', false);
47084 this.owner.fireEvent('activate', this);
47088 adjustFont: function(btn){
47089 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
47090 //if(Roo.isSafari){ // safari
47093 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
47094 if(Roo.isSafari){ // safari
47095 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
47096 v = (v < 10) ? 10 : v;
47097 v = (v > 48) ? 48 : v;
47098 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
47103 v = Math.max(1, v+adjust);
47105 this.execCmd('FontSize', v );
47108 onEditorEvent : function(e)
47110 this.owner.fireEvent('editorevent', this, e);
47111 // this.updateToolbar();
47112 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
47115 insertTag : function(tg)
47117 // could be a bit smarter... -> wrap the current selected tRoo..
47118 if (tg.toLowerCase() == 'span' ||
47119 tg.toLowerCase() == 'code' ||
47120 tg.toLowerCase() == 'sup' ||
47121 tg.toLowerCase() == 'sub'
47124 range = this.createRange(this.getSelection());
47125 var wrappingNode = this.doc.createElement(tg.toLowerCase());
47126 wrappingNode.appendChild(range.extractContents());
47127 range.insertNode(wrappingNode);
47134 this.execCmd("formatblock", tg);
47138 insertText : function(txt)
47142 var range = this.createRange();
47143 range.deleteContents();
47144 //alert(Sender.getAttribute('label'));
47146 range.insertNode(this.doc.createTextNode(txt));
47152 * Executes a Midas editor command on the editor document and performs necessary focus and
47153 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
47154 * @param {String} cmd The Midas command
47155 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
47157 relayCmd : function(cmd, value){
47159 this.execCmd(cmd, value);
47160 this.owner.fireEvent('editorevent', this);
47161 //this.updateToolbar();
47162 this.owner.deferFocus();
47166 * Executes a Midas editor command directly on the editor document.
47167 * For visual commands, you should use {@link #relayCmd} instead.
47168 * <b>This should only be called after the editor is initialized.</b>
47169 * @param {String} cmd The Midas command
47170 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
47172 execCmd : function(cmd, value){
47173 this.doc.execCommand(cmd, false, value === undefined ? null : value);
47180 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
47182 * @param {String} text | dom node..
47184 insertAtCursor : function(text)
47187 if(!this.activated){
47191 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
47195 // from jquery ui (MIT licenced)
47197 var win = this.win;
47199 if (win.getSelection && win.getSelection().getRangeAt) {
47201 // delete the existing?
47203 this.createRange(this.getSelection()).deleteContents();
47204 range = win.getSelection().getRangeAt(0);
47205 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
47206 range.insertNode(node);
47207 } else if (win.document.selection && win.document.selection.createRange) {
47208 // no firefox support
47209 var txt = typeof(text) == 'string' ? text : text.outerHTML;
47210 win.document.selection.createRange().pasteHTML(txt);
47212 // no firefox support
47213 var txt = typeof(text) == 'string' ? text : text.outerHTML;
47214 this.execCmd('InsertHTML', txt);
47223 mozKeyPress : function(e){
47225 var c = e.getCharCode(), cmd;
47228 c = String.fromCharCode(c).toLowerCase();
47242 // this.cleanUpPaste.defer(100, this);
47250 e.preventDefault();
47258 fixKeys : function(){ // load time branching for fastest keydown performance
47260 return function(e){
47261 var k = e.getKey(), r;
47264 r = this.doc.selection.createRange();
47267 r.pasteHTML('    ');
47274 r = this.doc.selection.createRange();
47276 var target = r.parentElement();
47277 if(!target || target.tagName.toLowerCase() != 'li'){
47279 r.pasteHTML('<br/>');
47285 //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
47286 // this.cleanUpPaste.defer(100, this);
47292 }else if(Roo.isOpera){
47293 return function(e){
47294 var k = e.getKey();
47298 this.execCmd('InsertHTML','    ');
47301 //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
47302 // this.cleanUpPaste.defer(100, this);
47307 }else if(Roo.isSafari){
47308 return function(e){
47309 var k = e.getKey();
47313 this.execCmd('InsertText','\t');
47317 //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
47318 // this.cleanUpPaste.defer(100, this);
47326 getAllAncestors: function()
47328 var p = this.getSelectedNode();
47331 a.push(p); // push blank onto stack..
47332 p = this.getParentElement();
47336 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
47340 a.push(this.doc.body);
47344 lastSelNode : false,
47347 getSelection : function()
47349 this.assignDocWin();
47350 return Roo.isIE ? this.doc.selection : this.win.getSelection();
47353 * Select a dom node
47354 * @param {DomElement} node the node to select
47356 selectNode : function(node)
47359 var nodeRange = node.ownerDocument.createRange();
47361 nodeRange.selectNode(node);
47363 nodeRange.selectNodeContents(node);
47365 //nodeRange.collapse(true);
47366 var s = this.win.getSelection();
47367 s.removeAllRanges();
47368 s.addRange(nodeRange);
47371 getSelectedNode: function()
47373 // this may only work on Gecko!!!
47375 // should we cache this!!!!
47380 var range = this.createRange(this.getSelection()).cloneRange();
47383 var parent = range.parentElement();
47385 var testRange = range.duplicate();
47386 testRange.moveToElementText(parent);
47387 if (testRange.inRange(range)) {
47390 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
47393 parent = parent.parentElement;
47398 // is ancestor a text element.
47399 var ac = range.commonAncestorContainer;
47400 if (ac.nodeType == 3) {
47401 ac = ac.parentNode;
47404 var ar = ac.childNodes;
47407 var other_nodes = [];
47408 var has_other_nodes = false;
47409 for (var i=0;i<ar.length;i++) {
47410 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
47413 // fullly contained node.
47415 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
47420 // probably selected..
47421 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
47422 other_nodes.push(ar[i]);
47426 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
47431 has_other_nodes = true;
47433 if (!nodes.length && other_nodes.length) {
47434 nodes= other_nodes;
47436 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
47442 createRange: function(sel)
47444 // this has strange effects when using with
47445 // top toolbar - not sure if it's a great idea.
47446 //this.editor.contentWindow.focus();
47447 if (typeof sel != "undefined") {
47449 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
47451 return this.doc.createRange();
47454 return this.doc.createRange();
47457 getParentElement: function()
47460 this.assignDocWin();
47461 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
47463 var range = this.createRange(sel);
47466 var p = range.commonAncestorContainer;
47467 while (p.nodeType == 3) { // text node
47478 * Range intersection.. the hard stuff...
47482 * [ -- selected range --- ]
47486 * if end is before start or hits it. fail.
47487 * if start is after end or hits it fail.
47489 * if either hits (but other is outside. - then it's not
47495 // @see http://www.thismuchiknow.co.uk/?p=64.
47496 rangeIntersectsNode : function(range, node)
47498 var nodeRange = node.ownerDocument.createRange();
47500 nodeRange.selectNode(node);
47502 nodeRange.selectNodeContents(node);
47505 var rangeStartRange = range.cloneRange();
47506 rangeStartRange.collapse(true);
47508 var rangeEndRange = range.cloneRange();
47509 rangeEndRange.collapse(false);
47511 var nodeStartRange = nodeRange.cloneRange();
47512 nodeStartRange.collapse(true);
47514 var nodeEndRange = nodeRange.cloneRange();
47515 nodeEndRange.collapse(false);
47517 return rangeStartRange.compareBoundaryPoints(
47518 Range.START_TO_START, nodeEndRange) == -1 &&
47519 rangeEndRange.compareBoundaryPoints(
47520 Range.START_TO_START, nodeStartRange) == 1;
47524 rangeCompareNode : function(range, node)
47526 var nodeRange = node.ownerDocument.createRange();
47528 nodeRange.selectNode(node);
47530 nodeRange.selectNodeContents(node);
47534 range.collapse(true);
47536 nodeRange.collapse(true);
47538 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
47539 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
47541 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
47543 var nodeIsBefore = ss == 1;
47544 var nodeIsAfter = ee == -1;
47546 if (nodeIsBefore && nodeIsAfter) {
47549 if (!nodeIsBefore && nodeIsAfter) {
47550 return 1; //right trailed.
47553 if (nodeIsBefore && !nodeIsAfter) {
47554 return 2; // left trailed.
47560 cleanWordChars : function(input) {// change the chars to hex code
47563 [ 8211, "–" ],
47564 [ 8212, "—" ],
47572 var output = input;
47573 Roo.each(swapCodes, function(sw) {
47574 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
47576 output = output.replace(swapper, sw[1]);
47586 cleanUpChild : function (node)
47589 new Roo.htmleditor.FilterComment({node : node});
47590 new Roo.htmleditor.FilterAttributes({
47592 attrib_black : this.ablack,
47593 attrib_clean : this.aclean,
47594 style_white : this.cwhite,
47595 style_black : this.cblack
47597 new Roo.htmleditor.FilterBlack({ node : node, tag : this.black});
47598 new Roo.htmleditor.FilterKeepChildren({node : node, tag : this.tag_remove} );
47604 * Clean up MS wordisms...
47605 * @deprecated - use filter directly
47607 cleanWord : function(node)
47609 new Roo.htmleditor.FilterWord({ node : node ? node : this.doc.body });
47616 * @deprecated - use filters
47618 cleanTableWidths : function(node)
47620 new Roo.htmleditor.FilterTableWidth({ node : node ? node : this.doc.body});
47627 applyBlacklists : function()
47629 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
47630 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
47632 this.aclean = typeof(this.owner.aclean) != 'undefined' && this.owner.aclean ? this.owner.aclean : Roo.HtmlEditorCore.aclean;
47633 this.ablack = typeof(this.owner.ablack) != 'undefined' && this.owner.ablack ? this.owner.ablack : Roo.HtmlEditorCore.ablack;
47634 this.tag_remove = typeof(this.owner.tag_remove) != 'undefined' && this.owner.tag_remove ? this.owner.tag_remove : Roo.HtmlEditorCore.tag_remove;
47638 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
47639 if (b.indexOf(tag) > -1) {
47642 this.white.push(tag);
47646 Roo.each(w, function(tag) {
47647 if (b.indexOf(tag) > -1) {
47650 if (this.white.indexOf(tag) > -1) {
47653 this.white.push(tag);
47658 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
47659 if (w.indexOf(tag) > -1) {
47662 this.black.push(tag);
47666 Roo.each(b, function(tag) {
47667 if (w.indexOf(tag) > -1) {
47670 if (this.black.indexOf(tag) > -1) {
47673 this.black.push(tag);
47678 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
47679 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
47683 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
47684 if (b.indexOf(tag) > -1) {
47687 this.cwhite.push(tag);
47691 Roo.each(w, function(tag) {
47692 if (b.indexOf(tag) > -1) {
47695 if (this.cwhite.indexOf(tag) > -1) {
47698 this.cwhite.push(tag);
47703 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
47704 if (w.indexOf(tag) > -1) {
47707 this.cblack.push(tag);
47711 Roo.each(b, function(tag) {
47712 if (w.indexOf(tag) > -1) {
47715 if (this.cblack.indexOf(tag) > -1) {
47718 this.cblack.push(tag);
47723 setStylesheets : function(stylesheets)
47725 if(typeof(stylesheets) == 'string'){
47726 Roo.get(this.iframe.contentDocument.head).createChild({
47728 rel : 'stylesheet',
47737 Roo.each(stylesheets, function(s) {
47742 Roo.get(_this.iframe.contentDocument.head).createChild({
47744 rel : 'stylesheet',
47753 removeStylesheets : function()
47757 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
47762 setStyle : function(style)
47764 Roo.get(this.iframe.contentDocument.head).createChild({
47773 // hide stuff that is not compatible
47787 * @event specialkey
47791 * @cfg {String} fieldClass @hide
47794 * @cfg {String} focusClass @hide
47797 * @cfg {String} autoCreate @hide
47800 * @cfg {String} inputType @hide
47803 * @cfg {String} invalidClass @hide
47806 * @cfg {String} invalidText @hide
47809 * @cfg {String} msgFx @hide
47812 * @cfg {String} validateOnBlur @hide
47816 Roo.HtmlEditorCore.white = [
47817 'AREA', 'BR', 'IMG', 'INPUT', 'HR', 'WBR',
47819 'ADDRESS', 'BLOCKQUOTE', 'CENTER', 'DD', 'DIR', 'DIV',
47820 'DL', 'DT', 'H1', 'H2', 'H3', 'H4',
47821 'H5', 'H6', 'HR', 'ISINDEX', 'LISTING', 'MARQUEE',
47822 'MENU', 'MULTICOL', 'OL', 'P', 'PLAINTEXT', 'PRE',
47823 'TABLE', 'UL', 'XMP',
47825 'CAPTION', 'COL', 'COLGROUP', 'TBODY', 'TD', 'TFOOT', 'TH',
47828 'DIR', 'MENU', 'OL', 'UL', 'DL',
47834 Roo.HtmlEditorCore.black = [
47835 // 'embed', 'object', // enable - backend responsiblity to clean thiese
47837 'BASE', 'BASEFONT', 'BGSOUND', 'BLINK', 'BODY',
47838 'FRAME', 'FRAMESET', 'HEAD', 'HTML', 'ILAYER',
47839 'IFRAME', 'LAYER', 'LINK', 'META', 'OBJECT',
47840 'SCRIPT', 'STYLE' ,'TITLE', 'XML',
47841 //'FONT' // CLEAN LATER..
47842 'COLGROUP', 'COL' // messy tables.
47845 Roo.HtmlEditorCore.clean = [ // ?? needed???
47846 'SCRIPT', 'STYLE', 'TITLE', 'XML'
47848 Roo.HtmlEditorCore.tag_remove = [
47853 Roo.HtmlEditorCore.ablack = [
47857 Roo.HtmlEditorCore.aclean = [
47858 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
47862 Roo.HtmlEditorCore.pwhite= [
47863 'http', 'https', 'mailto'
47866 // white listed style attributes.
47867 Roo.HtmlEditorCore.cwhite= [
47868 // 'text-align', /// default is to allow most things..
47874 // black listed style attributes.
47875 Roo.HtmlEditorCore.cblack= [
47876 // 'font-size' -- this can be set by the project
47882 //<script type="text/javascript">
47885 * Ext JS Library 1.1.1
47886 * Copyright(c) 2006-2007, Ext JS, LLC.
47892 Roo.form.HtmlEditor = function(config){
47896 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
47898 if (!this.toolbars) {
47899 this.toolbars = [];
47901 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
47907 * @class Roo.form.HtmlEditor
47908 * @extends Roo.form.Field
47909 * Provides a lightweight HTML Editor component.
47911 * This has been tested on Fireforx / Chrome.. IE may not be so great..
47913 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
47914 * supported by this editor.</b><br/><br/>
47915 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
47916 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
47918 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
47920 * @cfg {Boolean} clearUp
47924 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
47929 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
47934 * @cfg {Number} height (in pixels)
47938 * @cfg {Number} width (in pixels)
47943 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets - this is usally a good idea rootURL + '/roojs1/css/undoreset.css', .
47946 stylesheets: false,
47950 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
47955 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
47961 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
47966 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
47971 * @cfg {boolean} allowComments - default false - allow comments in HTML source - by default they are stripped - if you are editing email you may need this.
47973 allowComments: false,
47975 * @cfg {string} bodyCls- default '' default classes to add to body of editable area - usually undoreset is a good start..
47984 // private properties
47985 validationEvent : false,
47987 initialized : false,
47990 onFocus : Roo.emptyFn,
47992 hideMode:'offsets',
47994 actionMode : 'container', // defaults to hiding it...
47996 defaultAutoCreate : { // modified by initCompnoent..
47998 style:"width:500px;height:300px;",
47999 autocomplete: "new-password"
48003 initComponent : function(){
48006 * @event initialize
48007 * Fires when the editor is fully initialized (including the iframe)
48008 * @param {HtmlEditor} this
48013 * Fires when the editor is first receives the focus. Any insertion must wait
48014 * until after this event.
48015 * @param {HtmlEditor} this
48019 * @event beforesync
48020 * Fires before the textarea is updated with content from the editor iframe. Return false
48021 * to cancel the sync.
48022 * @param {HtmlEditor} this
48023 * @param {String} html
48027 * @event beforepush
48028 * Fires before the iframe editor is updated with content from the textarea. Return false
48029 * to cancel the push.
48030 * @param {HtmlEditor} this
48031 * @param {String} html
48036 * Fires when the textarea is updated with content from the editor iframe.
48037 * @param {HtmlEditor} this
48038 * @param {String} html
48043 * Fires when the iframe editor is updated with content from the textarea.
48044 * @param {HtmlEditor} this
48045 * @param {String} html
48049 * @event editmodechange
48050 * Fires when the editor switches edit modes
48051 * @param {HtmlEditor} this
48052 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
48054 editmodechange: true,
48056 * @event editorevent
48057 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
48058 * @param {HtmlEditor} this
48062 * @event firstfocus
48063 * Fires when on first focus - needed by toolbars..
48064 * @param {HtmlEditor} this
48069 * Auto save the htmlEditor value as a file into Events
48070 * @param {HtmlEditor} this
48074 * @event savedpreview
48075 * preview the saved version of htmlEditor
48076 * @param {HtmlEditor} this
48078 savedpreview: true,
48081 * @event stylesheetsclick
48082 * Fires when press the Sytlesheets button
48083 * @param {Roo.HtmlEditorCore} this
48085 stylesheetsclick: true,
48088 * Fires when press user pastes into the editor
48089 * @param {Roo.HtmlEditorCore} this
48093 this.defaultAutoCreate = {
48095 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
48096 autocomplete: "new-password"
48101 * Protected method that will not generally be called directly. It
48102 * is called when the editor creates its toolbar. Override this method if you need to
48103 * add custom toolbar buttons.
48104 * @param {HtmlEditor} editor
48106 createToolbar : function(editor){
48107 Roo.log("create toolbars");
48108 if (!editor.toolbars || !editor.toolbars.length) {
48109 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
48112 for (var i =0 ; i < editor.toolbars.length;i++) {
48113 editor.toolbars[i] = Roo.factory(
48114 typeof(editor.toolbars[i]) == 'string' ?
48115 { xtype: editor.toolbars[i]} : editor.toolbars[i],
48116 Roo.form.HtmlEditor);
48117 editor.toolbars[i].init(editor);
48125 onRender : function(ct, position)
48128 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
48130 this.wrap = this.el.wrap({
48131 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
48134 this.editorcore.onRender(ct, position);
48136 if (this.resizable) {
48137 this.resizeEl = new Roo.Resizable(this.wrap, {
48141 minHeight : this.height,
48142 height: this.height,
48143 handles : this.resizable,
48146 resize : function(r, w, h) {
48147 _t.onResize(w,h); // -something
48153 this.createToolbar(this);
48157 this.setSize(this.wrap.getSize());
48159 if (this.resizeEl) {
48160 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
48161 // should trigger onReize..
48164 this.keyNav = new Roo.KeyNav(this.el, {
48166 "tab" : function(e){
48167 e.preventDefault();
48169 var value = this.getValue();
48171 var start = this.el.dom.selectionStart;
48172 var end = this.el.dom.selectionEnd;
48176 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
48177 this.el.dom.setSelectionRange(end + 1, end + 1);
48181 var f = value.substring(0, start).split("\t");
48183 if(f.pop().length != 0){
48187 this.setValue(f.join("\t") + value.substring(end));
48188 this.el.dom.setSelectionRange(start - 1, start - 1);
48192 "home" : function(e){
48193 e.preventDefault();
48195 var curr = this.el.dom.selectionStart;
48196 var lines = this.getValue().split("\n");
48203 this.el.dom.setSelectionRange(0, 0);
48209 for (var i = 0; i < lines.length;i++) {
48210 pos += lines[i].length;
48220 pos -= lines[i].length;
48226 this.el.dom.setSelectionRange(pos, pos);
48230 this.el.dom.selectionStart = pos;
48231 this.el.dom.selectionEnd = curr;
48234 "end" : function(e){
48235 e.preventDefault();
48237 var curr = this.el.dom.selectionStart;
48238 var lines = this.getValue().split("\n");
48245 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
48251 for (var i = 0; i < lines.length;i++) {
48253 pos += lines[i].length;
48267 this.el.dom.setSelectionRange(pos, pos);
48271 this.el.dom.selectionStart = curr;
48272 this.el.dom.selectionEnd = pos;
48277 doRelay : function(foo, bar, hname){
48278 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
48284 // if(this.autosave && this.w){
48285 // this.autoSaveFn = setInterval(this.autosave, 1000);
48290 onResize : function(w, h)
48292 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
48297 if(typeof w == 'number'){
48298 var aw = w - this.wrap.getFrameWidth('lr');
48299 this.el.setWidth(this.adjustWidth('textarea', aw));
48302 if(typeof h == 'number'){
48304 for (var i =0; i < this.toolbars.length;i++) {
48305 // fixme - ask toolbars for heights?
48306 tbh += this.toolbars[i].tb.el.getHeight();
48307 if (this.toolbars[i].footer) {
48308 tbh += this.toolbars[i].footer.el.getHeight();
48315 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
48316 ah -= 5; // knock a few pixes off for look..
48318 this.el.setHeight(this.adjustWidth('textarea', ah));
48322 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
48323 this.editorcore.onResize(ew,eh);
48328 * Toggles the editor between standard and source edit mode.
48329 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
48331 toggleSourceEdit : function(sourceEditMode)
48333 this.editorcore.toggleSourceEdit(sourceEditMode);
48335 if(this.editorcore.sourceEditMode){
48336 Roo.log('editor - showing textarea');
48339 // Roo.log(this.syncValue());
48340 this.editorcore.syncValue();
48341 this.el.removeClass('x-hidden');
48342 this.el.dom.removeAttribute('tabIndex');
48344 this.el.dom.scrollTop = 0;
48347 for (var i = 0; i < this.toolbars.length; i++) {
48348 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
48349 this.toolbars[i].tb.hide();
48350 this.toolbars[i].footer.hide();
48355 Roo.log('editor - hiding textarea');
48357 // Roo.log(this.pushValue());
48358 this.editorcore.pushValue();
48360 this.el.addClass('x-hidden');
48361 this.el.dom.setAttribute('tabIndex', -1);
48363 for (var i = 0; i < this.toolbars.length; i++) {
48364 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
48365 this.toolbars[i].tb.show();
48366 this.toolbars[i].footer.show();
48370 //this.deferFocus();
48373 this.setSize(this.wrap.getSize());
48374 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
48376 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
48379 // private (for BoxComponent)
48380 adjustSize : Roo.BoxComponent.prototype.adjustSize,
48382 // private (for BoxComponent)
48383 getResizeEl : function(){
48387 // private (for BoxComponent)
48388 getPositionEl : function(){
48393 initEvents : function(){
48394 this.originalValue = this.getValue();
48398 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
48401 markInvalid : Roo.emptyFn,
48403 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
48406 clearInvalid : Roo.emptyFn,
48408 setValue : function(v){
48409 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
48410 this.editorcore.pushValue();
48415 deferFocus : function(){
48416 this.focus.defer(10, this);
48420 focus : function(){
48421 this.editorcore.focus();
48427 onDestroy : function(){
48433 for (var i =0; i < this.toolbars.length;i++) {
48434 // fixme - ask toolbars for heights?
48435 this.toolbars[i].onDestroy();
48438 this.wrap.dom.innerHTML = '';
48439 this.wrap.remove();
48444 onFirstFocus : function(){
48445 //Roo.log("onFirstFocus");
48446 this.editorcore.onFirstFocus();
48447 for (var i =0; i < this.toolbars.length;i++) {
48448 this.toolbars[i].onFirstFocus();
48454 syncValue : function()
48456 this.editorcore.syncValue();
48459 pushValue : function()
48461 this.editorcore.pushValue();
48464 setStylesheets : function(stylesheets)
48466 this.editorcore.setStylesheets(stylesheets);
48469 removeStylesheets : function()
48471 this.editorcore.removeStylesheets();
48475 // hide stuff that is not compatible
48489 * @event specialkey
48493 * @cfg {String} fieldClass @hide
48496 * @cfg {String} focusClass @hide
48499 * @cfg {String} autoCreate @hide
48502 * @cfg {String} inputType @hide
48505 * @cfg {String} invalidClass @hide
48508 * @cfg {String} invalidText @hide
48511 * @cfg {String} msgFx @hide
48514 * @cfg {String} validateOnBlur @hide
48518 // <script type="text/javascript">
48521 * Ext JS Library 1.1.1
48522 * Copyright(c) 2006-2007, Ext JS, LLC.
48528 * @class Roo.form.HtmlEditorToolbar1
48533 new Roo.form.HtmlEditor({
48536 new Roo.form.HtmlEditorToolbar1({
48537 disable : { fonts: 1 , format: 1, ..., ... , ...],
48543 * @cfg {Object} disable List of elements to disable..
48544 * @cfg {Array} btns List of additional buttons.
48548 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
48551 Roo.form.HtmlEditor.ToolbarStandard = function(config)
48554 Roo.apply(this, config);
48556 // default disabled, based on 'good practice'..
48557 this.disable = this.disable || {};
48558 Roo.applyIf(this.disable, {
48561 specialElements : true
48565 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
48566 // dont call parent... till later.
48569 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
48576 editorcore : false,
48578 * @cfg {Object} disable List of toolbar elements to disable
48585 * @cfg {String} createLinkText The default text for the create link prompt
48587 createLinkText : 'Please enter the URL for the link:',
48589 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
48591 defaultLinkValue : 'http:/'+'/',
48595 * @cfg {Array} fontFamilies An array of available font families
48613 // "á" , ?? a acute?
48618 "°" // , // degrees
48620 // "é" , // e ecute
48621 // "ú" , // u ecute?
48624 specialElements : [
48626 text: "Insert Table",
48629 ihtml : '<table><tr><td>Cell</td></tr></table>'
48633 text: "Insert Image",
48636 ihtml : '<img src="about:blank"/>'
48645 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
48646 "input:submit", "input:button", "select", "textarea", "label" ],
48649 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
48651 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
48660 * @cfg {String} defaultFont default font to use.
48662 defaultFont: 'tahoma',
48664 fontSelect : false,
48667 formatCombo : false,
48669 init : function(editor)
48671 this.editor = editor;
48672 this.editorcore = editor.editorcore ? editor.editorcore : editor;
48673 var editorcore = this.editorcore;
48677 var fid = editorcore.frameId;
48679 function btn(id, toggle, handler){
48680 var xid = fid + '-'+ id ;
48684 cls : 'x-btn-icon x-edit-'+id,
48685 enableToggle:toggle !== false,
48686 scope: _t, // was editor...
48687 handler:handler||_t.relayBtnCmd,
48688 clickEvent:'mousedown',
48689 tooltip: etb.buttonTips[id] || undefined, ///tips ???
48696 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
48698 // stop form submits
48699 tb.el.on('click', function(e){
48700 e.preventDefault(); // what does this do?
48703 if(!this.disable.font) { // && !Roo.isSafari){
48704 /* why no safari for fonts
48705 editor.fontSelect = tb.el.createChild({
48708 cls:'x-font-select',
48709 html: this.createFontOptions()
48712 editor.fontSelect.on('change', function(){
48713 var font = editor.fontSelect.dom.value;
48714 editor.relayCmd('fontname', font);
48715 editor.deferFocus();
48719 editor.fontSelect.dom,
48725 if(!this.disable.formats){
48726 this.formatCombo = new Roo.form.ComboBox({
48727 store: new Roo.data.SimpleStore({
48730 data : this.formats // from states.js
48734 //autoCreate : {tag: "div", size: "20"},
48735 displayField:'tag',
48739 triggerAction: 'all',
48740 emptyText:'Add tag',
48741 selectOnFocus:true,
48744 'select': function(c, r, i) {
48745 editorcore.insertTag(r.get('tag'));
48751 tb.addField(this.formatCombo);
48755 if(!this.disable.format){
48760 btn('strikethrough')
48763 if(!this.disable.fontSize){
48768 btn('increasefontsize', false, editorcore.adjustFont),
48769 btn('decreasefontsize', false, editorcore.adjustFont)
48774 if(!this.disable.colors){
48777 id:editorcore.frameId +'-forecolor',
48778 cls:'x-btn-icon x-edit-forecolor',
48779 clickEvent:'mousedown',
48780 tooltip: this.buttonTips['forecolor'] || undefined,
48782 menu : new Roo.menu.ColorMenu({
48783 allowReselect: true,
48784 focus: Roo.emptyFn,
48787 selectHandler: function(cp, color){
48788 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
48789 editor.deferFocus();
48792 clickEvent:'mousedown'
48795 id:editorcore.frameId +'backcolor',
48796 cls:'x-btn-icon x-edit-backcolor',
48797 clickEvent:'mousedown',
48798 tooltip: this.buttonTips['backcolor'] || undefined,
48800 menu : new Roo.menu.ColorMenu({
48801 focus: Roo.emptyFn,
48804 allowReselect: true,
48805 selectHandler: function(cp, color){
48807 editorcore.execCmd('useCSS', false);
48808 editorcore.execCmd('hilitecolor', color);
48809 editorcore.execCmd('useCSS', true);
48810 editor.deferFocus();
48812 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
48813 Roo.isSafari || Roo.isIE ? '#'+color : color);
48814 editor.deferFocus();
48818 clickEvent:'mousedown'
48823 // now add all the items...
48826 if(!this.disable.alignments){
48829 btn('justifyleft'),
48830 btn('justifycenter'),
48831 btn('justifyright')
48835 //if(!Roo.isSafari){
48836 if(!this.disable.links){
48839 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
48843 if(!this.disable.lists){
48846 btn('insertorderedlist'),
48847 btn('insertunorderedlist')
48850 if(!this.disable.sourceEdit){
48853 btn('sourceedit', true, function(btn){
48854 this.toggleSourceEdit(btn.pressed);
48861 // special menu.. - needs to be tidied up..
48862 if (!this.disable.special) {
48865 cls: 'x-edit-none',
48871 for (var i =0; i < this.specialChars.length; i++) {
48872 smenu.menu.items.push({
48874 html: this.specialChars[i],
48875 handler: function(a,b) {
48876 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
48877 //editor.insertAtCursor(a.html);
48891 if (!this.disable.cleanStyles) {
48893 cls: 'x-btn-icon x-btn-clear',
48899 for (var i =0; i < this.cleanStyles.length; i++) {
48900 cmenu.menu.items.push({
48901 actiontype : this.cleanStyles[i],
48902 html: 'Remove ' + this.cleanStyles[i],
48903 handler: function(a,b) {
48906 var c = Roo.get(editorcore.doc.body);
48907 c.select('[style]').each(function(s) {
48908 s.dom.style.removeProperty(a.actiontype);
48910 editorcore.syncValue();
48915 cmenu.menu.items.push({
48916 actiontype : 'tablewidths',
48917 html: 'Remove Table Widths',
48918 handler: function(a,b) {
48919 editorcore.cleanTableWidths();
48920 editorcore.syncValue();
48924 cmenu.menu.items.push({
48925 actiontype : 'word',
48926 html: 'Remove MS Word Formating',
48927 handler: function(a,b) {
48928 editorcore.cleanWord();
48929 editorcore.syncValue();
48934 cmenu.menu.items.push({
48935 actiontype : 'all',
48936 html: 'Remove All Styles',
48937 handler: function(a,b) {
48939 var c = Roo.get(editorcore.doc.body);
48940 c.select('[style]').each(function(s) {
48941 s.dom.removeAttribute('style');
48943 editorcore.syncValue();
48948 cmenu.menu.items.push({
48949 actiontype : 'all',
48950 html: 'Remove All CSS Classes',
48951 handler: function(a,b) {
48953 var c = Roo.get(editorcore.doc.body);
48954 c.select('[class]').each(function(s) {
48955 s.dom.removeAttribute('class');
48957 editorcore.cleanWord();
48958 editorcore.syncValue();
48963 cmenu.menu.items.push({
48964 actiontype : 'tidy',
48965 html: 'Tidy HTML Source',
48966 handler: function(a,b) {
48967 new Roo.htmleditor.Tidy(editorcore.doc.body);
48968 editorcore.syncValue();
48977 if (!this.disable.specialElements) {
48980 cls: 'x-edit-none',
48985 for (var i =0; i < this.specialElements.length; i++) {
48986 semenu.menu.items.push(
48988 handler: function(a,b) {
48989 editor.insertAtCursor(this.ihtml);
48991 }, this.specialElements[i])
49003 for(var i =0; i< this.btns.length;i++) {
49004 var b = Roo.factory(this.btns[i],this.btns[i].xns || Roo.form);
49005 b.cls = 'x-edit-none';
49007 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
49008 b.cls += ' x-init-enable';
49011 b.scope = editorcore;
49019 // disable everything...
49021 this.tb.items.each(function(item){
49024 item.id != editorcore.frameId+ '-sourceedit' &&
49025 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
49031 this.rendered = true;
49033 // the all the btns;
49034 editor.on('editorevent', this.updateToolbar, this);
49035 // other toolbars need to implement this..
49036 //editor.on('editmodechange', this.updateToolbar, this);
49040 relayBtnCmd : function(btn) {
49041 this.editorcore.relayCmd(btn.cmd);
49043 // private used internally
49044 createLink : function(){
49045 Roo.log("create link?");
49046 var url = prompt(this.createLinkText, this.defaultLinkValue);
49047 if(url && url != 'http:/'+'/'){
49048 this.editorcore.relayCmd('createlink', url);
49054 * Protected method that will not generally be called directly. It triggers
49055 * a toolbar update by reading the markup state of the current selection in the editor.
49057 updateToolbar: function(){
49059 if(!this.editorcore.activated){
49060 this.editor.onFirstFocus();
49064 var btns = this.tb.items.map,
49065 doc = this.editorcore.doc,
49066 frameId = this.editorcore.frameId;
49068 if(!this.disable.font && !Roo.isSafari){
49070 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
49071 if(name != this.fontSelect.dom.value){
49072 this.fontSelect.dom.value = name;
49076 if(!this.disable.format){
49077 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
49078 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
49079 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
49080 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
49082 if(!this.disable.alignments){
49083 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
49084 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
49085 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
49087 if(!Roo.isSafari && !this.disable.lists){
49088 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
49089 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
49092 var ans = this.editorcore.getAllAncestors();
49093 if (this.formatCombo) {
49096 var store = this.formatCombo.store;
49097 this.formatCombo.setValue("");
49098 for (var i =0; i < ans.length;i++) {
49099 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
49101 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
49109 // hides menus... - so this cant be on a menu...
49110 Roo.menu.MenuMgr.hideAll();
49112 //this.editorsyncValue();
49116 createFontOptions : function(){
49117 var buf = [], fs = this.fontFamilies, ff, lc;
49121 for(var i = 0, len = fs.length; i< len; i++){
49123 lc = ff.toLowerCase();
49125 '<option value="',lc,'" style="font-family:',ff,';"',
49126 (this.defaultFont == lc ? ' selected="true">' : '>'),
49131 return buf.join('');
49134 toggleSourceEdit : function(sourceEditMode){
49136 Roo.log("toolbar toogle");
49137 if(sourceEditMode === undefined){
49138 sourceEditMode = !this.sourceEditMode;
49140 this.sourceEditMode = sourceEditMode === true;
49141 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
49142 // just toggle the button?
49143 if(btn.pressed !== this.sourceEditMode){
49144 btn.toggle(this.sourceEditMode);
49148 if(sourceEditMode){
49149 Roo.log("disabling buttons");
49150 this.tb.items.each(function(item){
49151 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
49157 Roo.log("enabling buttons");
49158 if(this.editorcore.initialized){
49159 this.tb.items.each(function(item){
49165 Roo.log("calling toggole on editor");
49166 // tell the editor that it's been pressed..
49167 this.editor.toggleSourceEdit(sourceEditMode);
49171 * Object collection of toolbar tooltips for the buttons in the editor. The key
49172 * is the command id associated with that button and the value is a valid QuickTips object.
49177 title: 'Bold (Ctrl+B)',
49178 text: 'Make the selected text bold.',
49179 cls: 'x-html-editor-tip'
49182 title: 'Italic (Ctrl+I)',
49183 text: 'Make the selected text italic.',
49184 cls: 'x-html-editor-tip'
49192 title: 'Bold (Ctrl+B)',
49193 text: 'Make the selected text bold.',
49194 cls: 'x-html-editor-tip'
49197 title: 'Italic (Ctrl+I)',
49198 text: 'Make the selected text italic.',
49199 cls: 'x-html-editor-tip'
49202 title: 'Underline (Ctrl+U)',
49203 text: 'Underline the selected text.',
49204 cls: 'x-html-editor-tip'
49207 title: 'Strikethrough',
49208 text: 'Strikethrough the selected text.',
49209 cls: 'x-html-editor-tip'
49211 increasefontsize : {
49212 title: 'Grow Text',
49213 text: 'Increase the font size.',
49214 cls: 'x-html-editor-tip'
49216 decreasefontsize : {
49217 title: 'Shrink Text',
49218 text: 'Decrease the font size.',
49219 cls: 'x-html-editor-tip'
49222 title: 'Text Highlight Color',
49223 text: 'Change the background color of the selected text.',
49224 cls: 'x-html-editor-tip'
49227 title: 'Font Color',
49228 text: 'Change the color of the selected text.',
49229 cls: 'x-html-editor-tip'
49232 title: 'Align Text Left',
49233 text: 'Align text to the left.',
49234 cls: 'x-html-editor-tip'
49237 title: 'Center Text',
49238 text: 'Center text in the editor.',
49239 cls: 'x-html-editor-tip'
49242 title: 'Align Text Right',
49243 text: 'Align text to the right.',
49244 cls: 'x-html-editor-tip'
49246 insertunorderedlist : {
49247 title: 'Bullet List',
49248 text: 'Start a bulleted list.',
49249 cls: 'x-html-editor-tip'
49251 insertorderedlist : {
49252 title: 'Numbered List',
49253 text: 'Start a numbered list.',
49254 cls: 'x-html-editor-tip'
49257 title: 'Hyperlink',
49258 text: 'Make the selected text a hyperlink.',
49259 cls: 'x-html-editor-tip'
49262 title: 'Source Edit',
49263 text: 'Switch to source editing mode.',
49264 cls: 'x-html-editor-tip'
49268 onDestroy : function(){
49271 this.tb.items.each(function(item){
49273 item.menu.removeAll();
49275 item.menu.el.destroy();
49283 onFirstFocus: function() {
49284 this.tb.items.each(function(item){
49293 // <script type="text/javascript">
49296 * Ext JS Library 1.1.1
49297 * Copyright(c) 2006-2007, Ext JS, LLC.
49304 * @class Roo.form.HtmlEditor.ToolbarContext
49309 new Roo.form.HtmlEditor({
49312 { xtype: 'ToolbarStandard', styles : {} }
49313 { xtype: 'ToolbarContext', disable : {} }
49319 * @config : {Object} disable List of elements to disable.. (not done yet.)
49320 * @config : {Object} styles Map of styles available.
49324 Roo.form.HtmlEditor.ToolbarContext = function(config)
49327 Roo.apply(this, config);
49328 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
49329 // dont call parent... till later.
49330 this.styles = this.styles || {};
49335 Roo.form.HtmlEditor.ToolbarContext.types = {
49350 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
49376 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
49447 name : 'selectoptions',
49453 // should we really allow this??
49454 // should this just be
49471 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
49472 Roo.form.HtmlEditor.ToolbarContext.stores = false;
49474 Roo.form.HtmlEditor.ToolbarContext.options = {
49476 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
49477 [ 'Courier New', 'Courier New'],
49478 [ 'Tahoma', 'Tahoma'],
49479 [ 'Times New Roman,serif', 'Times'],
49480 [ 'Verdana','Verdana' ]
49484 // fixme - these need to be configurable..
49487 //Roo.form.HtmlEditor.ToolbarContext.types
49490 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
49497 editorcore : false,
49499 * @cfg {Object} disable List of toolbar elements to disable
49504 * @cfg {Object} styles List of styles
49505 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
49507 * These must be defined in the page, so they get rendered correctly..
49518 init : function(editor)
49520 this.editor = editor;
49521 this.editorcore = editor.editorcore ? editor.editorcore : editor;
49522 var editorcore = this.editorcore;
49524 var fid = editorcore.frameId;
49526 function btn(id, toggle, handler){
49527 var xid = fid + '-'+ id ;
49531 cls : 'x-btn-icon x-edit-'+id,
49532 enableToggle:toggle !== false,
49533 scope: editorcore, // was editor...
49534 handler:handler||editorcore.relayBtnCmd,
49535 clickEvent:'mousedown',
49536 tooltip: etb.buttonTips[id] || undefined, ///tips ???
49540 // create a new element.
49541 var wdiv = editor.wrap.createChild({
49543 }, editor.wrap.dom.firstChild.nextSibling, true);
49545 // can we do this more than once??
49547 // stop form submits
49550 // disable everything...
49551 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
49552 this.toolbars = {};
49554 for (var i in ty) {
49556 this.toolbars[i] = this.buildToolbar(ty[i],i);
49558 this.tb = this.toolbars.BODY;
49560 this.buildFooter();
49561 this.footer.show();
49562 editor.on('hide', function( ) { this.footer.hide() }, this);
49563 editor.on('show', function( ) { this.footer.show() }, this);
49566 this.rendered = true;
49568 // the all the btns;
49569 editor.on('editorevent', this.updateToolbar, this);
49570 // other toolbars need to implement this..
49571 //editor.on('editmodechange', this.updateToolbar, this);
49577 * Protected method that will not generally be called directly. It triggers
49578 * a toolbar update by reading the markup state of the current selection in the editor.
49580 * Note you can force an update by calling on('editorevent', scope, false)
49582 updateToolbar: function(editor ,ev, sel)
49586 ev.stopEvent(); // se if we can stop this looping with mutiple events.
49590 // capture mouse up - this is handy for selecting images..
49591 // perhaps should go somewhere else...
49592 if(!this.editorcore.activated){
49593 this.editor.onFirstFocus();
49596 Roo.log(ev ? ev.target : 'NOTARGET');
49599 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
49600 // selectNode - might want to handle IE?
49605 (ev.type == 'mouseup' || ev.type == 'click' ) &&
49606 ev.target && ev.target.tagName != 'BODY' ) { // && ev.target.tagName == 'IMG') {
49607 // they have click on an image...
49608 // let's see if we can change the selection...
49611 // this triggers looping?
49612 //this.editorcore.selectNode(sel);
49617 //var updateFooter = sel ? false : true;
49620 var ans = this.editorcore.getAllAncestors();
49623 var ty = Roo.form.HtmlEditor.ToolbarContext.types;
49626 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
49627 sel = sel ? sel : this.editorcore.doc.body;
49628 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
49632 var tn = sel.tagName.toUpperCase();
49633 var lastSel = this.tb.selectedNode;
49634 this.tb.selectedNode = sel;
49635 var left_label = tn;
49637 // ok see if we are editing a block?
49638 var sel_el = Roo.get(sel);
49640 // you are not actually selecting the block.
49641 if (sel && sel.hasAttribute('data-block')) {
49643 } else if (sel && !sel.hasAttribute('contenteditable')) {
49644 db = sel_el.findParent('[data-block]');
49645 var cepar = sel_el.findParent('[contenteditable=true]');
49646 if (db && cepar && cepar.tagName != 'BODY') {
49647 db = false; // we are inside an editable block.. = not sure how we are going to handle nested blocks!?
49653 //if (db && !sel.hasAttribute('contenteditable') && sel.getAttribute('contenteditable') != 'true' ) {
49655 block = Roo.htmleditor.Block.factory(db);
49657 tn = 'BLOCK.' + db.getAttribute('data-block');
49659 //this.editorcore.selectNode(db);
49660 if (typeof(this.toolbars[tn]) == 'undefined') {
49661 this.toolbars[tn] = this.buildToolbar( false ,tn ,block.friendly_name, block);
49663 this.toolbars[tn].selectedNode = db;
49664 left_label = block.friendly_name;
49665 ans = this.editorcore.getAllAncestors();
49673 if (this.tb.name == tn && lastSel == this.tb.selectedNode && ev !== false) {
49674 return; // no change?
49680 ///console.log("show: " + tn);
49681 this.tb = typeof(this.toolbars[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
49685 this.tb.items.first().el.innerHTML = left_label + ': ';
49688 // update attributes
49691 this.tb.fields.each(function(e) {
49692 e.setValue(block[e.name]);
49696 } else if (this.tb.fields && this.tb.selectedNode) {
49697 this.tb.fields.each( function(e) {
49699 e.setValue(this.tb.selectedNode.style[e.stylename]);
49702 e.setValue(this.tb.selectedNode.getAttribute(e.attrname));
49704 this.updateToolbarStyles(this.tb.selectedNode);
49709 Roo.menu.MenuMgr.hideAll();
49714 // update the footer
49716 this.updateFooter(ans);
49720 updateToolbarStyles : function(sel)
49722 var hasStyles = false;
49723 for(var i in this.styles) {
49729 if (hasStyles && this.tb.hasStyles) {
49730 var st = this.tb.fields.item(0);
49732 st.store.removeAll();
49733 var cn = sel.className.split(/\s+/);
49736 if (this.styles['*']) {
49738 Roo.each(this.styles['*'], function(v) {
49739 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
49742 if (this.styles[tn]) {
49743 Roo.each(this.styles[tn], function(v) {
49744 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
49748 st.store.loadData(avs);
49755 updateFooter : function(ans)
49758 if (ans === false) {
49759 this.footDisp.dom.innerHTML = '';
49763 this.footerEls = ans.reverse();
49764 Roo.each(this.footerEls, function(a,i) {
49765 if (!a) { return; }
49766 html += html.length ? ' > ' : '';
49768 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
49773 var sz = this.footDisp.up('td').getSize();
49774 this.footDisp.dom.style.width = (sz.width -10) + 'px';
49775 this.footDisp.dom.style.marginLeft = '5px';
49777 this.footDisp.dom.style.overflow = 'hidden';
49779 this.footDisp.dom.innerHTML = html;
49786 onDestroy : function(){
49789 this.tb.items.each(function(item){
49791 item.menu.removeAll();
49793 item.menu.el.destroy();
49801 onFirstFocus: function() {
49802 // need to do this for all the toolbars..
49803 this.tb.items.each(function(item){
49807 buildToolbar: function(tlist, nm, friendly_name, block)
49809 var editor = this.editor;
49810 var editorcore = this.editorcore;
49811 // create a new element.
49812 var wdiv = editor.wrap.createChild({
49814 }, editor.wrap.dom.firstChild.nextSibling, true);
49817 var tb = new Roo.Toolbar(wdiv);
49818 ///this.tb = tb; // << this sets the active toolbar..
49819 if (tlist === false && block) {
49820 tlist = block.contextMenu(this);
49823 tb.hasStyles = false;
49826 tb.add((typeof(friendly_name) == 'undefined' ? nm : friendly_name) + ": ");
49828 var styles = Array.from(this.styles);
49832 if (styles && styles.length) {
49833 tb.hasStyles = true;
49834 // this needs a multi-select checkbox...
49835 tb.addField( new Roo.form.ComboBox({
49836 store: new Roo.data.SimpleStore({
49838 fields: ['val', 'selected'],
49841 name : '-roo-edit-className',
49842 attrname : 'className',
49843 displayField: 'val',
49847 triggerAction: 'all',
49848 emptyText:'Select Style',
49849 selectOnFocus:true,
49852 'select': function(c, r, i) {
49853 // initial support only for on class per el..
49854 tb.selectedNode.className = r ? r.get('val') : '';
49855 editorcore.syncValue();
49862 var tbc = Roo.form.HtmlEditor.ToolbarContext;
49865 for (var i = 0; i < tlist.length; i++) {
49867 // newer versions will use xtype cfg to create menus.
49868 if (typeof(tlist[i].xtype) != 'undefined') {
49870 tb[typeof(tlist[i].name)== 'undefined' ? 'add' : 'addField'](Roo.factory(tlist[i]));
49876 var item = tlist[i];
49877 tb.add(item.title + ": ");
49880 //optname == used so you can configure the options available..
49881 var opts = item.opts ? item.opts : false;
49882 if (item.optname) { // use the b
49883 opts = Roo.form.HtmlEditor.ToolbarContext.options[item.optname];
49888 // opts == pulldown..
49889 tb.addField( new Roo.form.ComboBox({
49890 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
49892 fields: ['val', 'display'],
49895 name : '-roo-edit-' + tlist[i].name,
49897 attrname : tlist[i].name,
49898 stylename : item.style ? item.style : false,
49900 displayField: item.displayField ? item.displayField : 'val',
49901 valueField : 'val',
49903 mode: typeof(tbc.stores[tlist[i].name]) != 'undefined' ? 'remote' : 'local',
49905 triggerAction: 'all',
49906 emptyText:'Select',
49907 selectOnFocus:true,
49908 width: item.width ? item.width : 130,
49910 'select': function(c, r, i) {
49911 if (tb.selectedNode.hasAttribute('data-block')) {
49912 var b = Roo.htmleditor.Block.factory(tb.selectedNode);
49913 b[c.attrname] = r.get('val');
49914 b.updateElement(tb.selectedNode);
49915 editorcore.syncValue();
49920 tb.selectedNode.style[c.stylename] = r.get('val');
49921 editorcore.syncValue();
49925 tb.selectedNode.removeAttribute(c.attrname);
49926 editorcore.syncValue();
49929 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
49930 editorcore.syncValue();
49939 tb.addField( new Roo.form.TextField({
49942 //allowBlank:false,
49948 tb.addField( new Roo.form.TextField({
49949 name: '-roo-edit-' + tlist[i].name,
49950 attrname : tlist[i].name,
49956 'change' : function(f, nv, ov) {
49958 if (tb.selectedNode.hasAttribute('data-block')) {
49959 var b = Roo.htmleditor.Block.factory(tb.selectedNode);
49960 b[f.attrname] = nv;
49961 b.updateElement(tb.selectedNode);
49962 editorcore.syncValue();
49966 tb.selectedNode.setAttribute(f.attrname, nv);
49967 editorcore.syncValue();
49980 text: 'Stylesheets',
49983 click : function ()
49985 _this.editor.fireEvent('stylesheetsclick', _this.editor);
49993 text: 'Remove Block or Formating', // remove the tag, and puts the children outside...
49996 click : function ()
49998 var sn = tb.selectedNode;
50000 sn = Roo.htmleditor.Block.factory(tb.selectedNode).removeNode();
50006 var stn = sn.childNodes[0] || sn.nextSibling || sn.previousSibling || sn.parentNode;
50007 if (sn.hasAttribute('data-block')) {
50008 stn = sn.nextSibling || sn.previousSibling || sn.parentNode;
50009 sn.parentNode.removeChild(sn);
50011 } else if (sn && sn.tagName != 'BODY') {
50012 // remove and keep parents.
50013 a = new Roo.htmleditor.FilterKeepChildren({tag : false});
50018 var range = editorcore.createRange();
50020 range.setStart(stn,0);
50021 range.setEnd(stn,0);
50022 var selection = editorcore.getSelection();
50023 selection.removeAllRanges();
50024 selection.addRange(range);
50027 //_this.updateToolbar(null, null, pn);
50028 _this.updateToolbar(null, null, null);
50029 _this.updateFooter(false);
50040 tb.el.on('click', function(e){
50041 e.preventDefault(); // what does this do?
50043 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
50046 // dont need to disable them... as they will get hidden
50051 buildFooter : function()
50054 var fel = this.editor.wrap.createChild();
50055 this.footer = new Roo.Toolbar(fel);
50056 // toolbar has scrolly on left / right?
50057 var footDisp= new Roo.Toolbar.Fill();
50063 handler : function() {
50064 _t.footDisp.scrollTo('left',0,true)
50068 this.footer.add( footDisp );
50073 handler : function() {
50075 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
50079 var fel = Roo.get(footDisp.el);
50080 fel.addClass('x-editor-context');
50081 this.footDispWrap = fel;
50082 this.footDispWrap.overflow = 'hidden';
50084 this.footDisp = fel.createChild();
50085 this.footDispWrap.on('click', this.onContextClick, this)
50089 // when the footer contect changes
50090 onContextClick : function (ev,dom)
50092 ev.preventDefault();
50093 var cn = dom.className;
50095 if (!cn.match(/x-ed-loc-/)) {
50098 var n = cn.split('-').pop();
50099 var ans = this.footerEls;
50103 var range = this.editorcore.createRange();
50105 range.selectNodeContents(sel);
50106 //range.selectNode(sel);
50109 var selection = this.editorcore.getSelection();
50110 selection.removeAllRanges();
50111 selection.addRange(range);
50115 this.updateToolbar(null, null, sel);
50132 * Ext JS Library 1.1.1
50133 * Copyright(c) 2006-2007, Ext JS, LLC.
50135 * Originally Released Under LGPL - original licence link has changed is not relivant.
50138 * <script type="text/javascript">
50142 * @class Roo.form.BasicForm
50143 * @extends Roo.util.Observable
50144 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
50146 * @param {String/HTMLElement/Roo.Element} el The form element or its id
50147 * @param {Object} config Configuration options
50149 Roo.form.BasicForm = function(el, config){
50150 this.allItems = [];
50151 this.childForms = [];
50152 Roo.apply(this, config);
50154 * The Roo.form.Field items in this form.
50155 * @type MixedCollection
50159 this.items = new Roo.util.MixedCollection(false, function(o){
50160 return o.id || (o.id = Roo.id());
50164 * @event beforeaction
50165 * Fires before any action is performed. Return false to cancel the action.
50166 * @param {Form} this
50167 * @param {Action} action The action to be performed
50169 beforeaction: true,
50171 * @event actionfailed
50172 * Fires when an action fails.
50173 * @param {Form} this
50174 * @param {Action} action The action that failed
50176 actionfailed : true,
50178 * @event actioncomplete
50179 * Fires when an action is completed.
50180 * @param {Form} this
50181 * @param {Action} action The action that completed
50183 actioncomplete : true
50188 Roo.form.BasicForm.superclass.constructor.call(this);
50190 Roo.form.BasicForm.popover.apply();
50193 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
50195 * @cfg {String} method
50196 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
50199 * @cfg {DataReader} reader
50200 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
50201 * This is optional as there is built-in support for processing JSON.
50204 * @cfg {DataReader} errorReader
50205 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
50206 * This is completely optional as there is built-in support for processing JSON.
50209 * @cfg {String} url
50210 * The URL to use for form actions if one isn't supplied in the action options.
50213 * @cfg {Boolean} fileUpload
50214 * Set to true if this form is a file upload.
50218 * @cfg {Object} baseParams
50219 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
50224 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
50229 activeAction : null,
50232 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
50233 * or setValues() data instead of when the form was first created.
50235 trackResetOnLoad : false,
50239 * childForms - used for multi-tab forms
50242 childForms : false,
50245 * allItems - full list of fields.
50251 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
50252 * element by passing it or its id or mask the form itself by passing in true.
50255 waitMsgTarget : false,
50260 disableMask : false,
50263 * @cfg {Boolean} errorMask (true|false) default false
50268 * @cfg {Number} maskOffset Default 100
50273 initEl : function(el){
50274 this.el = Roo.get(el);
50275 this.id = this.el.id || Roo.id();
50276 this.el.on('submit', this.onSubmit, this);
50277 this.el.addClass('x-form');
50281 onSubmit : function(e){
50286 * Returns true if client-side validation on the form is successful.
50289 isValid : function(){
50291 var target = false;
50292 this.items.each(function(f){
50299 if(!target && f.el.isVisible(true)){
50304 if(this.errorMask && !valid){
50305 Roo.form.BasicForm.popover.mask(this, target);
50311 * Returns array of invalid form fields.
50315 invalidFields : function()
50318 this.items.each(function(f){
50331 * DEPRICATED Returns true if any fields in this form have changed since their original load.
50334 isDirty : function(){
50336 this.items.each(function(f){
50346 * Returns true if any fields in this form have changed since their original load. (New version)
50350 hasChanged : function()
50353 this.items.each(function(f){
50354 if(f.hasChanged()){
50363 * Resets all hasChanged to 'false' -
50364 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
50365 * So hasChanged storage is only to be used for this purpose
50368 resetHasChanged : function()
50370 this.items.each(function(f){
50371 f.resetHasChanged();
50378 * Performs a predefined action (submit or load) or custom actions you define on this form.
50379 * @param {String} actionName The name of the action type
50380 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
50381 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
50382 * accept other config options):
50384 Property Type Description
50385 ---------------- --------------- ----------------------------------------------------------------------------------
50386 url String The url for the action (defaults to the form's url)
50387 method String The form method to use (defaults to the form's method, or POST if not defined)
50388 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
50389 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
50390 validate the form on the client (defaults to false)
50392 * @return {BasicForm} this
50394 doAction : function(action, options){
50395 if(typeof action == 'string'){
50396 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
50398 if(this.fireEvent('beforeaction', this, action) !== false){
50399 this.beforeAction(action);
50400 action.run.defer(100, action);
50406 * Shortcut to do a submit action.
50407 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
50408 * @return {BasicForm} this
50410 submit : function(options){
50411 this.doAction('submit', options);
50416 * Shortcut to do a load action.
50417 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
50418 * @return {BasicForm} this
50420 load : function(options){
50421 this.doAction('load', options);
50426 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
50427 * @param {Record} record The record to edit
50428 * @return {BasicForm} this
50430 updateRecord : function(record){
50431 record.beginEdit();
50432 var fs = record.fields;
50433 fs.each(function(f){
50434 var field = this.findField(f.name);
50436 record.set(f.name, field.getValue());
50444 * Loads an Roo.data.Record into this form.
50445 * @param {Record} record The record to load
50446 * @return {BasicForm} this
50448 loadRecord : function(record){
50449 this.setValues(record.data);
50454 beforeAction : function(action){
50455 var o = action.options;
50457 if(!this.disableMask) {
50458 if(this.waitMsgTarget === true){
50459 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
50460 }else if(this.waitMsgTarget){
50461 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
50462 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
50464 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
50472 afterAction : function(action, success){
50473 this.activeAction = null;
50474 var o = action.options;
50476 if(!this.disableMask) {
50477 if(this.waitMsgTarget === true){
50479 }else if(this.waitMsgTarget){
50480 this.waitMsgTarget.unmask();
50482 Roo.MessageBox.updateProgress(1);
50483 Roo.MessageBox.hide();
50491 Roo.callback(o.success, o.scope, [this, action]);
50492 this.fireEvent('actioncomplete', this, action);
50496 // failure condition..
50497 // we have a scenario where updates need confirming.
50498 // eg. if a locking scenario exists..
50499 // we look for { errors : { needs_confirm : true }} in the response.
50501 (typeof(action.result) != 'undefined') &&
50502 (typeof(action.result.errors) != 'undefined') &&
50503 (typeof(action.result.errors.needs_confirm) != 'undefined')
50506 Roo.MessageBox.confirm(
50507 "Change requires confirmation",
50508 action.result.errorMsg,
50513 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
50523 Roo.callback(o.failure, o.scope, [this, action]);
50524 // show an error message if no failed handler is set..
50525 if (!this.hasListener('actionfailed')) {
50526 Roo.MessageBox.alert("Error",
50527 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
50528 action.result.errorMsg :
50529 "Saving Failed, please check your entries or try again"
50533 this.fireEvent('actionfailed', this, action);
50539 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
50540 * @param {String} id The value to search for
50543 findField : function(id){
50544 var field = this.items.get(id);
50546 this.items.each(function(f){
50547 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
50553 return field || null;
50557 * Add a secondary form to this one,
50558 * Used to provide tabbed forms. One form is primary, with hidden values
50559 * which mirror the elements from the other forms.
50561 * @param {Roo.form.Form} form to add.
50564 addForm : function(form)
50567 if (this.childForms.indexOf(form) > -1) {
50571 this.childForms.push(form);
50573 Roo.each(form.allItems, function (fe) {
50575 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
50576 if (this.findField(n)) { // already added..
50579 var add = new Roo.form.Hidden({
50582 add.render(this.el);
50589 * Mark fields in this form invalid in bulk.
50590 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
50591 * @return {BasicForm} this
50593 markInvalid : function(errors){
50594 if(errors instanceof Array){
50595 for(var i = 0, len = errors.length; i < len; i++){
50596 var fieldError = errors[i];
50597 var f = this.findField(fieldError.id);
50599 f.markInvalid(fieldError.msg);
50605 if(typeof errors[id] != 'function' && (field = this.findField(id))){
50606 field.markInvalid(errors[id]);
50610 Roo.each(this.childForms || [], function (f) {
50611 f.markInvalid(errors);
50618 * Set values for fields in this form in bulk.
50619 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
50620 * @return {BasicForm} this
50622 setValues : function(values){
50623 if(values instanceof Array){ // array of objects
50624 for(var i = 0, len = values.length; i < len; i++){
50626 var f = this.findField(v.id);
50628 f.setValue(v.value);
50629 if(this.trackResetOnLoad){
50630 f.originalValue = f.getValue();
50634 }else{ // object hash
50637 if(typeof values[id] != 'function' && (field = this.findField(id))){
50639 if (field.setFromData &&
50640 field.valueField &&
50641 field.displayField &&
50642 // combos' with local stores can
50643 // be queried via setValue()
50644 // to set their value..
50645 (field.store && !field.store.isLocal)
50649 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
50650 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
50651 field.setFromData(sd);
50654 field.setValue(values[id]);
50658 if(this.trackResetOnLoad){
50659 field.originalValue = field.getValue();
50664 this.resetHasChanged();
50667 Roo.each(this.childForms || [], function (f) {
50668 f.setValues(values);
50669 f.resetHasChanged();
50676 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
50677 * they are returned as an array.
50678 * @param {Boolean} asString
50681 getValues : function(asString)
50683 if (this.childForms) {
50684 // copy values from the child forms
50685 Roo.each(this.childForms, function (f) {
50686 this.setValues(f.getFieldValues()); // get the full set of data, as we might be copying comboboxes from external into this one.
50691 if (typeof(FormData) != 'undefined' && asString !== true) {
50692 // this relies on a 'recent' version of chrome apparently...
50694 var fd = (new FormData(this.el.dom)).entries();
50696 var ent = fd.next();
50697 while (!ent.done) {
50698 ret[ent.value[0]] = ent.value[1]; // not sure how this will handle duplicates..
50709 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
50710 if(asString === true){
50713 return Roo.urlDecode(fs);
50717 * Returns the fields in this form as an object with key/value pairs.
50718 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
50721 getFieldValues : function(with_hidden)
50723 if (this.childForms) {
50724 // copy values from the child forms
50725 // should this call getFieldValues - probably not as we do not currently copy
50726 // hidden fields when we generate..
50727 Roo.each(this.childForms, function (f) {
50728 this.setValues(f.getFieldValues());
50733 this.items.each(function(f){
50736 return; // skip read only values. - this is in theory to stop 'old' values being copied over new ones
50737 // if a subform contains a copy of them.
50738 // if you have subforms with the same editable data, you will need to copy the data back
50742 if (!f.getName()) {
50745 var v = f.getValue();
50746 if (f.inputType =='radio') {
50747 if (typeof(ret[f.getName()]) == 'undefined') {
50748 ret[f.getName()] = ''; // empty..
50751 if (!f.el.dom.checked) {
50755 v = f.el.dom.value;
50759 // not sure if this supported any more..
50760 if ((typeof(v) == 'object') && f.getRawValue) {
50761 v = f.getRawValue() ; // dates..
50763 // combo boxes where name != hiddenName...
50764 if (f.name != f.getName()) {
50765 ret[f.name] = f.getRawValue();
50767 ret[f.getName()] = v;
50774 * Clears all invalid messages in this form.
50775 * @return {BasicForm} this
50777 clearInvalid : function(){
50778 this.items.each(function(f){
50782 Roo.each(this.childForms || [], function (f) {
50791 * Resets this form.
50792 * @return {BasicForm} this
50794 reset : function(){
50795 this.items.each(function(f){
50799 Roo.each(this.childForms || [], function (f) {
50802 this.resetHasChanged();
50808 * Add Roo.form components to this form.
50809 * @param {Field} field1
50810 * @param {Field} field2 (optional)
50811 * @param {Field} etc (optional)
50812 * @return {BasicForm} this
50815 this.items.addAll(Array.prototype.slice.call(arguments, 0));
50821 * Removes a field from the items collection (does NOT remove its markup).
50822 * @param {Field} field
50823 * @return {BasicForm} this
50825 remove : function(field){
50826 this.items.remove(field);
50831 * Looks at the fields in this form, checks them for an id attribute,
50832 * and calls applyTo on the existing dom element with that id.
50833 * @return {BasicForm} this
50835 render : function(){
50836 this.items.each(function(f){
50837 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
50845 * Calls {@link Ext#apply} for all fields in this form with the passed object.
50846 * @param {Object} values
50847 * @return {BasicForm} this
50849 applyToFields : function(o){
50850 this.items.each(function(f){
50857 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
50858 * @param {Object} values
50859 * @return {BasicForm} this
50861 applyIfToFields : function(o){
50862 this.items.each(function(f){
50870 Roo.BasicForm = Roo.form.BasicForm;
50872 Roo.apply(Roo.form.BasicForm, {
50886 intervalID : false,
50892 if(this.isApplied){
50897 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
50898 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
50899 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
50900 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
50903 this.maskEl.top.enableDisplayMode("block");
50904 this.maskEl.left.enableDisplayMode("block");
50905 this.maskEl.bottom.enableDisplayMode("block");
50906 this.maskEl.right.enableDisplayMode("block");
50908 Roo.get(document.body).on('click', function(){
50912 Roo.get(document.body).on('touchstart', function(){
50916 this.isApplied = true
50919 mask : function(form, target)
50923 this.target = target;
50925 if(!this.form.errorMask || !target.el){
50929 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.x-layout-active-content', 100, true) || Roo.get(document.body);
50931 var ot = this.target.el.calcOffsetsTo(scrollable);
50933 var scrollTo = ot[1] - this.form.maskOffset;
50935 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
50937 scrollable.scrollTo('top', scrollTo);
50939 var el = this.target.wrap || this.target.el;
50941 var box = el.getBox();
50943 this.maskEl.top.setStyle('position', 'absolute');
50944 this.maskEl.top.setStyle('z-index', 10000);
50945 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
50946 this.maskEl.top.setLeft(0);
50947 this.maskEl.top.setTop(0);
50948 this.maskEl.top.show();
50950 this.maskEl.left.setStyle('position', 'absolute');
50951 this.maskEl.left.setStyle('z-index', 10000);
50952 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
50953 this.maskEl.left.setLeft(0);
50954 this.maskEl.left.setTop(box.y - this.padding);
50955 this.maskEl.left.show();
50957 this.maskEl.bottom.setStyle('position', 'absolute');
50958 this.maskEl.bottom.setStyle('z-index', 10000);
50959 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
50960 this.maskEl.bottom.setLeft(0);
50961 this.maskEl.bottom.setTop(box.bottom + this.padding);
50962 this.maskEl.bottom.show();
50964 this.maskEl.right.setStyle('position', 'absolute');
50965 this.maskEl.right.setStyle('z-index', 10000);
50966 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
50967 this.maskEl.right.setLeft(box.right + this.padding);
50968 this.maskEl.right.setTop(box.y - this.padding);
50969 this.maskEl.right.show();
50971 this.intervalID = window.setInterval(function() {
50972 Roo.form.BasicForm.popover.unmask();
50975 window.onwheel = function(){ return false;};
50977 (function(){ this.isMasked = true; }).defer(500, this);
50981 unmask : function()
50983 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
50987 this.maskEl.top.setStyle('position', 'absolute');
50988 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
50989 this.maskEl.top.hide();
50991 this.maskEl.left.setStyle('position', 'absolute');
50992 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
50993 this.maskEl.left.hide();
50995 this.maskEl.bottom.setStyle('position', 'absolute');
50996 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
50997 this.maskEl.bottom.hide();
50999 this.maskEl.right.setStyle('position', 'absolute');
51000 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
51001 this.maskEl.right.hide();
51003 window.onwheel = function(){ return true;};
51005 if(this.intervalID){
51006 window.clearInterval(this.intervalID);
51007 this.intervalID = false;
51010 this.isMasked = false;
51018 * Ext JS Library 1.1.1
51019 * Copyright(c) 2006-2007, Ext JS, LLC.
51021 * Originally Released Under LGPL - original licence link has changed is not relivant.
51024 * <script type="text/javascript">
51028 * @class Roo.form.Form
51029 * @extends Roo.form.BasicForm
51030 * @children Roo.form.Column Roo.form.FieldSet Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
51031 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
51033 * @param {Object} config Configuration options
51035 Roo.form.Form = function(config){
51037 if (config.items) {
51038 xitems = config.items;
51039 delete config.items;
51043 Roo.form.Form.superclass.constructor.call(this, null, config);
51044 this.url = this.url || this.action;
51046 this.root = new Roo.form.Layout(Roo.applyIf({
51050 this.active = this.root;
51052 * Array of all the buttons that have been added to this form via {@link addButton}
51056 this.allItems = [];
51059 * @event clientvalidation
51060 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
51061 * @param {Form} this
51062 * @param {Boolean} valid true if the form has passed client-side validation
51064 clientvalidation: true,
51067 * Fires when the form is rendered
51068 * @param {Roo.form.Form} form
51073 if (this.progressUrl) {
51074 // push a hidden field onto the list of fields..
51078 name : 'UPLOAD_IDENTIFIER'
51083 Roo.each(xitems, this.addxtype, this);
51087 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
51089 * @cfg {Roo.Button} buttons[] buttons at bottom of form
51093 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
51096 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
51099 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
51101 buttonAlign:'center',
51104 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
51109 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
51110 * This property cascades to child containers if not set.
51115 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
51116 * fires a looping event with that state. This is required to bind buttons to the valid
51117 * state using the config value formBind:true on the button.
51119 monitorValid : false,
51122 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
51127 * @cfg {String} progressUrl - Url to return progress data
51130 progressUrl : false,
51132 * @cfg {boolean|FormData} formData - true to use new 'FormData' post, or set to a new FormData({dom form}) Object, if
51133 * sending a formdata with extra parameters - eg uploaded elements.
51139 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
51140 * fields are added and the column is closed. If no fields are passed the column remains open
51141 * until end() is called.
51142 * @param {Object} config The config to pass to the column
51143 * @param {Field} field1 (optional)
51144 * @param {Field} field2 (optional)
51145 * @param {Field} etc (optional)
51146 * @return Column The column container object
51148 column : function(c){
51149 var col = new Roo.form.Column(c);
51151 if(arguments.length > 1){ // duplicate code required because of Opera
51152 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
51159 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
51160 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
51161 * until end() is called.
51162 * @param {Object} config The config to pass to the fieldset
51163 * @param {Field} field1 (optional)
51164 * @param {Field} field2 (optional)
51165 * @param {Field} etc (optional)
51166 * @return FieldSet The fieldset container object
51168 fieldset : function(c){
51169 var fs = new Roo.form.FieldSet(c);
51171 if(arguments.length > 1){ // duplicate code required because of Opera
51172 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
51179 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
51180 * fields are added and the container is closed. If no fields are passed the container remains open
51181 * until end() is called.
51182 * @param {Object} config The config to pass to the Layout
51183 * @param {Field} field1 (optional)
51184 * @param {Field} field2 (optional)
51185 * @param {Field} etc (optional)
51186 * @return Layout The container object
51188 container : function(c){
51189 var l = new Roo.form.Layout(c);
51191 if(arguments.length > 1){ // duplicate code required because of Opera
51192 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
51199 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
51200 * @param {Object} container A Roo.form.Layout or subclass of Layout
51201 * @return {Form} this
51203 start : function(c){
51204 // cascade label info
51205 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
51206 this.active.stack.push(c);
51207 c.ownerCt = this.active;
51213 * Closes the current open container
51214 * @return {Form} this
51217 if(this.active == this.root){
51220 this.active = this.active.ownerCt;
51225 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
51226 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
51227 * as the label of the field.
51228 * @param {Field} field1
51229 * @param {Field} field2 (optional)
51230 * @param {Field} etc. (optional)
51231 * @return {Form} this
51234 this.active.stack.push.apply(this.active.stack, arguments);
51235 this.allItems.push.apply(this.allItems,arguments);
51237 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
51238 if(a[i].isFormField){
51243 Roo.form.Form.superclass.add.apply(this, r);
51253 * Find any element that has been added to a form, using it's ID or name
51254 * This can include framesets, columns etc. along with regular fields..
51255 * @param {String} id - id or name to find.
51257 * @return {Element} e - or false if nothing found.
51259 findbyId : function(id)
51265 Roo.each(this.allItems, function(f){
51266 if (f.id == id || f.name == id ){
51277 * Render this form into the passed container. This should only be called once!
51278 * @param {String/HTMLElement/Element} container The element this component should be rendered into
51279 * @return {Form} this
51281 render : function(ct)
51287 var o = this.autoCreate || {
51289 method : this.method || 'POST',
51290 id : this.id || Roo.id()
51292 this.initEl(ct.createChild(o));
51294 this.root.render(this.el);
51298 this.items.each(function(f){
51299 f.render('x-form-el-'+f.id);
51302 if(this.buttons.length > 0){
51303 // tables are required to maintain order and for correct IE layout
51304 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
51305 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
51306 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
51308 var tr = tb.getElementsByTagName('tr')[0];
51309 for(var i = 0, len = this.buttons.length; i < len; i++) {
51310 var b = this.buttons[i];
51311 var td = document.createElement('td');
51312 td.className = 'x-form-btn-td';
51313 b.render(tr.appendChild(td));
51316 if(this.monitorValid){ // initialize after render
51317 this.startMonitoring();
51319 this.fireEvent('rendered', this);
51324 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
51325 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
51326 * object or a valid Roo.DomHelper element config
51327 * @param {Function} handler The function called when the button is clicked
51328 * @param {Object} scope (optional) The scope of the handler function
51329 * @return {Roo.Button}
51331 addButton : function(config, handler, scope){
51335 minWidth: this.minButtonWidth,
51338 if(typeof config == "string"){
51341 Roo.apply(bc, config);
51343 var btn = new Roo.Button(null, bc);
51344 this.buttons.push(btn);
51349 * Adds a series of form elements (using the xtype property as the factory method.
51350 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
51351 * @param {Object} config
51354 addxtype : function()
51356 var ar = Array.prototype.slice.call(arguments, 0);
51358 for(var i = 0; i < ar.length; i++) {
51360 continue; // skip -- if this happends something invalid got sent, we
51361 // should ignore it, as basically that interface element will not show up
51362 // and that should be pretty obvious!!
51365 if (Roo.form[ar[i].xtype]) {
51367 var fe = Roo.factory(ar[i], Roo.form);
51373 fe.store.form = this;
51378 this.allItems.push(fe);
51379 if (fe.items && fe.addxtype) {
51380 fe.addxtype.apply(fe, fe.items);
51390 // console.log('adding ' + ar[i].xtype);
51392 if (ar[i].xtype == 'Button') {
51393 //console.log('adding button');
51394 //console.log(ar[i]);
51395 this.addButton(ar[i]);
51396 this.allItems.push(fe);
51400 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
51401 alert('end is not supported on xtype any more, use items');
51403 // //console.log('adding end');
51411 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
51412 * option "monitorValid"
51414 startMonitoring : function(){
51417 Roo.TaskMgr.start({
51418 run : this.bindHandler,
51419 interval : this.monitorPoll || 200,
51426 * Stops monitoring of the valid state of this form
51428 stopMonitoring : function(){
51429 this.bound = false;
51433 bindHandler : function(){
51435 return false; // stops binding
51438 this.items.each(function(f){
51439 if(!f.isValid(true)){
51444 for(var i = 0, len = this.buttons.length; i < len; i++){
51445 var btn = this.buttons[i];
51446 if(btn.formBind === true && btn.disabled === valid){
51447 btn.setDisabled(!valid);
51450 this.fireEvent('clientvalidation', this, valid);
51464 Roo.Form = Roo.form.Form;
51467 * Ext JS Library 1.1.1
51468 * Copyright(c) 2006-2007, Ext JS, LLC.
51470 * Originally Released Under LGPL - original licence link has changed is not relivant.
51473 * <script type="text/javascript">
51476 // as we use this in bootstrap.
51477 Roo.namespace('Roo.form');
51479 * @class Roo.form.Action
51480 * Internal Class used to handle form actions
51482 * @param {Roo.form.BasicForm} el The form element or its id
51483 * @param {Object} config Configuration options
51488 // define the action interface
51489 Roo.form.Action = function(form, options){
51491 this.options = options || {};
51494 * Client Validation Failed
51497 Roo.form.Action.CLIENT_INVALID = 'client';
51499 * Server Validation Failed
51502 Roo.form.Action.SERVER_INVALID = 'server';
51504 * Connect to Server Failed
51507 Roo.form.Action.CONNECT_FAILURE = 'connect';
51509 * Reading Data from Server Failed
51512 Roo.form.Action.LOAD_FAILURE = 'load';
51514 Roo.form.Action.prototype = {
51516 failureType : undefined,
51517 response : undefined,
51518 result : undefined,
51520 // interface method
51521 run : function(options){
51525 // interface method
51526 success : function(response){
51530 // interface method
51531 handleResponse : function(response){
51535 // default connection failure
51536 failure : function(response){
51538 this.response = response;
51539 this.failureType = Roo.form.Action.CONNECT_FAILURE;
51540 this.form.afterAction(this, false);
51543 processResponse : function(response){
51544 this.response = response;
51545 if(!response.responseText){
51548 this.result = this.handleResponse(response);
51549 return this.result;
51552 // utility functions used internally
51553 getUrl : function(appendParams){
51554 var url = this.options.url || this.form.url || this.form.el.dom.action;
51556 var p = this.getParams();
51558 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
51564 getMethod : function(){
51565 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
51568 getParams : function(){
51569 var bp = this.form.baseParams;
51570 var p = this.options.params;
51572 if(typeof p == "object"){
51573 p = Roo.urlEncode(Roo.applyIf(p, bp));
51574 }else if(typeof p == 'string' && bp){
51575 p += '&' + Roo.urlEncode(bp);
51578 p = Roo.urlEncode(bp);
51583 createCallback : function(){
51585 success: this.success,
51586 failure: this.failure,
51588 timeout: (this.form.timeout*1000),
51589 upload: this.form.fileUpload ? this.success : undefined
51594 Roo.form.Action.Submit = function(form, options){
51595 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
51598 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
51601 haveProgress : false,
51602 uploadComplete : false,
51604 // uploadProgress indicator.
51605 uploadProgress : function()
51607 if (!this.form.progressUrl) {
51611 if (!this.haveProgress) {
51612 Roo.MessageBox.progress("Uploading", "Uploading");
51614 if (this.uploadComplete) {
51615 Roo.MessageBox.hide();
51619 this.haveProgress = true;
51621 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
51623 var c = new Roo.data.Connection();
51625 url : this.form.progressUrl,
51630 success : function(req){
51631 //console.log(data);
51635 rdata = Roo.decode(req.responseText)
51637 Roo.log("Invalid data from server..");
51641 if (!rdata || !rdata.success) {
51643 Roo.MessageBox.alert(Roo.encode(rdata));
51646 var data = rdata.data;
51648 if (this.uploadComplete) {
51649 Roo.MessageBox.hide();
51654 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
51655 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
51658 this.uploadProgress.defer(2000,this);
51661 failure: function(data) {
51662 Roo.log('progress url failed ');
51673 // run get Values on the form, so it syncs any secondary forms.
51674 this.form.getValues();
51676 var o = this.options;
51677 var method = this.getMethod();
51678 var isPost = method == 'POST';
51679 if(o.clientValidation === false || this.form.isValid()){
51681 if (this.form.progressUrl) {
51682 this.form.findField('UPLOAD_IDENTIFIER').setValue(
51683 (new Date() * 1) + '' + Math.random());
51688 Roo.Ajax.request(Roo.apply(this.createCallback(), {
51689 form:this.form.el.dom,
51690 url:this.getUrl(!isPost),
51692 params:isPost ? this.getParams() : null,
51693 isUpload: this.form.fileUpload,
51694 formData : this.form.formData
51697 this.uploadProgress();
51699 }else if (o.clientValidation !== false){ // client validation failed
51700 this.failureType = Roo.form.Action.CLIENT_INVALID;
51701 this.form.afterAction(this, false);
51705 success : function(response)
51707 this.uploadComplete= true;
51708 if (this.haveProgress) {
51709 Roo.MessageBox.hide();
51713 var result = this.processResponse(response);
51714 if(result === true || result.success){
51715 this.form.afterAction(this, true);
51719 this.form.markInvalid(result.errors);
51720 this.failureType = Roo.form.Action.SERVER_INVALID;
51722 this.form.afterAction(this, false);
51724 failure : function(response)
51726 this.uploadComplete= true;
51727 if (this.haveProgress) {
51728 Roo.MessageBox.hide();
51731 this.response = response;
51732 this.failureType = Roo.form.Action.CONNECT_FAILURE;
51733 this.form.afterAction(this, false);
51736 handleResponse : function(response){
51737 if(this.form.errorReader){
51738 var rs = this.form.errorReader.read(response);
51741 for(var i = 0, len = rs.records.length; i < len; i++) {
51742 var r = rs.records[i];
51743 errors[i] = r.data;
51746 if(errors.length < 1){
51750 success : rs.success,
51756 ret = Roo.decode(response.responseText);
51760 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
51770 Roo.form.Action.Load = function(form, options){
51771 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
51772 this.reader = this.form.reader;
51775 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
51780 Roo.Ajax.request(Roo.apply(
51781 this.createCallback(), {
51782 method:this.getMethod(),
51783 url:this.getUrl(false),
51784 params:this.getParams()
51788 success : function(response){
51790 var result = this.processResponse(response);
51791 if(result === true || !result.success || !result.data){
51792 this.failureType = Roo.form.Action.LOAD_FAILURE;
51793 this.form.afterAction(this, false);
51796 this.form.clearInvalid();
51797 this.form.setValues(result.data);
51798 this.form.afterAction(this, true);
51801 handleResponse : function(response){
51802 if(this.form.reader){
51803 var rs = this.form.reader.read(response);
51804 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
51806 success : rs.success,
51810 return Roo.decode(response.responseText);
51814 Roo.form.Action.ACTION_TYPES = {
51815 'load' : Roo.form.Action.Load,
51816 'submit' : Roo.form.Action.Submit
51819 * Ext JS Library 1.1.1
51820 * Copyright(c) 2006-2007, Ext JS, LLC.
51822 * Originally Released Under LGPL - original licence link has changed is not relivant.
51825 * <script type="text/javascript">
51829 * @class Roo.form.Layout
51830 * @extends Roo.Component
51831 * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem Roo.form.FieldSet
51832 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
51834 * @param {Object} config Configuration options
51836 Roo.form.Layout = function(config){
51838 if (config.items) {
51839 xitems = config.items;
51840 delete config.items;
51842 Roo.form.Layout.superclass.constructor.call(this, config);
51844 Roo.each(xitems, this.addxtype, this);
51848 Roo.extend(Roo.form.Layout, Roo.Component, {
51850 * @cfg {String/Object} autoCreate
51851 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
51854 * @cfg {String/Object/Function} style
51855 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
51856 * a function which returns such a specification.
51859 * @cfg {String} labelAlign
51860 * Valid values are "left," "top" and "right" (defaults to "left")
51863 * @cfg {Number} labelWidth
51864 * Fixed width in pixels of all field labels (defaults to undefined)
51867 * @cfg {Boolean} clear
51868 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
51872 * @cfg {String} labelSeparator
51873 * The separator to use after field labels (defaults to ':')
51875 labelSeparator : ':',
51877 * @cfg {Boolean} hideLabels
51878 * True to suppress the display of field labels in this layout (defaults to false)
51880 hideLabels : false,
51883 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
51888 onRender : function(ct, position){
51889 if(this.el){ // from markup
51890 this.el = Roo.get(this.el);
51891 }else { // generate
51892 var cfg = this.getAutoCreate();
51893 this.el = ct.createChild(cfg, position);
51896 this.el.applyStyles(this.style);
51898 if(this.labelAlign){
51899 this.el.addClass('x-form-label-'+this.labelAlign);
51901 if(this.hideLabels){
51902 this.labelStyle = "display:none";
51903 this.elementStyle = "padding-left:0;";
51905 if(typeof this.labelWidth == 'number'){
51906 this.labelStyle = "width:"+this.labelWidth+"px;";
51907 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
51909 if(this.labelAlign == 'top'){
51910 this.labelStyle = "width:auto;";
51911 this.elementStyle = "padding-left:0;";
51914 var stack = this.stack;
51915 var slen = stack.length;
51917 if(!this.fieldTpl){
51918 var t = new Roo.Template(
51919 '<div class="x-form-item {5}">',
51920 '<label for="{0}" style="{2}">{1}{4}</label>',
51921 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
51923 '</div><div class="x-form-clear-left"></div>'
51925 t.disableFormats = true;
51927 Roo.form.Layout.prototype.fieldTpl = t;
51929 for(var i = 0; i < slen; i++) {
51930 if(stack[i].isFormField){
51931 this.renderField(stack[i]);
51933 this.renderComponent(stack[i]);
51938 this.el.createChild({cls:'x-form-clear'});
51943 renderField : function(f){
51944 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
51947 f.labelStyle||this.labelStyle||'', //2
51948 this.elementStyle||'', //3
51949 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
51950 f.itemCls||this.itemCls||'' //5
51951 ], true).getPrevSibling());
51955 renderComponent : function(c){
51956 c.render(c.isLayout ? this.el : this.el.createChild());
51959 * Adds a object form elements (using the xtype property as the factory method.)
51960 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
51961 * @param {Object} config
51963 addxtype : function(o)
51965 // create the lement.
51966 o.form = this.form;
51967 var fe = Roo.factory(o, Roo.form);
51968 this.form.allItems.push(fe);
51969 this.stack.push(fe);
51971 if (fe.isFormField) {
51972 this.form.items.add(fe);
51980 * @class Roo.form.Column
51981 * @extends Roo.form.Layout
51982 * @children Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem Roo.form.FieldSet
51983 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
51985 * @param {Object} config Configuration options
51987 Roo.form.Column = function(config){
51988 Roo.form.Column.superclass.constructor.call(this, config);
51991 Roo.extend(Roo.form.Column, Roo.form.Layout, {
51993 * @cfg {Number/String} width
51994 * The fixed width of the column in pixels or CSS value (defaults to "auto")
51997 * @cfg {String/Object} autoCreate
51998 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
52002 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
52005 onRender : function(ct, position){
52006 Roo.form.Column.superclass.onRender.call(this, ct, position);
52008 this.el.setWidth(this.width);
52015 * @class Roo.form.Row
52016 * @extends Roo.form.Layout
52017 * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem Roo.form.FieldSet
52018 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
52020 * @param {Object} config Configuration options
52024 Roo.form.Row = function(config){
52025 Roo.form.Row.superclass.constructor.call(this, config);
52028 Roo.extend(Roo.form.Row, Roo.form.Layout, {
52030 * @cfg {Number/String} width
52031 * The fixed width of the column in pixels or CSS value (defaults to "auto")
52034 * @cfg {Number/String} height
52035 * The fixed height of the column in pixels or CSS value (defaults to "auto")
52037 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
52041 onRender : function(ct, position){
52042 //console.log('row render');
52044 var t = new Roo.Template(
52045 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
52046 '<label for="{0}" style="{2}">{1}{4}</label>',
52047 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
52051 t.disableFormats = true;
52053 Roo.form.Layout.prototype.rowTpl = t;
52055 this.fieldTpl = this.rowTpl;
52057 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
52058 var labelWidth = 100;
52060 if ((this.labelAlign != 'top')) {
52061 if (typeof this.labelWidth == 'number') {
52062 labelWidth = this.labelWidth
52064 this.padWidth = 20 + labelWidth;
52068 Roo.form.Column.superclass.onRender.call(this, ct, position);
52070 this.el.setWidth(this.width);
52073 this.el.setHeight(this.height);
52078 renderField : function(f){
52079 f.fieldEl = this.fieldTpl.append(this.el, [
52080 f.id, f.fieldLabel,
52081 f.labelStyle||this.labelStyle||'',
52082 this.elementStyle||'',
52083 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
52084 f.itemCls||this.itemCls||'',
52085 f.width ? f.width + this.padWidth : 160 + this.padWidth
52092 * @class Roo.form.FieldSet
52093 * @extends Roo.form.Layout
52094 * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
52095 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
52097 * @param {Object} config Configuration options
52099 Roo.form.FieldSet = function(config){
52100 Roo.form.FieldSet.superclass.constructor.call(this, config);
52103 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
52105 * @cfg {String} legend
52106 * The text to display as the legend for the FieldSet (defaults to '')
52109 * @cfg {String/Object} autoCreate
52110 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
52114 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
52117 onRender : function(ct, position){
52118 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
52120 this.setLegend(this.legend);
52125 setLegend : function(text){
52127 this.el.child('legend').update(text);
52132 * Ext JS Library 1.1.1
52133 * Copyright(c) 2006-2007, Ext JS, LLC.
52135 * Originally Released Under LGPL - original licence link has changed is not relivant.
52138 * <script type="text/javascript">
52141 * @class Roo.form.VTypes
52142 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
52145 Roo.form.VTypes = function(){
52146 // closure these in so they are only created once.
52147 var alpha = /^[a-zA-Z_]+$/;
52148 var alphanum = /^[a-zA-Z0-9_]+$/;
52149 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
52150 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
52152 // All these messages and functions are configurable
52155 * The function used to validate email addresses
52156 * @param {String} value The email address
52158 'email' : function(v){
52159 return email.test(v);
52162 * The error text to display when the email validation function returns false
52165 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
52167 * The keystroke filter mask to be applied on email input
52170 'emailMask' : /[a-z0-9_\.\-@]/i,
52173 * The function used to validate URLs
52174 * @param {String} value The URL
52176 'url' : function(v){
52177 return url.test(v);
52180 * The error text to display when the url validation function returns false
52183 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
52186 * The function used to validate alpha values
52187 * @param {String} value The value
52189 'alpha' : function(v){
52190 return alpha.test(v);
52193 * The error text to display when the alpha validation function returns false
52196 'alphaText' : 'This field should only contain letters and _',
52198 * The keystroke filter mask to be applied on alpha input
52201 'alphaMask' : /[a-z_]/i,
52204 * The function used to validate alphanumeric values
52205 * @param {String} value The value
52207 'alphanum' : function(v){
52208 return alphanum.test(v);
52211 * The error text to display when the alphanumeric validation function returns false
52214 'alphanumText' : 'This field should only contain letters, numbers and _',
52216 * The keystroke filter mask to be applied on alphanumeric input
52219 'alphanumMask' : /[a-z0-9_]/i
52221 }();//<script type="text/javascript">
52224 * @class Roo.form.FCKeditor
52225 * @extends Roo.form.TextArea
52226 * Wrapper around the FCKEditor http://www.fckeditor.net
52228 * Creates a new FCKeditor
52229 * @param {Object} config Configuration options
52231 Roo.form.FCKeditor = function(config){
52232 Roo.form.FCKeditor.superclass.constructor.call(this, config);
52235 * @event editorinit
52236 * Fired when the editor is initialized - you can add extra handlers here..
52237 * @param {FCKeditor} this
52238 * @param {Object} the FCK object.
52245 Roo.form.FCKeditor.editors = { };
52246 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
52248 //defaultAutoCreate : {
52249 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
52253 * @cfg {Object} fck options - see fck manual for details.
52258 * @cfg {Object} fck toolbar set (Basic or Default)
52260 toolbarSet : 'Basic',
52262 * @cfg {Object} fck BasePath
52264 basePath : '/fckeditor/',
52272 onRender : function(ct, position)
52275 this.defaultAutoCreate = {
52277 style:"width:300px;height:60px;",
52278 autocomplete: "new-password"
52281 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
52284 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
52285 if(this.preventScrollbars){
52286 this.el.setStyle("overflow", "hidden");
52288 this.el.setHeight(this.growMin);
52291 //console.log('onrender' + this.getId() );
52292 Roo.form.FCKeditor.editors[this.getId()] = this;
52295 this.replaceTextarea() ;
52299 getEditor : function() {
52300 return this.fckEditor;
52303 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
52304 * @param {Mixed} value The value to set
52308 setValue : function(value)
52310 //console.log('setValue: ' + value);
52312 if(typeof(value) == 'undefined') { // not sure why this is happending...
52315 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
52317 //if(!this.el || !this.getEditor()) {
52318 // this.value = value;
52319 //this.setValue.defer(100,this,[value]);
52323 if(!this.getEditor()) {
52327 this.getEditor().SetData(value);
52334 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
52335 * @return {Mixed} value The field value
52337 getValue : function()
52340 if (this.frame && this.frame.dom.style.display == 'none') {
52341 return Roo.form.FCKeditor.superclass.getValue.call(this);
52344 if(!this.el || !this.getEditor()) {
52346 // this.getValue.defer(100,this);
52351 var value=this.getEditor().GetData();
52352 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
52353 return Roo.form.FCKeditor.superclass.getValue.call(this);
52359 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
52360 * @return {Mixed} value The field value
52362 getRawValue : function()
52364 if (this.frame && this.frame.dom.style.display == 'none') {
52365 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
52368 if(!this.el || !this.getEditor()) {
52369 //this.getRawValue.defer(100,this);
52376 var value=this.getEditor().GetData();
52377 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
52378 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
52382 setSize : function(w,h) {
52386 //if (this.frame && this.frame.dom.style.display == 'none') {
52387 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
52390 //if(!this.el || !this.getEditor()) {
52391 // this.setSize.defer(100,this, [w,h]);
52397 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
52399 this.frame.dom.setAttribute('width', w);
52400 this.frame.dom.setAttribute('height', h);
52401 this.frame.setSize(w,h);
52405 toggleSourceEdit : function(value) {
52409 this.el.dom.style.display = value ? '' : 'none';
52410 this.frame.dom.style.display = value ? 'none' : '';
52415 focus: function(tag)
52417 if (this.frame.dom.style.display == 'none') {
52418 return Roo.form.FCKeditor.superclass.focus.call(this);
52420 if(!this.el || !this.getEditor()) {
52421 this.focus.defer(100,this, [tag]);
52428 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
52429 this.getEditor().Focus();
52431 if (!this.getEditor().Selection.GetSelection()) {
52432 this.focus.defer(100,this, [tag]);
52437 var r = this.getEditor().EditorDocument.createRange();
52438 r.setStart(tgs[0],0);
52439 r.setEnd(tgs[0],0);
52440 this.getEditor().Selection.GetSelection().removeAllRanges();
52441 this.getEditor().Selection.GetSelection().addRange(r);
52442 this.getEditor().Focus();
52449 replaceTextarea : function()
52451 if ( document.getElementById( this.getId() + '___Frame' ) ) {
52454 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
52456 // We must check the elements firstly using the Id and then the name.
52457 var oTextarea = document.getElementById( this.getId() );
52459 var colElementsByName = document.getElementsByName( this.getId() ) ;
52461 oTextarea.style.display = 'none' ;
52463 if ( oTextarea.tabIndex ) {
52464 this.TabIndex = oTextarea.tabIndex ;
52467 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
52468 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
52469 this.frame = Roo.get(this.getId() + '___Frame')
52472 _getConfigHtml : function()
52476 for ( var o in this.fckconfig ) {
52477 sConfig += sConfig.length > 0 ? '&' : '';
52478 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
52481 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
52485 _getIFrameHtml : function()
52487 var sFile = 'fckeditor.html' ;
52488 /* no idea what this is about..
52491 if ( (/fcksource=true/i).test( window.top.location.search ) )
52492 sFile = 'fckeditor.original.html' ;
52497 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
52498 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
52501 var html = '<iframe id="' + this.getId() +
52502 '___Frame" src="' + sLink +
52503 '" width="' + this.width +
52504 '" height="' + this.height + '"' +
52505 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
52506 ' frameborder="0" scrolling="no"></iframe>' ;
52511 _insertHtmlBefore : function( html, element )
52513 if ( element.insertAdjacentHTML ) {
52515 element.insertAdjacentHTML( 'beforeBegin', html ) ;
52517 var oRange = document.createRange() ;
52518 oRange.setStartBefore( element ) ;
52519 var oFragment = oRange.createContextualFragment( html );
52520 element.parentNode.insertBefore( oFragment, element ) ;
52533 //Roo.reg('fckeditor', Roo.form.FCKeditor);
52535 function FCKeditor_OnComplete(editorInstance){
52536 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
52537 f.fckEditor = editorInstance;
52538 //console.log("loaded");
52539 f.fireEvent('editorinit', f, editorInstance);
52559 //<script type="text/javascript">
52561 * @class Roo.form.GridField
52562 * @extends Roo.form.Field
52563 * Embed a grid (or editable grid into a form)
52566 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
52568 * xgrid.store = Roo.data.Store
52569 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
52570 * xgrid.store.reader = Roo.data.JsonReader
52574 * Creates a new GridField
52575 * @param {Object} config Configuration options
52577 Roo.form.GridField = function(config){
52578 Roo.form.GridField.superclass.constructor.call(this, config);
52582 Roo.extend(Roo.form.GridField, Roo.form.Field, {
52584 * @cfg {Number} width - used to restrict width of grid..
52588 * @cfg {Number} height - used to restrict height of grid..
52592 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
52598 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
52599 * {tag: "input", type: "checkbox", autocomplete: "off"})
52601 // defaultAutoCreate : { tag: 'div' },
52602 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
52604 * @cfg {String} addTitle Text to include for adding a title.
52608 onResize : function(){
52609 Roo.form.Field.superclass.onResize.apply(this, arguments);
52612 initEvents : function(){
52613 // Roo.form.Checkbox.superclass.initEvents.call(this);
52614 // has no events...
52619 getResizeEl : function(){
52623 getPositionEl : function(){
52628 onRender : function(ct, position){
52630 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
52631 var style = this.style;
52634 Roo.form.GridField.superclass.onRender.call(this, ct, position);
52635 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
52636 this.viewEl = this.wrap.createChild({ tag: 'div' });
52638 this.viewEl.applyStyles(style);
52641 this.viewEl.setWidth(this.width);
52644 this.viewEl.setHeight(this.height);
52646 //if(this.inputValue !== undefined){
52647 //this.setValue(this.value);
52650 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
52653 this.grid.render();
52654 this.grid.getDataSource().on('remove', this.refreshValue, this);
52655 this.grid.getDataSource().on('update', this.refreshValue, this);
52656 this.grid.on('afteredit', this.refreshValue, this);
52662 * Sets the value of the item.
52663 * @param {String} either an object or a string..
52665 setValue : function(v){
52667 v = v || []; // empty set..
52668 // this does not seem smart - it really only affects memoryproxy grids..
52669 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
52670 var ds = this.grid.getDataSource();
52671 // assumes a json reader..
52673 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
52674 ds.loadData( data);
52676 // clear selection so it does not get stale.
52677 if (this.grid.sm) {
52678 this.grid.sm.clearSelections();
52681 Roo.form.GridField.superclass.setValue.call(this, v);
52682 this.refreshValue();
52683 // should load data in the grid really....
52687 refreshValue: function() {
52689 this.grid.getDataSource().each(function(r) {
52692 this.el.dom.value = Roo.encode(val);
52700 * Ext JS Library 1.1.1
52701 * Copyright(c) 2006-2007, Ext JS, LLC.
52703 * Originally Released Under LGPL - original licence link has changed is not relivant.
52706 * <script type="text/javascript">
52709 * @class Roo.form.DisplayField
52710 * @extends Roo.form.Field
52711 * A generic Field to display non-editable data.
52712 * @cfg {Boolean} closable (true|false) default false
52714 * Creates a new Display Field item.
52715 * @param {Object} config Configuration options
52717 Roo.form.DisplayField = function(config){
52718 Roo.form.DisplayField.superclass.constructor.call(this, config);
52723 * Fires after the click the close btn
52724 * @param {Roo.form.DisplayField} this
52730 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
52731 inputType: 'hidden',
52737 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
52739 focusClass : undefined,
52741 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
52743 fieldClass: 'x-form-field',
52746 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
52748 valueRenderer: undefined,
52752 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
52753 * {tag: "input", type: "checkbox", autocomplete: "off"})
52756 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
52760 onResize : function(){
52761 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
52765 initEvents : function(){
52766 // Roo.form.Checkbox.superclass.initEvents.call(this);
52767 // has no events...
52770 this.closeEl.on('click', this.onClose, this);
52776 getResizeEl : function(){
52780 getPositionEl : function(){
52785 onRender : function(ct, position){
52787 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
52788 //if(this.inputValue !== undefined){
52789 this.wrap = this.el.wrap();
52791 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
52794 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
52797 if (this.bodyStyle) {
52798 this.viewEl.applyStyles(this.bodyStyle);
52800 //this.viewEl.setStyle('padding', '2px');
52802 this.setValue(this.value);
52807 initValue : Roo.emptyFn,
52812 onClick : function(){
52817 * Sets the checked state of the checkbox.
52818 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
52820 setValue : function(v){
52822 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
52823 // this might be called before we have a dom element..
52824 if (!this.viewEl) {
52827 this.viewEl.dom.innerHTML = html;
52828 Roo.form.DisplayField.superclass.setValue.call(this, v);
52832 onClose : function(e)
52834 e.preventDefault();
52836 this.fireEvent('close', this);
52845 * @class Roo.form.DayPicker
52846 * @extends Roo.form.Field
52847 * A Day picker show [M] [T] [W] ....
52849 * Creates a new Day Picker
52850 * @param {Object} config Configuration options
52852 Roo.form.DayPicker= function(config){
52853 Roo.form.DayPicker.superclass.constructor.call(this, config);
52857 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
52859 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
52861 focusClass : undefined,
52863 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
52865 fieldClass: "x-form-field",
52868 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
52869 * {tag: "input", type: "checkbox", autocomplete: "off"})
52871 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
52874 actionMode : 'viewEl',
52878 inputType : 'hidden',
52881 inputElement: false, // real input element?
52882 basedOn: false, // ????
52884 isFormField: true, // not sure where this is needed!!!!
52886 onResize : function(){
52887 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
52888 if(!this.boxLabel){
52889 this.el.alignTo(this.wrap, 'c-c');
52893 initEvents : function(){
52894 Roo.form.Checkbox.superclass.initEvents.call(this);
52895 this.el.on("click", this.onClick, this);
52896 this.el.on("change", this.onClick, this);
52900 getResizeEl : function(){
52904 getPositionEl : function(){
52910 onRender : function(ct, position){
52911 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
52913 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
52915 var r1 = '<table><tr>';
52916 var r2 = '<tr class="x-form-daypick-icons">';
52917 for (var i=0; i < 7; i++) {
52918 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
52919 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
52922 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
52923 viewEl.select('img').on('click', this.onClick, this);
52924 this.viewEl = viewEl;
52927 // this will not work on Chrome!!!
52928 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
52929 this.el.on('propertychange', this.setFromHidden, this); //ie
52937 initValue : Roo.emptyFn,
52940 * Returns the checked state of the checkbox.
52941 * @return {Boolean} True if checked, else false
52943 getValue : function(){
52944 return this.el.dom.value;
52949 onClick : function(e){
52950 //this.setChecked(!this.checked);
52951 Roo.get(e.target).toggleClass('x-menu-item-checked');
52952 this.refreshValue();
52953 //if(this.el.dom.checked != this.checked){
52954 // this.setValue(this.el.dom.checked);
52959 refreshValue : function()
52962 this.viewEl.select('img',true).each(function(e,i,n) {
52963 val += e.is(".x-menu-item-checked") ? String(n) : '';
52965 this.setValue(val, true);
52969 * Sets the checked state of the checkbox.
52970 * On is always based on a string comparison between inputValue and the param.
52971 * @param {Boolean/String} value - the value to set
52972 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
52974 setValue : function(v,suppressEvent){
52975 if (!this.el.dom) {
52978 var old = this.el.dom.value ;
52979 this.el.dom.value = v;
52980 if (suppressEvent) {
52984 // update display..
52985 this.viewEl.select('img',true).each(function(e,i,n) {
52987 var on = e.is(".x-menu-item-checked");
52988 var newv = v.indexOf(String(n)) > -1;
52990 e.toggleClass('x-menu-item-checked');
52996 this.fireEvent('change', this, v, old);
53001 // handle setting of hidden value by some other method!!?!?
53002 setFromHidden: function()
53007 //console.log("SET FROM HIDDEN");
53008 //alert('setFrom hidden');
53009 this.setValue(this.el.dom.value);
53012 onDestroy : function()
53015 Roo.get(this.viewEl).remove();
53018 Roo.form.DayPicker.superclass.onDestroy.call(this);
53022 * RooJS Library 1.1.1
53023 * Copyright(c) 2008-2011 Alan Knowles
53030 * @class Roo.form.ComboCheck
53031 * @extends Roo.form.ComboBox
53032 * A combobox for multiple select items.
53034 * FIXME - could do with a reset button..
53037 * Create a new ComboCheck
53038 * @param {Object} config Configuration options
53040 Roo.form.ComboCheck = function(config){
53041 Roo.form.ComboCheck.superclass.constructor.call(this, config);
53042 // should verify some data...
53044 // hiddenName = required..
53045 // displayField = required
53046 // valudField == required
53047 var req= [ 'hiddenName', 'displayField', 'valueField' ];
53049 Roo.each(req, function(e) {
53050 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
53051 throw "Roo.form.ComboCheck : missing value for: " + e;
53058 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
53063 selectedClass: 'x-menu-item-checked',
53066 onRender : function(ct, position){
53072 var cls = 'x-combo-list';
53075 this.tpl = new Roo.Template({
53076 html : '<div class="'+cls+'-item x-menu-check-item">' +
53077 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
53078 '<span>{' + this.displayField + '}</span>' +
53085 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
53086 this.view.singleSelect = false;
53087 this.view.multiSelect = true;
53088 this.view.toggleSelect = true;
53089 this.pageTb.add(new Roo.Toolbar.Fill(), {
53092 handler: function()
53099 onViewOver : function(e, t){
53105 onViewClick : function(doFocus,index){
53109 select: function () {
53110 //Roo.log("SELECT CALLED");
53113 selectByValue : function(xv, scrollIntoView){
53114 var ar = this.getValueArray();
53117 Roo.each(ar, function(v) {
53118 if(v === undefined || v === null){
53121 var r = this.findRecord(this.valueField, v);
53123 sels.push(this.store.indexOf(r))
53127 this.view.select(sels);
53133 onSelect : function(record, index){
53134 // Roo.log("onselect Called");
53135 // this is only called by the clear button now..
53136 this.view.clearSelections();
53137 this.setValue('[]');
53138 if (this.value != this.valueBefore) {
53139 this.fireEvent('change', this, this.value, this.valueBefore);
53140 this.valueBefore = this.value;
53143 getValueArray : function()
53148 //Roo.log(this.value);
53149 if (typeof(this.value) == 'undefined') {
53152 var ar = Roo.decode(this.value);
53153 return ar instanceof Array ? ar : []; //?? valid?
53156 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
53161 expand : function ()
53164 Roo.form.ComboCheck.superclass.expand.call(this);
53165 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
53166 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
53171 collapse : function(){
53172 Roo.form.ComboCheck.superclass.collapse.call(this);
53173 var sl = this.view.getSelectedIndexes();
53174 var st = this.store;
53178 Roo.each(sl, function(i) {
53180 nv.push(r.get(this.valueField));
53182 this.setValue(Roo.encode(nv));
53183 if (this.value != this.valueBefore) {
53185 this.fireEvent('change', this, this.value, this.valueBefore);
53186 this.valueBefore = this.value;
53191 setValue : function(v){
53195 var vals = this.getValueArray();
53197 Roo.each(vals, function(k) {
53198 var r = this.findRecord(this.valueField, k);
53200 tv.push(r.data[this.displayField]);
53201 }else if(this.valueNotFoundText !== undefined){
53202 tv.push( this.valueNotFoundText );
53207 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
53208 this.hiddenField.value = v;
53214 * Ext JS Library 1.1.1
53215 * Copyright(c) 2006-2007, Ext JS, LLC.
53217 * Originally Released Under LGPL - original licence link has changed is not relivant.
53220 * <script type="text/javascript">
53224 * @class Roo.form.Signature
53225 * @extends Roo.form.Field
53229 * @param {Object} config Configuration options
53232 Roo.form.Signature = function(config){
53233 Roo.form.Signature.superclass.constructor.call(this, config);
53235 this.addEvents({// not in used??
53238 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
53239 * @param {Roo.form.Signature} combo This combo box
53244 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
53245 * @param {Roo.form.ComboBox} combo This combo box
53246 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
53252 Roo.extend(Roo.form.Signature, Roo.form.Field, {
53254 * @cfg {Object} labels Label to use when rendering a form.
53258 * confirm : "Confirm"
53263 confirm : "Confirm"
53266 * @cfg {Number} width The signature panel width (defaults to 300)
53270 * @cfg {Number} height The signature panel height (defaults to 100)
53274 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
53276 allowBlank : false,
53279 // {Object} signPanel The signature SVG panel element (defaults to {})
53281 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
53282 isMouseDown : false,
53283 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
53284 isConfirmed : false,
53285 // {String} signatureTmp SVG mapping string (defaults to empty string)
53289 defaultAutoCreate : { // modified by initCompnoent..
53295 onRender : function(ct, position){
53297 Roo.form.Signature.superclass.onRender.call(this, ct, position);
53299 this.wrap = this.el.wrap({
53300 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
53303 this.createToolbar(this);
53304 this.signPanel = this.wrap.createChild({
53306 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
53310 this.svgID = Roo.id();
53311 this.svgEl = this.signPanel.createChild({
53312 xmlns : 'http://www.w3.org/2000/svg',
53314 id : this.svgID + "-svg",
53316 height: this.height,
53317 viewBox: '0 0 '+this.width+' '+this.height,
53321 id: this.svgID + "-svg-r",
53323 height: this.height,
53328 id: this.svgID + "-svg-l",
53330 y1: (this.height*0.8), // start set the line in 80% of height
53331 x2: this.width, // end
53332 y2: (this.height*0.8), // end set the line in 80% of height
53334 'stroke-width': "1",
53335 'stroke-dasharray': "3",
53336 'shape-rendering': "crispEdges",
53337 'pointer-events': "none"
53341 id: this.svgID + "-svg-p",
53343 'stroke-width': "3",
53345 'pointer-events': 'none'
53350 this.svgBox = this.svgEl.dom.getScreenCTM();
53352 createSVG : function(){
53353 var svg = this.signPanel;
53354 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
53357 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
53358 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
53359 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
53360 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
53361 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
53362 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
53363 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
53366 isTouchEvent : function(e){
53367 return e.type.match(/^touch/);
53369 getCoords : function (e) {
53370 var pt = this.svgEl.dom.createSVGPoint();
53373 if (this.isTouchEvent(e)) {
53374 pt.x = e.targetTouches[0].clientX;
53375 pt.y = e.targetTouches[0].clientY;
53377 var a = this.svgEl.dom.getScreenCTM();
53378 var b = a.inverse();
53379 var mx = pt.matrixTransform(b);
53380 return mx.x + ',' + mx.y;
53382 //mouse event headler
53383 down : function (e) {
53384 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
53385 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
53387 this.isMouseDown = true;
53389 e.preventDefault();
53391 move : function (e) {
53392 if (this.isMouseDown) {
53393 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
53394 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
53397 e.preventDefault();
53399 up : function (e) {
53400 this.isMouseDown = false;
53401 var sp = this.signatureTmp.split(' ');
53404 if(!sp[sp.length-2].match(/^L/)){
53408 this.signatureTmp = sp.join(" ");
53411 if(this.getValue() != this.signatureTmp){
53412 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
53413 this.isConfirmed = false;
53415 e.preventDefault();
53419 * Protected method that will not generally be called directly. It
53420 * is called when the editor creates its toolbar. Override this method if you need to
53421 * add custom toolbar buttons.
53422 * @param {HtmlEditor} editor
53424 createToolbar : function(editor){
53425 function btn(id, toggle, handler){
53426 var xid = fid + '-'+ id ;
53430 cls : 'x-btn-icon x-edit-'+id,
53431 enableToggle:toggle !== false,
53432 scope: editor, // was editor...
53433 handler:handler||editor.relayBtnCmd,
53434 clickEvent:'mousedown',
53435 tooltip: etb.buttonTips[id] || undefined, ///tips ???
53441 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
53445 cls : ' x-signature-btn x-signature-'+id,
53446 scope: editor, // was editor...
53447 handler: this.reset,
53448 clickEvent:'mousedown',
53449 text: this.labels.clear
53456 cls : ' x-signature-btn x-signature-'+id,
53457 scope: editor, // was editor...
53458 handler: this.confirmHandler,
53459 clickEvent:'mousedown',
53460 text: this.labels.confirm
53467 * when user is clicked confirm then show this image.....
53469 * @return {String} Image Data URI
53471 getImageDataURI : function(){
53472 var svg = this.svgEl.dom.parentNode.innerHTML;
53473 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
53478 * @return {Boolean} this.isConfirmed
53480 getConfirmed : function(){
53481 return this.isConfirmed;
53485 * @return {Number} this.width
53487 getWidth : function(){
53492 * @return {Number} this.height
53494 getHeight : function(){
53495 return this.height;
53498 getSignature : function(){
53499 return this.signatureTmp;
53502 reset : function(){
53503 this.signatureTmp = '';
53504 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
53505 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
53506 this.isConfirmed = false;
53507 Roo.form.Signature.superclass.reset.call(this);
53509 setSignature : function(s){
53510 this.signatureTmp = s;
53511 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
53512 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
53514 this.isConfirmed = false;
53515 Roo.form.Signature.superclass.reset.call(this);
53518 // Roo.log(this.signPanel.dom.contentWindow.up())
53521 setConfirmed : function(){
53525 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
53528 confirmHandler : function(){
53529 if(!this.getSignature()){
53533 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
53534 this.setValue(this.getSignature());
53535 this.isConfirmed = true;
53537 this.fireEvent('confirm', this);
53540 // Subclasses should provide the validation implementation by overriding this
53541 validateValue : function(value){
53542 if(this.allowBlank){
53546 if(this.isConfirmed){
53553 * Ext JS Library 1.1.1
53554 * Copyright(c) 2006-2007, Ext JS, LLC.
53556 * Originally Released Under LGPL - original licence link has changed is not relivant.
53559 * <script type="text/javascript">
53564 * @class Roo.form.ComboBox
53565 * @extends Roo.form.TriggerField
53566 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
53568 * Create a new ComboBox.
53569 * @param {Object} config Configuration options
53571 Roo.form.Select = function(config){
53572 Roo.form.Select.superclass.constructor.call(this, config);
53576 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
53578 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
53581 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
53582 * rendering into an Roo.Editor, defaults to false)
53585 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
53586 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
53589 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
53592 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
53593 * the dropdown list (defaults to undefined, with no header element)
53597 * @cfg {String/Roo.Template} tpl The template to use to render the output
53601 defaultAutoCreate : {tag: "select" },
53603 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
53605 listWidth: undefined,
53607 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
53608 * mode = 'remote' or 'text' if mode = 'local')
53610 displayField: undefined,
53612 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
53613 * mode = 'remote' or 'value' if mode = 'local').
53614 * Note: use of a valueField requires the user make a selection
53615 * in order for a value to be mapped.
53617 valueField: undefined,
53621 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
53622 * field's data value (defaults to the underlying DOM element's name)
53624 hiddenName: undefined,
53626 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
53630 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
53632 selectedClass: 'x-combo-selected',
53634 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
53635 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
53636 * which displays a downward arrow icon).
53638 triggerClass : 'x-form-arrow-trigger',
53640 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
53644 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
53645 * anchor positions (defaults to 'tl-bl')
53647 listAlign: 'tl-bl?',
53649 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
53653 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
53654 * query specified by the allQuery config option (defaults to 'query')
53656 triggerAction: 'query',
53658 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
53659 * (defaults to 4, does not apply if editable = false)
53663 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
53664 * delay (typeAheadDelay) if it matches a known value (defaults to false)
53668 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
53669 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
53673 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
53674 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
53678 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
53679 * when editable = true (defaults to false)
53681 selectOnFocus:false,
53683 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
53685 queryParam: 'query',
53687 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
53688 * when mode = 'remote' (defaults to 'Loading...')
53690 loadingText: 'Loading...',
53692 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
53696 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
53700 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
53701 * traditional select (defaults to true)
53705 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
53709 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
53713 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
53714 * listWidth has a higher value)
53718 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
53719 * allow the user to set arbitrary text into the field (defaults to false)
53721 forceSelection:false,
53723 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
53724 * if typeAhead = true (defaults to 250)
53726 typeAheadDelay : 250,
53728 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
53729 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
53731 valueNotFoundText : undefined,
53734 * @cfg {String} defaultValue The value displayed after loading the store.
53739 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
53741 blockFocus : false,
53744 * @cfg {Boolean} disableClear Disable showing of clear button.
53746 disableClear : false,
53748 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
53750 alwaysQuery : false,
53756 // element that contains real text value.. (when hidden is used..)
53759 onRender : function(ct, position){
53760 Roo.form.Field.prototype.onRender.call(this, ct, position);
53763 this.store.on('beforeload', this.onBeforeLoad, this);
53764 this.store.on('load', this.onLoad, this);
53765 this.store.on('loadexception', this.onLoadException, this);
53766 this.store.load({});
53774 initEvents : function(){
53775 //Roo.form.ComboBox.superclass.initEvents.call(this);
53779 onDestroy : function(){
53782 this.store.un('beforeload', this.onBeforeLoad, this);
53783 this.store.un('load', this.onLoad, this);
53784 this.store.un('loadexception', this.onLoadException, this);
53786 //Roo.form.ComboBox.superclass.onDestroy.call(this);
53790 fireKey : function(e){
53791 if(e.isNavKeyPress() && !this.list.isVisible()){
53792 this.fireEvent("specialkey", this, e);
53797 onResize: function(w, h){
53805 * Allow or prevent the user from directly editing the field text. If false is passed,
53806 * the user will only be able to select from the items defined in the dropdown list. This method
53807 * is the runtime equivalent of setting the 'editable' config option at config time.
53808 * @param {Boolean} value True to allow the user to directly edit the field text
53810 setEditable : function(value){
53815 onBeforeLoad : function(){
53817 Roo.log("Select before load");
53820 this.innerList.update(this.loadingText ?
53821 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
53822 //this.restrictHeight();
53823 this.selectedIndex = -1;
53827 onLoad : function(){
53830 var dom = this.el.dom;
53831 dom.innerHTML = '';
53832 var od = dom.ownerDocument;
53834 if (this.emptyText) {
53835 var op = od.createElement('option');
53836 op.setAttribute('value', '');
53837 op.innerHTML = String.format('{0}', this.emptyText);
53838 dom.appendChild(op);
53840 if(this.store.getCount() > 0){
53842 var vf = this.valueField;
53843 var df = this.displayField;
53844 this.store.data.each(function(r) {
53845 // which colmsn to use... testing - cdoe / title..
53846 var op = od.createElement('option');
53847 op.setAttribute('value', r.data[vf]);
53848 op.innerHTML = String.format('{0}', r.data[df]);
53849 dom.appendChild(op);
53851 if (typeof(this.defaultValue != 'undefined')) {
53852 this.setValue(this.defaultValue);
53857 //this.onEmptyResults();
53862 onLoadException : function()
53864 dom.innerHTML = '';
53866 Roo.log("Select on load exception");
53870 Roo.log(this.store.reader.jsonData);
53871 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
53872 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
53878 onTypeAhead : function(){
53883 onSelect : function(record, index){
53884 Roo.log('on select?');
53886 if(this.fireEvent('beforeselect', this, record, index) !== false){
53887 this.setFromData(index > -1 ? record.data : false);
53889 this.fireEvent('select', this, record, index);
53894 * Returns the currently selected field value or empty string if no value is set.
53895 * @return {String} value The selected value
53897 getValue : function(){
53898 var dom = this.el.dom;
53899 this.value = dom.options[dom.selectedIndex].value;
53905 * Clears any text/value currently set in the field
53907 clearValue : function(){
53909 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
53914 * Sets the specified value into the field. If the value finds a match, the corresponding record text
53915 * will be displayed in the field. If the value does not match the data value of an existing item,
53916 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
53917 * Otherwise the field will be blank (although the value will still be set).
53918 * @param {String} value The value to match
53920 setValue : function(v){
53921 var d = this.el.dom;
53922 for (var i =0; i < d.options.length;i++) {
53923 if (v == d.options[i].value) {
53924 d.selectedIndex = i;
53932 * @property {Object} the last set data for the element
53937 * Sets the value of the field based on a object which is related to the record format for the store.
53938 * @param {Object} value the value to set as. or false on reset?
53940 setFromData : function(o){
53941 Roo.log('setfrom data?');
53947 reset : function(){
53951 findRecord : function(prop, value){
53956 if(this.store.getCount() > 0){
53957 this.store.each(function(r){
53958 if(r.data[prop] == value){
53968 getName: function()
53970 // returns hidden if it's set..
53971 if (!this.rendered) {return ''};
53972 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
53980 onEmptyResults : function(){
53981 Roo.log('empty results');
53986 * Returns true if the dropdown list is expanded, else false.
53988 isExpanded : function(){
53993 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
53994 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
53995 * @param {String} value The data value of the item to select
53996 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
53997 * selected item if it is not currently in view (defaults to true)
53998 * @return {Boolean} True if the value matched an item in the list, else false
54000 selectByValue : function(v, scrollIntoView){
54001 Roo.log('select By Value');
54004 if(v !== undefined && v !== null){
54005 var r = this.findRecord(this.valueField || this.displayField, v);
54007 this.select(this.store.indexOf(r), scrollIntoView);
54015 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
54016 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
54017 * @param {Number} index The zero-based index of the list item to select
54018 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
54019 * selected item if it is not currently in view (defaults to true)
54021 select : function(index, scrollIntoView){
54022 Roo.log('select ');
54025 this.selectedIndex = index;
54026 this.view.select(index);
54027 if(scrollIntoView !== false){
54028 var el = this.view.getNode(index);
54030 this.innerList.scrollChildIntoView(el, false);
54038 validateBlur : function(){
54045 initQuery : function(){
54046 this.doQuery(this.getRawValue());
54050 doForce : function(){
54051 if(this.el.dom.value.length > 0){
54052 this.el.dom.value =
54053 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
54059 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
54060 * query allowing the query action to be canceled if needed.
54061 * @param {String} query The SQL query to execute
54062 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
54063 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
54064 * saved in the current store (defaults to false)
54066 doQuery : function(q, forceAll){
54068 Roo.log('doQuery?');
54069 if(q === undefined || q === null){
54074 forceAll: forceAll,
54078 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
54082 forceAll = qe.forceAll;
54083 if(forceAll === true || (q.length >= this.minChars)){
54084 if(this.lastQuery != q || this.alwaysQuery){
54085 this.lastQuery = q;
54086 if(this.mode == 'local'){
54087 this.selectedIndex = -1;
54089 this.store.clearFilter();
54091 this.store.filter(this.displayField, q);
54095 this.store.baseParams[this.queryParam] = q;
54097 params: this.getParams(q)
54102 this.selectedIndex = -1;
54109 getParams : function(q){
54111 //p[this.queryParam] = q;
54114 p.limit = this.pageSize;
54120 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
54122 collapse : function(){
54127 collapseIf : function(e){
54132 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
54134 expand : function(){
54142 * @cfg {Boolean} grow
54146 * @cfg {Number} growMin
54150 * @cfg {Number} growMax
54158 setWidth : function()
54162 getResizeEl : function(){
54165 });//<script type="text/javasscript">
54169 * @class Roo.DDView
54170 * A DnD enabled version of Roo.View.
54171 * @param {Element/String} container The Element in which to create the View.
54172 * @param {String} tpl The template string used to create the markup for each element of the View
54173 * @param {Object} config The configuration properties. These include all the config options of
54174 * {@link Roo.View} plus some specific to this class.<br>
54176 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
54177 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
54179 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
54180 .x-view-drag-insert-above {
54181 border-top:1px dotted #3366cc;
54183 .x-view-drag-insert-below {
54184 border-bottom:1px dotted #3366cc;
54190 Roo.DDView = function(container, tpl, config) {
54191 Roo.DDView.superclass.constructor.apply(this, arguments);
54192 this.getEl().setStyle("outline", "0px none");
54193 this.getEl().unselectable();
54194 if (this.dragGroup) {
54195 this.setDraggable(this.dragGroup.split(","));
54197 if (this.dropGroup) {
54198 this.setDroppable(this.dropGroup.split(","));
54200 if (this.deletable) {
54201 this.setDeletable();
54203 this.isDirtyFlag = false;
54209 Roo.extend(Roo.DDView, Roo.View, {
54210 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
54211 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
54212 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
54213 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
54217 reset: Roo.emptyFn,
54219 clearInvalid: Roo.form.Field.prototype.clearInvalid,
54221 validate: function() {
54225 destroy: function() {
54226 this.purgeListeners();
54227 this.getEl.removeAllListeners();
54228 this.getEl().remove();
54229 if (this.dragZone) {
54230 if (this.dragZone.destroy) {
54231 this.dragZone.destroy();
54234 if (this.dropZone) {
54235 if (this.dropZone.destroy) {
54236 this.dropZone.destroy();
54241 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
54242 getName: function() {
54246 /** Loads the View from a JSON string representing the Records to put into the Store. */
54247 setValue: function(v) {
54249 throw "DDView.setValue(). DDView must be constructed with a valid Store";
54252 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
54253 this.store.proxy = new Roo.data.MemoryProxy(data);
54257 /** @return {String} a parenthesised list of the ids of the Records in the View. */
54258 getValue: function() {
54260 this.store.each(function(rec) {
54261 result += rec.id + ',';
54263 return result.substr(0, result.length - 1) + ')';
54266 getIds: function() {
54267 var i = 0, result = new Array(this.store.getCount());
54268 this.store.each(function(rec) {
54269 result[i++] = rec.id;
54274 isDirty: function() {
54275 return this.isDirtyFlag;
54279 * Part of the Roo.dd.DropZone interface. If no target node is found, the
54280 * whole Element becomes the target, and this causes the drop gesture to append.
54282 getTargetFromEvent : function(e) {
54283 var target = e.getTarget();
54284 while ((target !== null) && (target.parentNode != this.el.dom)) {
54285 target = target.parentNode;
54288 target = this.el.dom.lastChild || this.el.dom;
54294 * Create the drag data which consists of an object which has the property "ddel" as
54295 * the drag proxy element.
54297 getDragData : function(e) {
54298 var target = this.findItemFromChild(e.getTarget());
54300 this.handleSelection(e);
54301 var selNodes = this.getSelectedNodes();
54304 copy: this.copy || (this.allowCopy && e.ctrlKey),
54308 var selectedIndices = this.getSelectedIndexes();
54309 for (var i = 0; i < selectedIndices.length; i++) {
54310 dragData.records.push(this.store.getAt(selectedIndices[i]));
54312 if (selNodes.length == 1) {
54313 dragData.ddel = target.cloneNode(true); // the div element
54315 var div = document.createElement('div'); // create the multi element drag "ghost"
54316 div.className = 'multi-proxy';
54317 for (var i = 0, len = selNodes.length; i < len; i++) {
54318 div.appendChild(selNodes[i].cloneNode(true));
54320 dragData.ddel = div;
54322 //console.log(dragData)
54323 //console.log(dragData.ddel.innerHTML)
54326 //console.log('nodragData')
54330 /** Specify to which ddGroup items in this DDView may be dragged. */
54331 setDraggable: function(ddGroup) {
54332 if (ddGroup instanceof Array) {
54333 Roo.each(ddGroup, this.setDraggable, this);
54336 if (this.dragZone) {
54337 this.dragZone.addToGroup(ddGroup);
54339 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
54340 containerScroll: true,
54344 // Draggability implies selection. DragZone's mousedown selects the element.
54345 if (!this.multiSelect) { this.singleSelect = true; }
54347 // Wire the DragZone's handlers up to methods in *this*
54348 this.dragZone.getDragData = this.getDragData.createDelegate(this);
54352 /** Specify from which ddGroup this DDView accepts drops. */
54353 setDroppable: function(ddGroup) {
54354 if (ddGroup instanceof Array) {
54355 Roo.each(ddGroup, this.setDroppable, this);
54358 if (this.dropZone) {
54359 this.dropZone.addToGroup(ddGroup);
54361 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
54362 containerScroll: true,
54366 // Wire the DropZone's handlers up to methods in *this*
54367 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
54368 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
54369 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
54370 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
54371 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
54375 /** Decide whether to drop above or below a View node. */
54376 getDropPoint : function(e, n, dd){
54377 if (n == this.el.dom) { return "above"; }
54378 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
54379 var c = t + (b - t) / 2;
54380 var y = Roo.lib.Event.getPageY(e);
54388 onNodeEnter : function(n, dd, e, data){
54392 onNodeOver : function(n, dd, e, data){
54393 var pt = this.getDropPoint(e, n, dd);
54394 // set the insert point style on the target node
54395 var dragElClass = this.dropNotAllowed;
54398 if (pt == "above"){
54399 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
54400 targetElClass = "x-view-drag-insert-above";
54402 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
54403 targetElClass = "x-view-drag-insert-below";
54405 if (this.lastInsertClass != targetElClass){
54406 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
54407 this.lastInsertClass = targetElClass;
54410 return dragElClass;
54413 onNodeOut : function(n, dd, e, data){
54414 this.removeDropIndicators(n);
54417 onNodeDrop : function(n, dd, e, data){
54418 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
54421 var pt = this.getDropPoint(e, n, dd);
54422 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
54423 if (pt == "below") { insertAt++; }
54424 for (var i = 0; i < data.records.length; i++) {
54425 var r = data.records[i];
54426 var dup = this.store.getById(r.id);
54427 if (dup && (dd != this.dragZone)) {
54428 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
54431 this.store.insert(insertAt++, r.copy());
54433 data.source.isDirtyFlag = true;
54435 this.store.insert(insertAt++, r);
54437 this.isDirtyFlag = true;
54440 this.dragZone.cachedTarget = null;
54444 removeDropIndicators : function(n){
54446 Roo.fly(n).removeClass([
54447 "x-view-drag-insert-above",
54448 "x-view-drag-insert-below"]);
54449 this.lastInsertClass = "_noclass";
54454 * Utility method. Add a delete option to the DDView's context menu.
54455 * @param {String} imageUrl The URL of the "delete" icon image.
54457 setDeletable: function(imageUrl) {
54458 if (!this.singleSelect && !this.multiSelect) {
54459 this.singleSelect = true;
54461 var c = this.getContextMenu();
54462 this.contextMenu.on("itemclick", function(item) {
54465 this.remove(this.getSelectedIndexes());
54469 this.contextMenu.add({
54476 /** Return the context menu for this DDView. */
54477 getContextMenu: function() {
54478 if (!this.contextMenu) {
54479 // Create the View's context menu
54480 this.contextMenu = new Roo.menu.Menu({
54481 id: this.id + "-contextmenu"
54483 this.el.on("contextmenu", this.showContextMenu, this);
54485 return this.contextMenu;
54488 disableContextMenu: function() {
54489 if (this.contextMenu) {
54490 this.el.un("contextmenu", this.showContextMenu, this);
54494 showContextMenu: function(e, item) {
54495 item = this.findItemFromChild(e.getTarget());
54498 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
54499 this.contextMenu.showAt(e.getXY());
54504 * Remove {@link Roo.data.Record}s at the specified indices.
54505 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
54507 remove: function(selectedIndices) {
54508 selectedIndices = [].concat(selectedIndices);
54509 for (var i = 0; i < selectedIndices.length; i++) {
54510 var rec = this.store.getAt(selectedIndices[i]);
54511 this.store.remove(rec);
54516 * Double click fires the event, but also, if this is draggable, and there is only one other
54517 * related DropZone, it transfers the selected node.
54519 onDblClick : function(e){
54520 var item = this.findItemFromChild(e.getTarget());
54522 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
54525 if (this.dragGroup) {
54526 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
54527 while (targets.indexOf(this.dropZone) > -1) {
54528 targets.remove(this.dropZone);
54530 if (targets.length == 1) {
54531 this.dragZone.cachedTarget = null;
54532 var el = Roo.get(targets[0].getEl());
54533 var box = el.getBox(true);
54534 targets[0].onNodeDrop(el.dom, {
54536 xy: [box.x, box.y + box.height - 1]
54537 }, null, this.getDragData(e));
54543 handleSelection: function(e) {
54544 this.dragZone.cachedTarget = null;
54545 var item = this.findItemFromChild(e.getTarget());
54547 this.clearSelections(true);
54550 if (item && (this.multiSelect || this.singleSelect)){
54551 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
54552 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
54553 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
54554 this.unselect(item);
54556 this.select(item, this.multiSelect && e.ctrlKey);
54557 this.lastSelection = item;
54562 onItemClick : function(item, index, e){
54563 if(this.fireEvent("beforeclick", this, index, item, e) === false){
54569 unselect : function(nodeInfo, suppressEvent){
54570 var node = this.getNode(nodeInfo);
54571 if(node && this.isSelected(node)){
54572 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
54573 Roo.fly(node).removeClass(this.selectedClass);
54574 this.selections.remove(node);
54575 if(!suppressEvent){
54576 this.fireEvent("selectionchange", this, this.selections);
54584 * Ext JS Library 1.1.1
54585 * Copyright(c) 2006-2007, Ext JS, LLC.
54587 * Originally Released Under LGPL - original licence link has changed is not relivant.
54590 * <script type="text/javascript">
54594 * @class Roo.LayoutManager
54595 * @extends Roo.util.Observable
54596 * Base class for layout managers.
54598 Roo.LayoutManager = function(container, config){
54599 Roo.LayoutManager.superclass.constructor.call(this);
54600 this.el = Roo.get(container);
54601 // ie scrollbar fix
54602 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
54603 document.body.scroll = "no";
54604 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
54605 this.el.position('relative');
54607 this.id = this.el.id;
54608 this.el.addClass("x-layout-container");
54609 /** false to disable window resize monitoring @type Boolean */
54610 this.monitorWindowResize = true;
54615 * Fires when a layout is performed.
54616 * @param {Roo.LayoutManager} this
54620 * @event regionresized
54621 * Fires when the user resizes a region.
54622 * @param {Roo.LayoutRegion} region The resized region
54623 * @param {Number} newSize The new size (width for east/west, height for north/south)
54625 "regionresized" : true,
54627 * @event regioncollapsed
54628 * Fires when a region is collapsed.
54629 * @param {Roo.LayoutRegion} region The collapsed region
54631 "regioncollapsed" : true,
54633 * @event regionexpanded
54634 * Fires when a region is expanded.
54635 * @param {Roo.LayoutRegion} region The expanded region
54637 "regionexpanded" : true
54639 this.updating = false;
54640 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
54643 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
54645 * Returns true if this layout is currently being updated
54646 * @return {Boolean}
54648 isUpdating : function(){
54649 return this.updating;
54653 * Suspend the LayoutManager from doing auto-layouts while
54654 * making multiple add or remove calls
54656 beginUpdate : function(){
54657 this.updating = true;
54661 * Restore auto-layouts and optionally disable the manager from performing a layout
54662 * @param {Boolean} noLayout true to disable a layout update
54664 endUpdate : function(noLayout){
54665 this.updating = false;
54671 layout: function(){
54675 onRegionResized : function(region, newSize){
54676 this.fireEvent("regionresized", region, newSize);
54680 onRegionCollapsed : function(region){
54681 this.fireEvent("regioncollapsed", region);
54684 onRegionExpanded : function(region){
54685 this.fireEvent("regionexpanded", region);
54689 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
54690 * performs box-model adjustments.
54691 * @return {Object} The size as an object {width: (the width), height: (the height)}
54693 getViewSize : function(){
54695 if(this.el.dom != document.body){
54696 size = this.el.getSize();
54698 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
54700 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
54701 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
54706 * Returns the Element this layout is bound to.
54707 * @return {Roo.Element}
54709 getEl : function(){
54714 * Returns the specified region.
54715 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
54716 * @return {Roo.LayoutRegion}
54718 getRegion : function(target){
54719 return this.regions[target.toLowerCase()];
54722 onWindowResize : function(){
54723 if(this.monitorWindowResize){
54729 * Ext JS Library 1.1.1
54730 * Copyright(c) 2006-2007, Ext JS, LLC.
54732 * Originally Released Under LGPL - original licence link has changed is not relivant.
54735 * <script type="text/javascript">
54738 * @class Roo.BorderLayout
54739 * @extends Roo.LayoutManager
54740 * @children Roo.ContentPanel
54741 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
54742 * please see: <br><br>
54743 * <a href="http://www.jackslocum.com/yui/2006/10/19/cross-browser-web-20-layouts-with-yahoo-ui/">Cross Browser Layouts - Part 1</a><br>
54744 * <a href="http://www.jackslocum.com/yui/2006/10/28/cross-browser-web-20-layouts-part-2-ajax-feed-viewer-20/">Cross Browser Layouts - Part 2</a><br><br>
54747 var layout = new Roo.BorderLayout(document.body, {
54781 preferredTabWidth: 150
54786 var CP = Roo.ContentPanel;
54788 layout.beginUpdate();
54789 layout.add("north", new CP("north", "North"));
54790 layout.add("south", new CP("south", {title: "South", closable: true}));
54791 layout.add("west", new CP("west", {title: "West"}));
54792 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
54793 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
54794 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
54795 layout.getRegion("center").showPanel("center1");
54796 layout.endUpdate();
54799 <b>The container the layout is rendered into can be either the body element or any other element.
54800 If it is not the body element, the container needs to either be an absolute positioned element,
54801 or you will need to add "position:relative" to the css of the container. You will also need to specify
54802 the container size if it is not the body element.</b>
54805 * Create a new BorderLayout
54806 * @param {String/HTMLElement/Element} container The container this layout is bound to
54807 * @param {Object} config Configuration options
54809 Roo.BorderLayout = function(container, config){
54810 config = config || {};
54811 Roo.BorderLayout.superclass.constructor.call(this, container, config);
54812 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
54813 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
54814 var target = this.factory.validRegions[i];
54815 if(config[target]){
54816 this.addRegion(target, config[target]);
54821 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
54824 * @cfg {Roo.LayoutRegion} east
54827 * @cfg {Roo.LayoutRegion} west
54830 * @cfg {Roo.LayoutRegion} north
54833 * @cfg {Roo.LayoutRegion} south
54836 * @cfg {Roo.LayoutRegion} center
54839 * Creates and adds a new region if it doesn't already exist.
54840 * @param {String} target The target region key (north, south, east, west or center).
54841 * @param {Object} config The regions config object
54842 * @return {BorderLayoutRegion} The new region
54844 addRegion : function(target, config){
54845 if(!this.regions[target]){
54846 var r = this.factory.create(target, this, config);
54847 this.bindRegion(target, r);
54849 return this.regions[target];
54853 bindRegion : function(name, r){
54854 this.regions[name] = r;
54855 r.on("visibilitychange", this.layout, this);
54856 r.on("paneladded", this.layout, this);
54857 r.on("panelremoved", this.layout, this);
54858 r.on("invalidated", this.layout, this);
54859 r.on("resized", this.onRegionResized, this);
54860 r.on("collapsed", this.onRegionCollapsed, this);
54861 r.on("expanded", this.onRegionExpanded, this);
54865 * Performs a layout update.
54867 layout : function(){
54868 if(this.updating) {
54871 var size = this.getViewSize();
54872 var w = size.width;
54873 var h = size.height;
54878 //var x = 0, y = 0;
54880 var rs = this.regions;
54881 var north = rs["north"];
54882 var south = rs["south"];
54883 var west = rs["west"];
54884 var east = rs["east"];
54885 var center = rs["center"];
54886 //if(this.hideOnLayout){ // not supported anymore
54887 //c.el.setStyle("display", "none");
54889 if(north && north.isVisible()){
54890 var b = north.getBox();
54891 var m = north.getMargins();
54892 b.width = w - (m.left+m.right);
54895 centerY = b.height + b.y + m.bottom;
54896 centerH -= centerY;
54897 north.updateBox(this.safeBox(b));
54899 if(south && south.isVisible()){
54900 var b = south.getBox();
54901 var m = south.getMargins();
54902 b.width = w - (m.left+m.right);
54904 var totalHeight = (b.height + m.top + m.bottom);
54905 b.y = h - totalHeight + m.top;
54906 centerH -= totalHeight;
54907 south.updateBox(this.safeBox(b));
54909 if(west && west.isVisible()){
54910 var b = west.getBox();
54911 var m = west.getMargins();
54912 b.height = centerH - (m.top+m.bottom);
54914 b.y = centerY + m.top;
54915 var totalWidth = (b.width + m.left + m.right);
54916 centerX += totalWidth;
54917 centerW -= totalWidth;
54918 west.updateBox(this.safeBox(b));
54920 if(east && east.isVisible()){
54921 var b = east.getBox();
54922 var m = east.getMargins();
54923 b.height = centerH - (m.top+m.bottom);
54924 var totalWidth = (b.width + m.left + m.right);
54925 b.x = w - totalWidth + m.left;
54926 b.y = centerY + m.top;
54927 centerW -= totalWidth;
54928 east.updateBox(this.safeBox(b));
54931 var m = center.getMargins();
54933 x: centerX + m.left,
54934 y: centerY + m.top,
54935 width: centerW - (m.left+m.right),
54936 height: centerH - (m.top+m.bottom)
54938 //if(this.hideOnLayout){
54939 //center.el.setStyle("display", "block");
54941 center.updateBox(this.safeBox(centerBox));
54944 this.fireEvent("layout", this);
54948 safeBox : function(box){
54949 box.width = Math.max(0, box.width);
54950 box.height = Math.max(0, box.height);
54955 * Adds a ContentPanel (or subclass) to this layout.
54956 * @param {String} target The target region key (north, south, east, west or center).
54957 * @param {Roo.ContentPanel} panel The panel to add
54958 * @return {Roo.ContentPanel} The added panel
54960 add : function(target, panel){
54962 target = target.toLowerCase();
54963 return this.regions[target].add(panel);
54967 * Remove a ContentPanel (or subclass) to this layout.
54968 * @param {String} target The target region key (north, south, east, west or center).
54969 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
54970 * @return {Roo.ContentPanel} The removed panel
54972 remove : function(target, panel){
54973 target = target.toLowerCase();
54974 return this.regions[target].remove(panel);
54978 * Searches all regions for a panel with the specified id
54979 * @param {String} panelId
54980 * @return {Roo.ContentPanel} The panel or null if it wasn't found
54982 findPanel : function(panelId){
54983 var rs = this.regions;
54984 for(var target in rs){
54985 if(typeof rs[target] != "function"){
54986 var p = rs[target].getPanel(panelId);
54996 * Searches all regions for a panel with the specified id and activates (shows) it.
54997 * @param {String/ContentPanel} panelId The panels id or the panel itself
54998 * @return {Roo.ContentPanel} The shown panel or null
55000 showPanel : function(panelId) {
55001 var rs = this.regions;
55002 for(var target in rs){
55003 var r = rs[target];
55004 if(typeof r != "function"){
55005 if(r.hasPanel(panelId)){
55006 return r.showPanel(panelId);
55014 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
55015 * @param {Roo.state.Provider} provider (optional) An alternate state provider
55017 restoreState : function(provider){
55019 provider = Roo.state.Manager;
55021 var sm = new Roo.LayoutStateManager();
55022 sm.init(this, provider);
55026 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
55027 * object should contain properties for each region to add ContentPanels to, and each property's value should be
55028 * a valid ContentPanel config object. Example:
55030 // Create the main layout
55031 var layout = new Roo.BorderLayout('main-ct', {
55042 // Create and add multiple ContentPanels at once via configs
55045 id: 'source-files',
55047 title:'Ext Source Files',
55060 * @param {Object} regions An object containing ContentPanel configs by region name
55062 batchAdd : function(regions){
55063 this.beginUpdate();
55064 for(var rname in regions){
55065 var lr = this.regions[rname];
55067 this.addTypedPanels(lr, regions[rname]);
55074 addTypedPanels : function(lr, ps){
55075 if(typeof ps == 'string'){
55076 lr.add(new Roo.ContentPanel(ps));
55078 else if(ps instanceof Array){
55079 for(var i =0, len = ps.length; i < len; i++){
55080 this.addTypedPanels(lr, ps[i]);
55083 else if(!ps.events){ // raw config?
55085 delete ps.el; // prevent conflict
55086 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
55088 else { // panel object assumed!
55093 * Adds a xtype elements to the layout.
55097 xtype : 'ContentPanel',
55104 xtype : 'NestedLayoutPanel',
55110 items : [ ... list of content panels or nested layout panels.. ]
55114 * @param {Object} cfg Xtype definition of item to add.
55116 addxtype : function(cfg)
55118 // basically accepts a pannel...
55119 // can accept a layout region..!?!?
55120 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
55122 if (!cfg.xtype.match(/Panel$/)) {
55127 if (typeof(cfg.region) == 'undefined') {
55128 Roo.log("Failed to add Panel, region was not set");
55132 var region = cfg.region;
55138 xitems = cfg.items;
55145 case 'ContentPanel': // ContentPanel (el, cfg)
55146 case 'ScrollPanel': // ContentPanel (el, cfg)
55148 if(cfg.autoCreate) {
55149 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
55151 var el = this.el.createChild();
55152 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
55155 this.add(region, ret);
55159 case 'TreePanel': // our new panel!
55160 cfg.el = this.el.createChild();
55161 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
55162 this.add(region, ret);
55165 case 'NestedLayoutPanel':
55166 // create a new Layout (which is a Border Layout...
55167 var el = this.el.createChild();
55168 var clayout = cfg.layout;
55170 clayout.items = clayout.items || [];
55171 // replace this exitems with the clayout ones..
55172 xitems = clayout.items;
55175 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
55176 cfg.background = false;
55178 var layout = new Roo.BorderLayout(el, clayout);
55180 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
55181 //console.log('adding nested layout panel ' + cfg.toSource());
55182 this.add(region, ret);
55183 nb = {}; /// find first...
55188 // needs grid and region
55190 //var el = this.getRegion(region).el.createChild();
55191 var el = this.el.createChild();
55192 // create the grid first...
55194 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
55196 if (region == 'center' && this.active ) {
55197 cfg.background = false;
55199 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
55201 this.add(region, ret);
55202 if (cfg.background) {
55203 ret.on('activate', function(gp) {
55204 if (!gp.grid.rendered) {
55219 if (typeof(Roo[cfg.xtype]) != 'undefined') {
55221 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
55222 this.add(region, ret);
55225 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
55229 // GridPanel (grid, cfg)
55232 this.beginUpdate();
55236 Roo.each(xitems, function(i) {
55237 region = nb && i.region ? i.region : false;
55239 var add = ret.addxtype(i);
55242 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
55243 if (!i.background) {
55244 abn[region] = nb[region] ;
55251 // make the last non-background panel active..
55252 //if (nb) { Roo.log(abn); }
55255 for(var r in abn) {
55256 region = this.getRegion(r);
55258 // tried using nb[r], but it does not work..
55260 region.showPanel(abn[r]);
55271 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
55272 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
55273 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
55274 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
55277 var CP = Roo.ContentPanel;
55279 var layout = Roo.BorderLayout.create({
55283 panels: [new CP("north", "North")]
55292 panels: [new CP("west", {title: "West"})]
55301 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
55310 panels: [new CP("south", {title: "South", closable: true})]
55317 preferredTabWidth: 150,
55319 new CP("center1", {title: "Close Me", closable: true}),
55320 new CP("center2", {title: "Center Panel", closable: false})
55325 layout.getRegion("center").showPanel("center1");
55330 Roo.BorderLayout.create = function(config, targetEl){
55331 var layout = new Roo.BorderLayout(targetEl || document.body, config);
55332 layout.beginUpdate();
55333 var regions = Roo.BorderLayout.RegionFactory.validRegions;
55334 for(var j = 0, jlen = regions.length; j < jlen; j++){
55335 var lr = regions[j];
55336 if(layout.regions[lr] && config[lr].panels){
55337 var r = layout.regions[lr];
55338 var ps = config[lr].panels;
55339 layout.addTypedPanels(r, ps);
55342 layout.endUpdate();
55347 Roo.BorderLayout.RegionFactory = {
55349 validRegions : ["north","south","east","west","center"],
55352 create : function(target, mgr, config){
55353 target = target.toLowerCase();
55354 if(config.lightweight || config.basic){
55355 return new Roo.BasicLayoutRegion(mgr, config, target);
55359 return new Roo.NorthLayoutRegion(mgr, config);
55361 return new Roo.SouthLayoutRegion(mgr, config);
55363 return new Roo.EastLayoutRegion(mgr, config);
55365 return new Roo.WestLayoutRegion(mgr, config);
55367 return new Roo.CenterLayoutRegion(mgr, config);
55369 throw 'Layout region "'+target+'" not supported.';
55373 * Ext JS Library 1.1.1
55374 * Copyright(c) 2006-2007, Ext JS, LLC.
55376 * Originally Released Under LGPL - original licence link has changed is not relivant.
55379 * <script type="text/javascript">
55383 * @class Roo.BasicLayoutRegion
55384 * @extends Roo.util.Observable
55385 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
55386 * and does not have a titlebar, tabs or any other features. All it does is size and position
55387 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
55389 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
55391 this.position = pos;
55394 * @scope Roo.BasicLayoutRegion
55398 * @event beforeremove
55399 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
55400 * @param {Roo.LayoutRegion} this
55401 * @param {Roo.ContentPanel} panel The panel
55402 * @param {Object} e The cancel event object
55404 "beforeremove" : true,
55406 * @event invalidated
55407 * Fires when the layout for this region is changed.
55408 * @param {Roo.LayoutRegion} this
55410 "invalidated" : true,
55412 * @event visibilitychange
55413 * Fires when this region is shown or hidden
55414 * @param {Roo.LayoutRegion} this
55415 * @param {Boolean} visibility true or false
55417 "visibilitychange" : true,
55419 * @event paneladded
55420 * Fires when a panel is added.
55421 * @param {Roo.LayoutRegion} this
55422 * @param {Roo.ContentPanel} panel The panel
55424 "paneladded" : true,
55426 * @event panelremoved
55427 * Fires when a panel is removed.
55428 * @param {Roo.LayoutRegion} this
55429 * @param {Roo.ContentPanel} panel The panel
55431 "panelremoved" : true,
55433 * @event beforecollapse
55434 * Fires when this region before collapse.
55435 * @param {Roo.LayoutRegion} this
55437 "beforecollapse" : true,
55440 * Fires when this region is collapsed.
55441 * @param {Roo.LayoutRegion} this
55443 "collapsed" : true,
55446 * Fires when this region is expanded.
55447 * @param {Roo.LayoutRegion} this
55452 * Fires when this region is slid into view.
55453 * @param {Roo.LayoutRegion} this
55455 "slideshow" : true,
55458 * Fires when this region slides out of view.
55459 * @param {Roo.LayoutRegion} this
55461 "slidehide" : true,
55463 * @event panelactivated
55464 * Fires when a panel is activated.
55465 * @param {Roo.LayoutRegion} this
55466 * @param {Roo.ContentPanel} panel The activated panel
55468 "panelactivated" : true,
55471 * Fires when the user resizes this region.
55472 * @param {Roo.LayoutRegion} this
55473 * @param {Number} newSize The new size (width for east/west, height for north/south)
55477 /** A collection of panels in this region. @type Roo.util.MixedCollection */
55478 this.panels = new Roo.util.MixedCollection();
55479 this.panels.getKey = this.getPanelId.createDelegate(this);
55481 this.activePanel = null;
55482 // ensure listeners are added...
55484 if (config.listeners || config.events) {
55485 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
55486 listeners : config.listeners || {},
55487 events : config.events || {}
55491 if(skipConfig !== true){
55492 this.applyConfig(config);
55496 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
55497 getPanelId : function(p){
55501 applyConfig : function(config){
55502 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
55503 this.config = config;
55508 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
55509 * the width, for horizontal (north, south) the height.
55510 * @param {Number} newSize The new width or height
55512 resizeTo : function(newSize){
55513 var el = this.el ? this.el :
55514 (this.activePanel ? this.activePanel.getEl() : null);
55516 switch(this.position){
55519 el.setWidth(newSize);
55520 this.fireEvent("resized", this, newSize);
55524 el.setHeight(newSize);
55525 this.fireEvent("resized", this, newSize);
55531 getBox : function(){
55532 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
55535 getMargins : function(){
55536 return this.margins;
55539 updateBox : function(box){
55541 var el = this.activePanel.getEl();
55542 el.dom.style.left = box.x + "px";
55543 el.dom.style.top = box.y + "px";
55544 this.activePanel.setSize(box.width, box.height);
55548 * Returns the container element for this region.
55549 * @return {Roo.Element}
55551 getEl : function(){
55552 return this.activePanel;
55556 * Returns true if this region is currently visible.
55557 * @return {Boolean}
55559 isVisible : function(){
55560 return this.activePanel ? true : false;
55563 setActivePanel : function(panel){
55564 panel = this.getPanel(panel);
55565 if(this.activePanel && this.activePanel != panel){
55566 this.activePanel.setActiveState(false);
55567 this.activePanel.getEl().setLeftTop(-10000,-10000);
55569 this.activePanel = panel;
55570 panel.setActiveState(true);
55572 panel.setSize(this.box.width, this.box.height);
55574 this.fireEvent("panelactivated", this, panel);
55575 this.fireEvent("invalidated");
55579 * Show the specified panel.
55580 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
55581 * @return {Roo.ContentPanel} The shown panel or null
55583 showPanel : function(panel){
55584 if(panel = this.getPanel(panel)){
55585 this.setActivePanel(panel);
55591 * Get the active panel for this region.
55592 * @return {Roo.ContentPanel} The active panel or null
55594 getActivePanel : function(){
55595 return this.activePanel;
55599 * Add the passed ContentPanel(s)
55600 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
55601 * @return {Roo.ContentPanel} The panel added (if only one was added)
55603 add : function(panel){
55604 if(arguments.length > 1){
55605 for(var i = 0, len = arguments.length; i < len; i++) {
55606 this.add(arguments[i]);
55610 if(this.hasPanel(panel)){
55611 this.showPanel(panel);
55614 var el = panel.getEl();
55615 if(el.dom.parentNode != this.mgr.el.dom){
55616 this.mgr.el.dom.appendChild(el.dom);
55618 if(panel.setRegion){
55619 panel.setRegion(this);
55621 this.panels.add(panel);
55622 el.setStyle("position", "absolute");
55623 if(!panel.background){
55624 this.setActivePanel(panel);
55625 if(this.config.initialSize && this.panels.getCount()==1){
55626 this.resizeTo(this.config.initialSize);
55629 this.fireEvent("paneladded", this, panel);
55634 * Returns true if the panel is in this region.
55635 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
55636 * @return {Boolean}
55638 hasPanel : function(panel){
55639 if(typeof panel == "object"){ // must be panel obj
55640 panel = panel.getId();
55642 return this.getPanel(panel) ? true : false;
55646 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
55647 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
55648 * @param {Boolean} preservePanel Overrides the config preservePanel option
55649 * @return {Roo.ContentPanel} The panel that was removed
55651 remove : function(panel, preservePanel){
55652 panel = this.getPanel(panel);
55657 this.fireEvent("beforeremove", this, panel, e);
55658 if(e.cancel === true){
55661 var panelId = panel.getId();
55662 this.panels.removeKey(panelId);
55667 * Returns the panel specified or null if it's not in this region.
55668 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
55669 * @return {Roo.ContentPanel}
55671 getPanel : function(id){
55672 if(typeof id == "object"){ // must be panel obj
55675 return this.panels.get(id);
55679 * Returns this regions position (north/south/east/west/center).
55682 getPosition: function(){
55683 return this.position;
55687 * Ext JS Library 1.1.1
55688 * Copyright(c) 2006-2007, Ext JS, LLC.
55690 * Originally Released Under LGPL - original licence link has changed is not relivant.
55693 * <script type="text/javascript">
55697 * @class Roo.LayoutRegion
55698 * @extends Roo.BasicLayoutRegion
55699 * This class represents a region in a layout manager.
55700 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
55701 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
55702 * @cfg {Boolean} floatable False to disable floating (defaults to true)
55703 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
55704 * @cfg {Object} cmargins Margins for the element when collapsed (defaults to: north/south {top: 2, left: 0, right:0, bottom: 2} or east/west {top: 0, left: 2, right:2, bottom: 0})
55705 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
55706 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
55707 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
55708 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
55709 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
55710 * @cfg {String} title The title for the region (overrides panel titles)
55711 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
55712 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
55713 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
55714 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
55715 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
55716 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
55717 * the space available, similar to FireFox 1.5 tabs (defaults to false)
55718 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
55719 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
55720 * @cfg {Boolean} showPin True to show a pin button
55721 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
55722 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
55723 * @cfg {Boolean} disableTabTips True to disable tab tooltips
55724 * @cfg {Number} width For East/West panels
55725 * @cfg {Number} height For North/South panels
55726 * @cfg {Boolean} split To show the splitter
55727 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
55729 Roo.LayoutRegion = function(mgr, config, pos){
55730 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
55731 var dh = Roo.DomHelper;
55732 /** This region's container element
55733 * @type Roo.Element */
55734 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
55735 /** This region's title element
55736 * @type Roo.Element */
55738 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
55739 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
55740 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
55742 this.titleEl.enableDisplayMode();
55743 /** This region's title text element
55744 * @type HTMLElement */
55745 this.titleTextEl = this.titleEl.dom.firstChild;
55746 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
55747 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
55748 this.closeBtn.enableDisplayMode();
55749 this.closeBtn.on("click", this.closeClicked, this);
55750 this.closeBtn.hide();
55752 this.createBody(config);
55753 this.visible = true;
55754 this.collapsed = false;
55756 if(config.hideWhenEmpty){
55758 this.on("paneladded", this.validateVisibility, this);
55759 this.on("panelremoved", this.validateVisibility, this);
55761 this.applyConfig(config);
55764 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
55766 createBody : function(){
55767 /** This region's body element
55768 * @type Roo.Element */
55769 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
55772 applyConfig : function(c){
55773 if(c.collapsible && this.position != "center" && !this.collapsedEl){
55774 var dh = Roo.DomHelper;
55775 if(c.titlebar !== false){
55776 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
55777 this.collapseBtn.on("click", this.collapse, this);
55778 this.collapseBtn.enableDisplayMode();
55780 if(c.showPin === true || this.showPin){
55781 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
55782 this.stickBtn.enableDisplayMode();
55783 this.stickBtn.on("click", this.expand, this);
55784 this.stickBtn.hide();
55787 /** This region's collapsed element
55788 * @type Roo.Element */
55789 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
55790 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
55792 if(c.floatable !== false){
55793 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
55794 this.collapsedEl.on("click", this.collapseClick, this);
55797 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
55798 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
55799 id: "message", unselectable: "on", style:{"float":"left"}});
55800 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
55802 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
55803 this.expandBtn.on("click", this.expand, this);
55805 if(this.collapseBtn){
55806 this.collapseBtn.setVisible(c.collapsible == true);
55808 this.cmargins = c.cmargins || this.cmargins ||
55809 (this.position == "west" || this.position == "east" ?
55810 {top: 0, left: 2, right:2, bottom: 0} :
55811 {top: 2, left: 0, right:0, bottom: 2});
55812 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
55813 this.bottomTabs = c.tabPosition != "top";
55814 this.autoScroll = c.autoScroll || false;
55815 if(this.autoScroll){
55816 this.bodyEl.setStyle("overflow", "auto");
55818 this.bodyEl.setStyle("overflow", "hidden");
55820 //if(c.titlebar !== false){
55821 if((!c.titlebar && !c.title) || c.titlebar === false){
55822 this.titleEl.hide();
55824 this.titleEl.show();
55826 this.titleTextEl.innerHTML = c.title;
55830 this.duration = c.duration || .30;
55831 this.slideDuration = c.slideDuration || .45;
55834 this.collapse(true);
55841 * Returns true if this region is currently visible.
55842 * @return {Boolean}
55844 isVisible : function(){
55845 return this.visible;
55849 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
55850 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
55852 setCollapsedTitle : function(title){
55853 title = title || " ";
55854 if(this.collapsedTitleTextEl){
55855 this.collapsedTitleTextEl.innerHTML = title;
55859 getBox : function(){
55861 if(!this.collapsed){
55862 b = this.el.getBox(false, true);
55864 b = this.collapsedEl.getBox(false, true);
55869 getMargins : function(){
55870 return this.collapsed ? this.cmargins : this.margins;
55873 highlight : function(){
55874 this.el.addClass("x-layout-panel-dragover");
55877 unhighlight : function(){
55878 this.el.removeClass("x-layout-panel-dragover");
55881 updateBox : function(box){
55883 if(!this.collapsed){
55884 this.el.dom.style.left = box.x + "px";
55885 this.el.dom.style.top = box.y + "px";
55886 this.updateBody(box.width, box.height);
55888 this.collapsedEl.dom.style.left = box.x + "px";
55889 this.collapsedEl.dom.style.top = box.y + "px";
55890 this.collapsedEl.setSize(box.width, box.height);
55893 this.tabs.autoSizeTabs();
55897 updateBody : function(w, h){
55899 this.el.setWidth(w);
55900 w -= this.el.getBorderWidth("rl");
55901 if(this.config.adjustments){
55902 w += this.config.adjustments[0];
55906 this.el.setHeight(h);
55907 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
55908 h -= this.el.getBorderWidth("tb");
55909 if(this.config.adjustments){
55910 h += this.config.adjustments[1];
55912 this.bodyEl.setHeight(h);
55914 h = this.tabs.syncHeight(h);
55917 if(this.panelSize){
55918 w = w !== null ? w : this.panelSize.width;
55919 h = h !== null ? h : this.panelSize.height;
55921 if(this.activePanel){
55922 var el = this.activePanel.getEl();
55923 w = w !== null ? w : el.getWidth();
55924 h = h !== null ? h : el.getHeight();
55925 this.panelSize = {width: w, height: h};
55926 this.activePanel.setSize(w, h);
55928 if(Roo.isIE && this.tabs){
55929 this.tabs.el.repaint();
55934 * Returns the container element for this region.
55935 * @return {Roo.Element}
55937 getEl : function(){
55942 * Hides this region.
55945 if(!this.collapsed){
55946 this.el.dom.style.left = "-2000px";
55949 this.collapsedEl.dom.style.left = "-2000px";
55950 this.collapsedEl.hide();
55952 this.visible = false;
55953 this.fireEvent("visibilitychange", this, false);
55957 * Shows this region if it was previously hidden.
55960 if(!this.collapsed){
55963 this.collapsedEl.show();
55965 this.visible = true;
55966 this.fireEvent("visibilitychange", this, true);
55969 closeClicked : function(){
55970 if(this.activePanel){
55971 this.remove(this.activePanel);
55975 collapseClick : function(e){
55977 e.stopPropagation();
55980 e.stopPropagation();
55986 * Collapses this region.
55987 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
55989 collapse : function(skipAnim, skipCheck){
55990 if(this.collapsed) {
55994 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
55996 this.collapsed = true;
55998 this.split.el.hide();
56000 if(this.config.animate && skipAnim !== true){
56001 this.fireEvent("invalidated", this);
56002 this.animateCollapse();
56004 this.el.setLocation(-20000,-20000);
56006 this.collapsedEl.show();
56007 this.fireEvent("collapsed", this);
56008 this.fireEvent("invalidated", this);
56014 animateCollapse : function(){
56019 * Expands this region if it was previously collapsed.
56020 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
56021 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
56023 expand : function(e, skipAnim){
56025 e.stopPropagation();
56027 if(!this.collapsed || this.el.hasActiveFx()) {
56031 this.afterSlideIn();
56034 this.collapsed = false;
56035 if(this.config.animate && skipAnim !== true){
56036 this.animateExpand();
56040 this.split.el.show();
56042 this.collapsedEl.setLocation(-2000,-2000);
56043 this.collapsedEl.hide();
56044 this.fireEvent("invalidated", this);
56045 this.fireEvent("expanded", this);
56049 animateExpand : function(){
56053 initTabs : function()
56055 this.bodyEl.setStyle("overflow", "hidden");
56056 var ts = new Roo.TabPanel(
56059 tabPosition: this.bottomTabs ? 'bottom' : 'top',
56060 disableTooltips: this.config.disableTabTips,
56061 toolbar : this.config.toolbar
56064 if(this.config.hideTabs){
56065 ts.stripWrap.setDisplayed(false);
56068 ts.resizeTabs = this.config.resizeTabs === true;
56069 ts.minTabWidth = this.config.minTabWidth || 40;
56070 ts.maxTabWidth = this.config.maxTabWidth || 250;
56071 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
56072 ts.monitorResize = false;
56073 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
56074 ts.bodyEl.addClass('x-layout-tabs-body');
56075 this.panels.each(this.initPanelAsTab, this);
56078 initPanelAsTab : function(panel){
56079 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
56080 this.config.closeOnTab && panel.isClosable());
56081 if(panel.tabTip !== undefined){
56082 ti.setTooltip(panel.tabTip);
56084 ti.on("activate", function(){
56085 this.setActivePanel(panel);
56087 if(this.config.closeOnTab){
56088 ti.on("beforeclose", function(t, e){
56090 this.remove(panel);
56096 updatePanelTitle : function(panel, title){
56097 if(this.activePanel == panel){
56098 this.updateTitle(title);
56101 var ti = this.tabs.getTab(panel.getEl().id);
56103 if(panel.tabTip !== undefined){
56104 ti.setTooltip(panel.tabTip);
56109 updateTitle : function(title){
56110 if(this.titleTextEl && !this.config.title){
56111 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
56115 setActivePanel : function(panel){
56116 panel = this.getPanel(panel);
56117 if(this.activePanel && this.activePanel != panel){
56118 this.activePanel.setActiveState(false);
56120 this.activePanel = panel;
56121 panel.setActiveState(true);
56122 if(this.panelSize){
56123 panel.setSize(this.panelSize.width, this.panelSize.height);
56126 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
56128 this.updateTitle(panel.getTitle());
56130 this.fireEvent("invalidated", this);
56132 this.fireEvent("panelactivated", this, panel);
56136 * Shows the specified panel.
56137 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
56138 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
56140 showPanel : function(panel)
56142 panel = this.getPanel(panel);
56145 var tab = this.tabs.getTab(panel.getEl().id);
56146 if(tab.isHidden()){
56147 this.tabs.unhideTab(tab.id);
56151 this.setActivePanel(panel);
56158 * Get the active panel for this region.
56159 * @return {Roo.ContentPanel} The active panel or null
56161 getActivePanel : function(){
56162 return this.activePanel;
56165 validateVisibility : function(){
56166 if(this.panels.getCount() < 1){
56167 this.updateTitle(" ");
56168 this.closeBtn.hide();
56171 if(!this.isVisible()){
56178 * Adds the passed ContentPanel(s) to this region.
56179 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
56180 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
56182 add : function(panel){
56183 if(arguments.length > 1){
56184 for(var i = 0, len = arguments.length; i < len; i++) {
56185 this.add(arguments[i]);
56189 if(this.hasPanel(panel)){
56190 this.showPanel(panel);
56193 panel.setRegion(this);
56194 this.panels.add(panel);
56195 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
56196 this.bodyEl.dom.appendChild(panel.getEl().dom);
56197 if(panel.background !== true){
56198 this.setActivePanel(panel);
56200 this.fireEvent("paneladded", this, panel);
56206 this.initPanelAsTab(panel);
56208 if(panel.background !== true){
56209 this.tabs.activate(panel.getEl().id);
56211 this.fireEvent("paneladded", this, panel);
56216 * Hides the tab for the specified panel.
56217 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
56219 hidePanel : function(panel){
56220 if(this.tabs && (panel = this.getPanel(panel))){
56221 this.tabs.hideTab(panel.getEl().id);
56226 * Unhides the tab for a previously hidden panel.
56227 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
56229 unhidePanel : function(panel){
56230 if(this.tabs && (panel = this.getPanel(panel))){
56231 this.tabs.unhideTab(panel.getEl().id);
56235 clearPanels : function(){
56236 while(this.panels.getCount() > 0){
56237 this.remove(this.panels.first());
56242 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
56243 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
56244 * @param {Boolean} preservePanel Overrides the config preservePanel option
56245 * @return {Roo.ContentPanel} The panel that was removed
56247 remove : function(panel, preservePanel){
56248 panel = this.getPanel(panel);
56253 this.fireEvent("beforeremove", this, panel, e);
56254 if(e.cancel === true){
56257 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
56258 var panelId = panel.getId();
56259 this.panels.removeKey(panelId);
56261 document.body.appendChild(panel.getEl().dom);
56264 this.tabs.removeTab(panel.getEl().id);
56265 }else if (!preservePanel){
56266 this.bodyEl.dom.removeChild(panel.getEl().dom);
56268 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
56269 var p = this.panels.first();
56270 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
56271 tempEl.appendChild(p.getEl().dom);
56272 this.bodyEl.update("");
56273 this.bodyEl.dom.appendChild(p.getEl().dom);
56275 this.updateTitle(p.getTitle());
56277 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
56278 this.setActivePanel(p);
56280 panel.setRegion(null);
56281 if(this.activePanel == panel){
56282 this.activePanel = null;
56284 if(this.config.autoDestroy !== false && preservePanel !== true){
56285 try{panel.destroy();}catch(e){}
56287 this.fireEvent("panelremoved", this, panel);
56292 * Returns the TabPanel component used by this region
56293 * @return {Roo.TabPanel}
56295 getTabs : function(){
56299 createTool : function(parentEl, className){
56300 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
56301 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
56302 btn.addClassOnOver("x-layout-tools-button-over");
56307 * Ext JS Library 1.1.1
56308 * Copyright(c) 2006-2007, Ext JS, LLC.
56310 * Originally Released Under LGPL - original licence link has changed is not relivant.
56313 * <script type="text/javascript">
56319 * @class Roo.SplitLayoutRegion
56320 * @extends Roo.LayoutRegion
56321 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
56323 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
56324 this.cursor = cursor;
56325 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
56328 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
56329 splitTip : "Drag to resize.",
56330 collapsibleSplitTip : "Drag to resize. Double click to hide.",
56331 useSplitTips : false,
56333 applyConfig : function(config){
56334 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
56337 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
56338 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
56339 /** The SplitBar for this region
56340 * @type Roo.SplitBar */
56341 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
56342 this.split.on("moved", this.onSplitMove, this);
56343 this.split.useShim = config.useShim === true;
56344 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
56345 if(this.useSplitTips){
56346 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
56348 if(config.collapsible){
56349 this.split.el.on("dblclick", this.collapse, this);
56352 if(typeof config.minSize != "undefined"){
56353 this.split.minSize = config.minSize;
56355 if(typeof config.maxSize != "undefined"){
56356 this.split.maxSize = config.maxSize;
56358 if(config.hideWhenEmpty || config.hidden || config.collapsed){
56359 this.hideSplitter();
56364 getHMaxSize : function(){
56365 var cmax = this.config.maxSize || 10000;
56366 var center = this.mgr.getRegion("center");
56367 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
56370 getVMaxSize : function(){
56371 var cmax = this.config.maxSize || 10000;
56372 var center = this.mgr.getRegion("center");
56373 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
56376 onSplitMove : function(split, newSize){
56377 this.fireEvent("resized", this, newSize);
56381 * Returns the {@link Roo.SplitBar} for this region.
56382 * @return {Roo.SplitBar}
56384 getSplitBar : function(){
56389 this.hideSplitter();
56390 Roo.SplitLayoutRegion.superclass.hide.call(this);
56393 hideSplitter : function(){
56395 this.split.el.setLocation(-2000,-2000);
56396 this.split.el.hide();
56402 this.split.el.show();
56404 Roo.SplitLayoutRegion.superclass.show.call(this);
56407 beforeSlide: function(){
56408 if(Roo.isGecko){// firefox overflow auto bug workaround
56409 this.bodyEl.clip();
56411 this.tabs.bodyEl.clip();
56413 if(this.activePanel){
56414 this.activePanel.getEl().clip();
56416 if(this.activePanel.beforeSlide){
56417 this.activePanel.beforeSlide();
56423 afterSlide : function(){
56424 if(Roo.isGecko){// firefox overflow auto bug workaround
56425 this.bodyEl.unclip();
56427 this.tabs.bodyEl.unclip();
56429 if(this.activePanel){
56430 this.activePanel.getEl().unclip();
56431 if(this.activePanel.afterSlide){
56432 this.activePanel.afterSlide();
56438 initAutoHide : function(){
56439 if(this.autoHide !== false){
56440 if(!this.autoHideHd){
56441 var st = new Roo.util.DelayedTask(this.slideIn, this);
56442 this.autoHideHd = {
56443 "mouseout": function(e){
56444 if(!e.within(this.el, true)){
56448 "mouseover" : function(e){
56454 this.el.on(this.autoHideHd);
56458 clearAutoHide : function(){
56459 if(this.autoHide !== false){
56460 this.el.un("mouseout", this.autoHideHd.mouseout);
56461 this.el.un("mouseover", this.autoHideHd.mouseover);
56465 clearMonitor : function(){
56466 Roo.get(document).un("click", this.slideInIf, this);
56469 // these names are backwards but not changed for compat
56470 slideOut : function(){
56471 if(this.isSlid || this.el.hasActiveFx()){
56474 this.isSlid = true;
56475 if(this.collapseBtn){
56476 this.collapseBtn.hide();
56478 this.closeBtnState = this.closeBtn.getStyle('display');
56479 this.closeBtn.hide();
56481 this.stickBtn.show();
56484 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
56485 this.beforeSlide();
56486 this.el.setStyle("z-index", 10001);
56487 this.el.slideIn(this.getSlideAnchor(), {
56488 callback: function(){
56490 this.initAutoHide();
56491 Roo.get(document).on("click", this.slideInIf, this);
56492 this.fireEvent("slideshow", this);
56499 afterSlideIn : function(){
56500 this.clearAutoHide();
56501 this.isSlid = false;
56502 this.clearMonitor();
56503 this.el.setStyle("z-index", "");
56504 if(this.collapseBtn){
56505 this.collapseBtn.show();
56507 this.closeBtn.setStyle('display', this.closeBtnState);
56509 this.stickBtn.hide();
56511 this.fireEvent("slidehide", this);
56514 slideIn : function(cb){
56515 if(!this.isSlid || this.el.hasActiveFx()){
56519 this.isSlid = false;
56520 this.beforeSlide();
56521 this.el.slideOut(this.getSlideAnchor(), {
56522 callback: function(){
56523 this.el.setLeftTop(-10000, -10000);
56525 this.afterSlideIn();
56533 slideInIf : function(e){
56534 if(!e.within(this.el)){
56539 animateCollapse : function(){
56540 this.beforeSlide();
56541 this.el.setStyle("z-index", 20000);
56542 var anchor = this.getSlideAnchor();
56543 this.el.slideOut(anchor, {
56544 callback : function(){
56545 this.el.setStyle("z-index", "");
56546 this.collapsedEl.slideIn(anchor, {duration:.3});
56548 this.el.setLocation(-10000,-10000);
56550 this.fireEvent("collapsed", this);
56557 animateExpand : function(){
56558 this.beforeSlide();
56559 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
56560 this.el.setStyle("z-index", 20000);
56561 this.collapsedEl.hide({
56564 this.el.slideIn(this.getSlideAnchor(), {
56565 callback : function(){
56566 this.el.setStyle("z-index", "");
56569 this.split.el.show();
56571 this.fireEvent("invalidated", this);
56572 this.fireEvent("expanded", this);
56600 getAnchor : function(){
56601 return this.anchors[this.position];
56604 getCollapseAnchor : function(){
56605 return this.canchors[this.position];
56608 getSlideAnchor : function(){
56609 return this.sanchors[this.position];
56612 getAlignAdj : function(){
56613 var cm = this.cmargins;
56614 switch(this.position){
56630 getExpandAdj : function(){
56631 var c = this.collapsedEl, cm = this.cmargins;
56632 switch(this.position){
56634 return [-(cm.right+c.getWidth()+cm.left), 0];
56637 return [cm.right+c.getWidth()+cm.left, 0];
56640 return [0, -(cm.top+cm.bottom+c.getHeight())];
56643 return [0, cm.top+cm.bottom+c.getHeight()];
56649 * Ext JS Library 1.1.1
56650 * Copyright(c) 2006-2007, Ext JS, LLC.
56652 * Originally Released Under LGPL - original licence link has changed is not relivant.
56655 * <script type="text/javascript">
56658 * These classes are private internal classes
56660 Roo.CenterLayoutRegion = function(mgr, config){
56661 Roo.LayoutRegion.call(this, mgr, config, "center");
56662 this.visible = true;
56663 this.minWidth = config.minWidth || 20;
56664 this.minHeight = config.minHeight || 20;
56667 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
56669 // center panel can't be hidden
56673 // center panel can't be hidden
56676 getMinWidth: function(){
56677 return this.minWidth;
56680 getMinHeight: function(){
56681 return this.minHeight;
56686 Roo.NorthLayoutRegion = function(mgr, config){
56687 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
56689 this.split.placement = Roo.SplitBar.TOP;
56690 this.split.orientation = Roo.SplitBar.VERTICAL;
56691 this.split.el.addClass("x-layout-split-v");
56693 var size = config.initialSize || config.height;
56694 if(typeof size != "undefined"){
56695 this.el.setHeight(size);
56698 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
56699 orientation: Roo.SplitBar.VERTICAL,
56700 getBox : function(){
56701 if(this.collapsed){
56702 return this.collapsedEl.getBox();
56704 var box = this.el.getBox();
56706 box.height += this.split.el.getHeight();
56711 updateBox : function(box){
56712 if(this.split && !this.collapsed){
56713 box.height -= this.split.el.getHeight();
56714 this.split.el.setLeft(box.x);
56715 this.split.el.setTop(box.y+box.height);
56716 this.split.el.setWidth(box.width);
56718 if(this.collapsed){
56719 this.updateBody(box.width, null);
56721 Roo.LayoutRegion.prototype.updateBox.call(this, box);
56725 Roo.SouthLayoutRegion = function(mgr, config){
56726 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
56728 this.split.placement = Roo.SplitBar.BOTTOM;
56729 this.split.orientation = Roo.SplitBar.VERTICAL;
56730 this.split.el.addClass("x-layout-split-v");
56732 var size = config.initialSize || config.height;
56733 if(typeof size != "undefined"){
56734 this.el.setHeight(size);
56737 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
56738 orientation: Roo.SplitBar.VERTICAL,
56739 getBox : function(){
56740 if(this.collapsed){
56741 return this.collapsedEl.getBox();
56743 var box = this.el.getBox();
56745 var sh = this.split.el.getHeight();
56752 updateBox : function(box){
56753 if(this.split && !this.collapsed){
56754 var sh = this.split.el.getHeight();
56757 this.split.el.setLeft(box.x);
56758 this.split.el.setTop(box.y-sh);
56759 this.split.el.setWidth(box.width);
56761 if(this.collapsed){
56762 this.updateBody(box.width, null);
56764 Roo.LayoutRegion.prototype.updateBox.call(this, box);
56768 Roo.EastLayoutRegion = function(mgr, config){
56769 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
56771 this.split.placement = Roo.SplitBar.RIGHT;
56772 this.split.orientation = Roo.SplitBar.HORIZONTAL;
56773 this.split.el.addClass("x-layout-split-h");
56775 var size = config.initialSize || config.width;
56776 if(typeof size != "undefined"){
56777 this.el.setWidth(size);
56780 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
56781 orientation: Roo.SplitBar.HORIZONTAL,
56782 getBox : function(){
56783 if(this.collapsed){
56784 return this.collapsedEl.getBox();
56786 var box = this.el.getBox();
56788 var sw = this.split.el.getWidth();
56795 updateBox : function(box){
56796 if(this.split && !this.collapsed){
56797 var sw = this.split.el.getWidth();
56799 this.split.el.setLeft(box.x);
56800 this.split.el.setTop(box.y);
56801 this.split.el.setHeight(box.height);
56804 if(this.collapsed){
56805 this.updateBody(null, box.height);
56807 Roo.LayoutRegion.prototype.updateBox.call(this, box);
56811 Roo.WestLayoutRegion = function(mgr, config){
56812 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
56814 this.split.placement = Roo.SplitBar.LEFT;
56815 this.split.orientation = Roo.SplitBar.HORIZONTAL;
56816 this.split.el.addClass("x-layout-split-h");
56818 var size = config.initialSize || config.width;
56819 if(typeof size != "undefined"){
56820 this.el.setWidth(size);
56823 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
56824 orientation: Roo.SplitBar.HORIZONTAL,
56825 getBox : function(){
56826 if(this.collapsed){
56827 return this.collapsedEl.getBox();
56829 var box = this.el.getBox();
56831 box.width += this.split.el.getWidth();
56836 updateBox : function(box){
56837 if(this.split && !this.collapsed){
56838 var sw = this.split.el.getWidth();
56840 this.split.el.setLeft(box.x+box.width);
56841 this.split.el.setTop(box.y);
56842 this.split.el.setHeight(box.height);
56844 if(this.collapsed){
56845 this.updateBody(null, box.height);
56847 Roo.LayoutRegion.prototype.updateBox.call(this, box);
56852 * Ext JS Library 1.1.1
56853 * Copyright(c) 2006-2007, Ext JS, LLC.
56855 * Originally Released Under LGPL - original licence link has changed is not relivant.
56858 * <script type="text/javascript">
56863 * Private internal class for reading and applying state
56865 Roo.LayoutStateManager = function(layout){
56866 // default empty state
56875 Roo.LayoutStateManager.prototype = {
56876 init : function(layout, provider){
56877 this.provider = provider;
56878 var state = provider.get(layout.id+"-layout-state");
56880 var wasUpdating = layout.isUpdating();
56882 layout.beginUpdate();
56884 for(var key in state){
56885 if(typeof state[key] != "function"){
56886 var rstate = state[key];
56887 var r = layout.getRegion(key);
56890 r.resizeTo(rstate.size);
56892 if(rstate.collapsed == true){
56895 r.expand(null, true);
56901 layout.endUpdate();
56903 this.state = state;
56905 this.layout = layout;
56906 layout.on("regionresized", this.onRegionResized, this);
56907 layout.on("regioncollapsed", this.onRegionCollapsed, this);
56908 layout.on("regionexpanded", this.onRegionExpanded, this);
56911 storeState : function(){
56912 this.provider.set(this.layout.id+"-layout-state", this.state);
56915 onRegionResized : function(region, newSize){
56916 this.state[region.getPosition()].size = newSize;
56920 onRegionCollapsed : function(region){
56921 this.state[region.getPosition()].collapsed = true;
56925 onRegionExpanded : function(region){
56926 this.state[region.getPosition()].collapsed = false;
56931 * Ext JS Library 1.1.1
56932 * Copyright(c) 2006-2007, Ext JS, LLC.
56934 * Originally Released Under LGPL - original licence link has changed is not relivant.
56937 * <script type="text/javascript">
56940 * @class Roo.ContentPanel
56941 * @extends Roo.util.Observable
56942 * @children Roo.form.Form Roo.JsonView Roo.View
56943 * @parent Roo.BorderLayout Roo.LayoutDialog builder
56944 * A basic ContentPanel element.
56945 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
56946 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
56947 * @cfg {Boolean|Object} autoCreate True to auto generate the DOM element for this panel, or a {@link Roo.DomHelper} config of the element to create
56948 * @cfg {Boolean} closable True if the panel can be closed/removed
56949 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
56950 * @cfg {String|HTMLElement|Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
56951 * @cfg {Roo.Toolbar} toolbar A toolbar for this panel
56952 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
56953 * @cfg {String} title The title for this panel
56954 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
56955 * @cfg {String} url Calls {@link #setUrl} with this value
56956 * @cfg {String} region (center|north|south|east|west) [required] which region to put this panel on (when used with xtype constructors)
56957 * @cfg {String|Object} params When used with {@link #url}, calls {@link #setUrl} with this value
56958 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
56959 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
56960 * @cfg {String} style Extra style to add to the content panel
56961 * @cfg {Roo.menu.Menu} menu popup menu
56964 * Create a new ContentPanel.
56965 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
56966 * @param {String/Object} config A string to set only the title or a config object
56967 * @param {String} content (optional) Set the HTML content for this panel
56968 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
56970 Roo.ContentPanel = function(el, config, content){
56974 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
56978 if (config && config.parentLayout) {
56979 el = config.parentLayout.el.createChild();
56982 if(el.autoCreate){ // xtype is available if this is called from factory
56986 this.el = Roo.get(el);
56987 if(!this.el && config && config.autoCreate){
56988 if(typeof config.autoCreate == "object"){
56989 if(!config.autoCreate.id){
56990 config.autoCreate.id = config.id||el;
56992 this.el = Roo.DomHelper.append(document.body,
56993 config.autoCreate, true);
56995 this.el = Roo.DomHelper.append(document.body,
56996 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
57001 this.closable = false;
57002 this.loaded = false;
57003 this.active = false;
57004 if(typeof config == "string"){
57005 this.title = config;
57007 Roo.apply(this, config);
57010 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
57011 this.wrapEl = this.el.wrap();
57012 this.toolbar.container = this.el.insertSibling(false, 'before');
57013 this.toolbar = new Roo.Toolbar(this.toolbar);
57016 // xtype created footer. - not sure if will work as we normally have to render first..
57017 if (this.footer && !this.footer.el && this.footer.xtype) {
57018 if (!this.wrapEl) {
57019 this.wrapEl = this.el.wrap();
57022 this.footer.container = this.wrapEl.createChild();
57024 this.footer = Roo.factory(this.footer, Roo);
57029 this.resizeEl = Roo.get(this.resizeEl, true);
57031 this.resizeEl = this.el;
57033 // handle view.xtype
57041 * Fires when this panel is activated.
57042 * @param {Roo.ContentPanel} this
57046 * @event deactivate
57047 * Fires when this panel is activated.
57048 * @param {Roo.ContentPanel} this
57050 "deactivate" : true,
57054 * Fires when this panel is resized if fitToFrame is true.
57055 * @param {Roo.ContentPanel} this
57056 * @param {Number} width The width after any component adjustments
57057 * @param {Number} height The height after any component adjustments
57063 * Fires when this tab is created
57064 * @param {Roo.ContentPanel} this
57074 if(this.autoScroll){
57075 this.resizeEl.setStyle("overflow", "auto");
57077 // fix randome scrolling
57078 this.el.on('scroll', function() {
57079 Roo.log('fix random scolling');
57080 this.scrollTo('top',0);
57083 content = content || this.content;
57085 this.setContent(content);
57087 if(config && config.url){
57088 this.setUrl(this.url, this.params, this.loadOnce);
57093 Roo.ContentPanel.superclass.constructor.call(this);
57095 if (this.view && typeof(this.view.xtype) != 'undefined') {
57096 this.view.el = this.el.appendChild(document.createElement("div"));
57097 this.view = Roo.factory(this.view);
57098 this.view.render && this.view.render(false, '');
57102 this.fireEvent('render', this);
57105 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
57107 setRegion : function(region){
57108 this.region = region;
57110 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
57112 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
57117 * Returns the toolbar for this Panel if one was configured.
57118 * @return {Roo.Toolbar}
57120 getToolbar : function(){
57121 return this.toolbar;
57124 setActiveState : function(active){
57125 this.active = active;
57127 this.fireEvent("deactivate", this);
57129 this.fireEvent("activate", this);
57133 * Updates this panel's element
57134 * @param {String} content The new content
57135 * @param {Boolean} loadScripts (optional) true to look for and process scripts
57137 setContent : function(content, loadScripts){
57138 this.el.update(content, loadScripts);
57141 ignoreResize : function(w, h){
57142 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
57145 this.lastSize = {width: w, height: h};
57150 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
57151 * @return {Roo.UpdateManager} The UpdateManager
57153 getUpdateManager : function(){
57154 return this.el.getUpdateManager();
57157 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
57158 * @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:
57161 url: "your-url.php",
57162 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
57163 callback: yourFunction,
57164 scope: yourObject, //(optional scope)
57167 text: "Loading...",
57172 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
57173 * are shorthand for <i>disableCaching</i>, <i>indicatorText</i> and <i>loadScripts</i> and are used to set their associated property on this panel UpdateManager instance.
57174 * @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}
57175 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
57176 * @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.
57177 * @return {Roo.ContentPanel} this
57180 var um = this.el.getUpdateManager();
57181 um.update.apply(um, arguments);
57187 * Set a URL to be used to load the content for this panel. When this panel is activated, the content will be loaded from that URL.
57188 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
57189 * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
57190 * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this panel is activated. (Defaults to false)
57191 * @return {Roo.UpdateManager} The UpdateManager
57193 setUrl : function(url, params, loadOnce){
57194 if(this.refreshDelegate){
57195 this.removeListener("activate", this.refreshDelegate);
57197 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
57198 this.on("activate", this.refreshDelegate);
57199 return this.el.getUpdateManager();
57202 _handleRefresh : function(url, params, loadOnce){
57203 if(!loadOnce || !this.loaded){
57204 var updater = this.el.getUpdateManager();
57205 updater.update(url, params, this._setLoaded.createDelegate(this));
57209 _setLoaded : function(){
57210 this.loaded = true;
57214 * Returns this panel's id
57217 getId : function(){
57222 * Returns this panel's element - used by regiosn to add.
57223 * @return {Roo.Element}
57225 getEl : function(){
57226 return this.wrapEl || this.el;
57229 adjustForComponents : function(width, height)
57231 //Roo.log('adjustForComponents ');
57232 if(this.resizeEl != this.el){
57233 width -= this.el.getFrameWidth('lr');
57234 height -= this.el.getFrameWidth('tb');
57237 var te = this.toolbar.getEl();
57238 height -= te.getHeight();
57239 te.setWidth(width);
57242 var te = this.footer.getEl();
57243 //Roo.log("footer:" + te.getHeight());
57245 height -= te.getHeight();
57246 te.setWidth(width);
57250 if(this.adjustments){
57251 width += this.adjustments[0];
57252 height += this.adjustments[1];
57254 return {"width": width, "height": height};
57257 setSize : function(width, height){
57258 if(this.fitToFrame && !this.ignoreResize(width, height)){
57259 if(this.fitContainer && this.resizeEl != this.el){
57260 this.el.setSize(width, height);
57262 var size = this.adjustForComponents(width, height);
57263 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
57264 this.fireEvent('resize', this, size.width, size.height);
57269 * Returns this panel's title
57272 getTitle : function(){
57277 * Set this panel's title
57278 * @param {String} title
57280 setTitle : function(title){
57281 this.title = title;
57283 this.region.updatePanelTitle(this, title);
57288 * Returns true is this panel was configured to be closable
57289 * @return {Boolean}
57291 isClosable : function(){
57292 return this.closable;
57295 beforeSlide : function(){
57297 this.resizeEl.clip();
57300 afterSlide : function(){
57302 this.resizeEl.unclip();
57306 * Force a content refresh from the URL specified in the {@link #setUrl} method.
57307 * Will fail silently if the {@link #setUrl} method has not been called.
57308 * This does not activate the panel, just updates its content.
57310 refresh : function(){
57311 if(this.refreshDelegate){
57312 this.loaded = false;
57313 this.refreshDelegate();
57318 * Destroys this panel
57320 destroy : function(){
57321 this.el.removeAllListeners();
57322 var tempEl = document.createElement("span");
57323 tempEl.appendChild(this.el.dom);
57324 tempEl.innerHTML = "";
57330 * form - if the content panel contains a form - this is a reference to it.
57331 * @type {Roo.form.Form}
57335 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
57336 * This contains a reference to it.
57342 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
57352 * @param {Object} cfg Xtype definition of item to add.
57355 addxtype : function(cfg) {
57357 if (cfg.xtype.match(/^Form$/)) {
57360 //if (this.footer) {
57361 // el = this.footer.container.insertSibling(false, 'before');
57363 el = this.el.createChild();
57366 this.form = new Roo.form.Form(cfg);
57369 if ( this.form.allItems.length) {
57370 this.form.render(el.dom);
57374 // should only have one of theses..
57375 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
57376 // views.. should not be just added - used named prop 'view''
57378 cfg.el = this.el.appendChild(document.createElement("div"));
57381 var ret = new Roo.factory(cfg);
57383 ret.render && ret.render(false, ''); // render blank..
57392 * @class Roo.GridPanel
57393 * @extends Roo.ContentPanel
57394 * @parent Roo.BorderLayout Roo.LayoutDialog builder
57396 * Create a new GridPanel.
57397 * @cfg {Roo.grid.Grid} grid The grid for this panel
57399 Roo.GridPanel = function(grid, config){
57401 // universal ctor...
57402 if (typeof(grid.grid) != 'undefined') {
57404 grid = config.grid;
57406 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
57407 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
57409 this.wrapper.dom.appendChild(grid.getGridEl().dom);
57411 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
57414 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
57416 // xtype created footer. - not sure if will work as we normally have to render first..
57417 if (this.footer && !this.footer.el && this.footer.xtype) {
57419 this.footer.container = this.grid.getView().getFooterPanel(true);
57420 this.footer.dataSource = this.grid.dataSource;
57421 this.footer = Roo.factory(this.footer, Roo);
57425 grid.monitorWindowResize = false; // turn off autosizing
57426 grid.autoHeight = false;
57427 grid.autoWidth = false;
57429 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
57432 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
57433 getId : function(){
57434 return this.grid.id;
57438 * Returns the grid for this panel
57439 * @return {Roo.grid.Grid}
57441 getGrid : function(){
57445 setSize : function(width, height){
57446 if(!this.ignoreResize(width, height)){
57447 var grid = this.grid;
57448 var size = this.adjustForComponents(width, height);
57449 grid.getGridEl().setSize(size.width, size.height);
57454 beforeSlide : function(){
57455 this.grid.getView().scroller.clip();
57458 afterSlide : function(){
57459 this.grid.getView().scroller.unclip();
57462 destroy : function(){
57463 this.grid.destroy();
57465 Roo.GridPanel.superclass.destroy.call(this);
57471 * @class Roo.NestedLayoutPanel
57472 * @extends Roo.ContentPanel
57473 * @parent Roo.BorderLayout Roo.LayoutDialog builder
57474 * @cfg Roo.BorderLayout} layout [required] The layout for this panel
57478 * Create a new NestedLayoutPanel.
57481 * @param {Roo.BorderLayout} layout [required] The layout for this panel
57482 * @param {String/Object} config A string to set only the title or a config object
57484 Roo.NestedLayoutPanel = function(layout, config)
57486 // construct with only one argument..
57487 /* FIXME - implement nicer consturctors
57488 if (layout.layout) {
57490 layout = config.layout;
57491 delete config.layout;
57493 if (layout.xtype && !layout.getEl) {
57494 // then layout needs constructing..
57495 layout = Roo.factory(layout, Roo);
57500 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
57502 layout.monitorWindowResize = false; // turn off autosizing
57503 this.layout = layout;
57504 this.layout.getEl().addClass("x-layout-nested-layout");
57511 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
57513 setSize : function(width, height){
57514 if(!this.ignoreResize(width, height)){
57515 var size = this.adjustForComponents(width, height);
57516 var el = this.layout.getEl();
57517 el.setSize(size.width, size.height);
57518 var touch = el.dom.offsetWidth;
57519 this.layout.layout();
57520 // ie requires a double layout on the first pass
57521 if(Roo.isIE && !this.initialized){
57522 this.initialized = true;
57523 this.layout.layout();
57528 // activate all subpanels if not currently active..
57530 setActiveState : function(active){
57531 this.active = active;
57533 this.fireEvent("deactivate", this);
57537 this.fireEvent("activate", this);
57538 // not sure if this should happen before or after..
57539 if (!this.layout) {
57540 return; // should not happen..
57543 for (var r in this.layout.regions) {
57544 reg = this.layout.getRegion(r);
57545 if (reg.getActivePanel()) {
57546 //reg.showPanel(reg.getActivePanel()); // force it to activate..
57547 reg.setActivePanel(reg.getActivePanel());
57550 if (!reg.panels.length) {
57553 reg.showPanel(reg.getPanel(0));
57562 * Returns the nested BorderLayout for this panel
57563 * @return {Roo.BorderLayout}
57565 getLayout : function(){
57566 return this.layout;
57570 * Adds a xtype elements to the layout of the nested panel
57574 xtype : 'ContentPanel',
57581 xtype : 'NestedLayoutPanel',
57587 items : [ ... list of content panels or nested layout panels.. ]
57591 * @param {Object} cfg Xtype definition of item to add.
57593 addxtype : function(cfg) {
57594 return this.layout.addxtype(cfg);
57599 Roo.ScrollPanel = function(el, config, content){
57600 config = config || {};
57601 config.fitToFrame = true;
57602 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
57604 this.el.dom.style.overflow = "hidden";
57605 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
57606 this.el.removeClass("x-layout-inactive-content");
57607 this.el.on("mousewheel", this.onWheel, this);
57609 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
57610 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
57611 up.unselectable(); down.unselectable();
57612 up.on("click", this.scrollUp, this);
57613 down.on("click", this.scrollDown, this);
57614 up.addClassOnOver("x-scroller-btn-over");
57615 down.addClassOnOver("x-scroller-btn-over");
57616 up.addClassOnClick("x-scroller-btn-click");
57617 down.addClassOnClick("x-scroller-btn-click");
57618 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
57620 this.resizeEl = this.el;
57621 this.el = wrap; this.up = up; this.down = down;
57624 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
57626 wheelIncrement : 5,
57627 scrollUp : function(){
57628 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
57631 scrollDown : function(){
57632 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
57635 afterScroll : function(){
57636 var el = this.resizeEl;
57637 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
57638 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
57639 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
57642 setSize : function(){
57643 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
57644 this.afterScroll();
57647 onWheel : function(e){
57648 var d = e.getWheelDelta();
57649 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
57650 this.afterScroll();
57654 setContent : function(content, loadScripts){
57655 this.resizeEl.update(content, loadScripts);
57663 * @class Roo.TreePanel
57664 * @extends Roo.ContentPanel
57665 * @parent Roo.BorderLayout Roo.LayoutDialog builder
57666 * Treepanel component
57669 * Create a new TreePanel. - defaults to fit/scoll contents.
57670 * @param {String/Object} config A string to set only the panel's title, or a config object
57672 Roo.TreePanel = function(config){
57673 var el = config.el;
57674 var tree = config.tree;
57675 delete config.tree;
57676 delete config.el; // hopefull!
57678 // wrapper for IE7 strict & safari scroll issue
57680 var treeEl = el.createChild();
57681 config.resizeEl = treeEl;
57685 Roo.TreePanel.superclass.constructor.call(this, el, config);
57688 this.tree = new Roo.tree.TreePanel(treeEl , tree);
57689 //console.log(tree);
57690 this.on('activate', function()
57692 if (this.tree.rendered) {
57695 //console.log('render tree');
57696 this.tree.render();
57698 // this should not be needed.. - it's actually the 'el' that resizes?
57699 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
57701 //this.on('resize', function (cp, w, h) {
57702 // this.tree.innerCt.setWidth(w);
57703 // this.tree.innerCt.setHeight(h);
57704 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
57711 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
57715 * @cfg {Roo.tree.TreePanel} tree [required] The tree TreePanel, with config etc.
57733 * Ext JS Library 1.1.1
57734 * Copyright(c) 2006-2007, Ext JS, LLC.
57736 * Originally Released Under LGPL - original licence link has changed is not relivant.
57739 * <script type="text/javascript">
57744 * @class Roo.ReaderLayout
57745 * @extends Roo.BorderLayout
57746 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
57747 * center region containing two nested regions (a top one for a list view and one for item preview below),
57748 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
57749 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
57750 * expedites the setup of the overall layout and regions for this common application style.
57753 var reader = new Roo.ReaderLayout();
57754 var CP = Roo.ContentPanel; // shortcut for adding
57756 reader.beginUpdate();
57757 reader.add("north", new CP("north", "North"));
57758 reader.add("west", new CP("west", {title: "West"}));
57759 reader.add("east", new CP("east", {title: "East"}));
57761 reader.regions.listView.add(new CP("listView", "List"));
57762 reader.regions.preview.add(new CP("preview", "Preview"));
57763 reader.endUpdate();
57766 * Create a new ReaderLayout
57767 * @param {Object} config Configuration options
57768 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
57769 * document.body if omitted)
57771 Roo.ReaderLayout = function(config, renderTo){
57772 var c = config || {size:{}};
57773 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
57774 north: c.north !== false ? Roo.apply({
57778 }, c.north) : false,
57779 west: c.west !== false ? Roo.apply({
57787 margins:{left:5,right:0,bottom:5,top:5},
57788 cmargins:{left:5,right:5,bottom:5,top:5}
57789 }, c.west) : false,
57790 east: c.east !== false ? Roo.apply({
57798 margins:{left:0,right:5,bottom:5,top:5},
57799 cmargins:{left:5,right:5,bottom:5,top:5}
57800 }, c.east) : false,
57801 center: Roo.apply({
57802 tabPosition: 'top',
57806 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
57810 this.el.addClass('x-reader');
57812 this.beginUpdate();
57814 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
57815 south: c.preview !== false ? Roo.apply({
57822 cmargins:{top:5,left:0, right:0, bottom:0}
57823 }, c.preview) : false,
57824 center: Roo.apply({
57830 this.add('center', new Roo.NestedLayoutPanel(inner,
57831 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
57835 this.regions.preview = inner.getRegion('south');
57836 this.regions.listView = inner.getRegion('center');
57839 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
57841 * Ext JS Library 1.1.1
57842 * Copyright(c) 2006-2007, Ext JS, LLC.
57844 * Originally Released Under LGPL - original licence link has changed is not relivant.
57847 * <script type="text/javascript">
57851 * @class Roo.grid.Grid
57852 * @extends Roo.util.Observable
57853 * This class represents the primary interface of a component based grid control.
57854 * <br><br>Usage:<pre><code>
57855 var grid = new Roo.grid.Grid("my-container-id", {
57858 selModel: mySelectionModel,
57859 autoSizeColumns: true,
57860 monitorWindowResize: false,
57861 trackMouseOver: true
57866 * <b>Common Problems:</b><br/>
57867 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
57868 * element will correct this<br/>
57869 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
57870 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
57871 * are unpredictable.<br/>
57872 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
57873 * grid to calculate dimensions/offsets.<br/>
57875 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
57876 * The container MUST have some type of size defined for the grid to fill. The container will be
57877 * automatically set to position relative if it isn't already.
57878 * @param {Object} config A config object that sets properties on this grid.
57880 Roo.grid.Grid = function(container, config){
57881 // initialize the container
57882 this.container = Roo.get(container);
57883 this.container.update("");
57884 this.container.setStyle("overflow", "hidden");
57885 this.container.addClass('x-grid-container');
57887 this.id = this.container.id;
57889 Roo.apply(this, config);
57890 // check and correct shorthanded configs
57892 this.dataSource = this.ds;
57896 this.colModel = this.cm;
57900 this.selModel = this.sm;
57904 if (this.selModel) {
57905 this.selModel = Roo.factory(this.selModel, Roo.grid);
57906 this.sm = this.selModel;
57907 this.sm.xmodule = this.xmodule || false;
57909 if (typeof(this.colModel.config) == 'undefined') {
57910 this.colModel = new Roo.grid.ColumnModel(this.colModel);
57911 this.cm = this.colModel;
57912 this.cm.xmodule = this.xmodule || false;
57914 if (this.dataSource) {
57915 this.dataSource= Roo.factory(this.dataSource, Roo.data);
57916 this.ds = this.dataSource;
57917 this.ds.xmodule = this.xmodule || false;
57924 this.container.setWidth(this.width);
57928 this.container.setHeight(this.height);
57935 * The raw click event for the entire grid.
57936 * @param {Roo.EventObject} e
57941 * The raw dblclick event for the entire grid.
57942 * @param {Roo.EventObject} e
57946 * @event contextmenu
57947 * The raw contextmenu event for the entire grid.
57948 * @param {Roo.EventObject} e
57950 "contextmenu" : true,
57953 * The raw mousedown event for the entire grid.
57954 * @param {Roo.EventObject} e
57956 "mousedown" : true,
57959 * The raw mouseup event for the entire grid.
57960 * @param {Roo.EventObject} e
57965 * The raw mouseover event for the entire grid.
57966 * @param {Roo.EventObject} e
57968 "mouseover" : true,
57971 * The raw mouseout event for the entire grid.
57972 * @param {Roo.EventObject} e
57977 * The raw keypress event for the entire grid.
57978 * @param {Roo.EventObject} e
57983 * The raw keydown event for the entire grid.
57984 * @param {Roo.EventObject} e
57992 * Fires when a cell is clicked
57993 * @param {Grid} this
57994 * @param {Number} rowIndex
57995 * @param {Number} columnIndex
57996 * @param {Roo.EventObject} e
57998 "cellclick" : true,
58000 * @event celldblclick
58001 * Fires when a cell is double clicked
58002 * @param {Grid} this
58003 * @param {Number} rowIndex
58004 * @param {Number} columnIndex
58005 * @param {Roo.EventObject} e
58007 "celldblclick" : true,
58010 * Fires when a row is clicked
58011 * @param {Grid} this
58012 * @param {Number} rowIndex
58013 * @param {Roo.EventObject} e
58017 * @event rowdblclick
58018 * Fires when a row is double clicked
58019 * @param {Grid} this
58020 * @param {Number} rowIndex
58021 * @param {Roo.EventObject} e
58023 "rowdblclick" : true,
58025 * @event headerclick
58026 * Fires when a header is clicked
58027 * @param {Grid} this
58028 * @param {Number} columnIndex
58029 * @param {Roo.EventObject} e
58031 "headerclick" : true,
58033 * @event headerdblclick
58034 * Fires when a header cell is double clicked
58035 * @param {Grid} this
58036 * @param {Number} columnIndex
58037 * @param {Roo.EventObject} e
58039 "headerdblclick" : true,
58041 * @event rowcontextmenu
58042 * Fires when a row is right clicked
58043 * @param {Grid} this
58044 * @param {Number} rowIndex
58045 * @param {Roo.EventObject} e
58047 "rowcontextmenu" : true,
58049 * @event cellcontextmenu
58050 * Fires when a cell is right clicked
58051 * @param {Grid} this
58052 * @param {Number} rowIndex
58053 * @param {Number} cellIndex
58054 * @param {Roo.EventObject} e
58056 "cellcontextmenu" : true,
58058 * @event headercontextmenu
58059 * Fires when a header is right clicked
58060 * @param {Grid} this
58061 * @param {Number} columnIndex
58062 * @param {Roo.EventObject} e
58064 "headercontextmenu" : true,
58066 * @event bodyscroll
58067 * Fires when the body element is scrolled
58068 * @param {Number} scrollLeft
58069 * @param {Number} scrollTop
58071 "bodyscroll" : true,
58073 * @event columnresize
58074 * Fires when the user resizes a column
58075 * @param {Number} columnIndex
58076 * @param {Number} newSize
58078 "columnresize" : true,
58080 * @event columnmove
58081 * Fires when the user moves a column
58082 * @param {Number} oldIndex
58083 * @param {Number} newIndex
58085 "columnmove" : true,
58088 * Fires when row(s) start being dragged
58089 * @param {Grid} this
58090 * @param {Roo.GridDD} dd The drag drop object
58091 * @param {event} e The raw browser event
58093 "startdrag" : true,
58096 * Fires when a drag operation is complete
58097 * @param {Grid} this
58098 * @param {Roo.GridDD} dd The drag drop object
58099 * @param {event} e The raw browser event
58104 * Fires when dragged row(s) are dropped on a valid DD target
58105 * @param {Grid} this
58106 * @param {Roo.GridDD} dd The drag drop object
58107 * @param {String} targetId The target drag drop object
58108 * @param {event} e The raw browser event
58113 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
58114 * @param {Grid} this
58115 * @param {Roo.GridDD} dd The drag drop object
58116 * @param {String} targetId The target drag drop object
58117 * @param {event} e The raw browser event
58122 * Fires when the dragged row(s) first cross another DD target while being dragged
58123 * @param {Grid} this
58124 * @param {Roo.GridDD} dd The drag drop object
58125 * @param {String} targetId The target drag drop object
58126 * @param {event} e The raw browser event
58128 "dragenter" : true,
58131 * Fires when the dragged row(s) leave another DD target while being dragged
58132 * @param {Grid} this
58133 * @param {Roo.GridDD} dd The drag drop object
58134 * @param {String} targetId The target drag drop object
58135 * @param {event} e The raw browser event
58140 * Fires when a row is rendered, so you can change add a style to it.
58141 * @param {GridView} gridview The grid view
58142 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
58148 * Fires when the grid is rendered
58149 * @param {Grid} grid
58154 Roo.grid.Grid.superclass.constructor.call(this);
58156 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
58159 * @cfg {Roo.grid.AbstractSelectionModel} sm The selection Model (default = Roo.grid.RowSelectionModel)
58162 * @cfg {Roo.grid.GridView} view The view that renders the grid (default = Roo.grid.GridView)
58165 * @cfg {Roo.grid.ColumnModel} cm[] The columns of the grid
58168 * @cfg {Roo.grid.Store} ds The data store for the grid
58171 * @cfg {Roo.Toolbar} toolbar a toolbar for buttons etc.
58174 * @cfg {String} ddGroup - drag drop group.
58177 * @cfg {String} dragGroup - drag group (?? not sure if needed.)
58181 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
58183 minColumnWidth : 25,
58186 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
58187 * <b>on initial render.</b> It is more efficient to explicitly size the columns
58188 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
58190 autoSizeColumns : false,
58193 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
58195 autoSizeHeaders : true,
58198 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
58200 monitorWindowResize : true,
58203 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
58204 * rows measured to get a columns size. Default is 0 (all rows).
58206 maxRowsToMeasure : 0,
58209 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
58211 trackMouseOver : true,
58214 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
58217 * @cfg {Boolean} enableDrop True to enable drop of elements. Default is false. (double check if this is needed?)
58221 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
58223 enableDragDrop : false,
58226 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
58228 enableColumnMove : true,
58231 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
58233 enableColumnHide : true,
58236 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
58238 enableRowHeightSync : false,
58241 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
58246 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
58248 autoHeight : false,
58251 * @cfg {String} autoExpandColumn The id (or dataIndex) of a column in this grid that should expand to fill unused space. This id can not be 0. Default is false.
58253 autoExpandColumn : false,
58256 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
58259 autoExpandMin : 50,
58262 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
58264 autoExpandMax : 1000,
58267 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
58272 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
58276 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
58280 * @cfg {boolean} sortColMenu Sort the column order menu when it shows (usefull for long lists..) default false
58282 sortColMenu : false,
58288 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
58289 * of a fixed width. Default is false.
58292 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
58297 * @cfg {String} ddText Configures the text is the drag proxy (defaults to "%0 selected row(s)").
58298 * %0 is replaced with the number of selected rows.
58300 ddText : "{0} selected row{1}",
58304 * Called once after all setup has been completed and the grid is ready to be rendered.
58305 * @return {Roo.grid.Grid} this
58307 render : function()
58309 var c = this.container;
58310 // try to detect autoHeight/width mode
58311 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
58312 this.autoHeight = true;
58314 var view = this.getView();
58317 c.on("click", this.onClick, this);
58318 c.on("dblclick", this.onDblClick, this);
58319 c.on("contextmenu", this.onContextMenu, this);
58320 c.on("keydown", this.onKeyDown, this);
58322 c.on("touchstart", this.onTouchStart, this);
58325 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
58327 this.getSelectionModel().init(this);
58332 this.loadMask = new Roo.LoadMask(this.container,
58333 Roo.apply({store:this.dataSource}, this.loadMask));
58337 if (this.toolbar && this.toolbar.xtype) {
58338 this.toolbar.container = this.getView().getHeaderPanel(true);
58339 this.toolbar = new Roo.Toolbar(this.toolbar);
58341 if (this.footer && this.footer.xtype) {
58342 this.footer.dataSource = this.getDataSource();
58343 this.footer.container = this.getView().getFooterPanel(true);
58344 this.footer = Roo.factory(this.footer, Roo);
58346 if (this.dropTarget && this.dropTarget.xtype) {
58347 delete this.dropTarget.xtype;
58348 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
58352 this.rendered = true;
58353 this.fireEvent('render', this);
58358 * Reconfigures the grid to use a different Store and Column Model.
58359 * The View will be bound to the new objects and refreshed.
58360 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
58361 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
58363 reconfigure : function(dataSource, colModel){
58365 this.loadMask.destroy();
58366 this.loadMask = new Roo.LoadMask(this.container,
58367 Roo.apply({store:dataSource}, this.loadMask));
58369 this.view.bind(dataSource, colModel);
58370 this.dataSource = dataSource;
58371 this.colModel = colModel;
58372 this.view.refresh(true);
58376 * Add's a column, default at the end..
58378 * @param {int} position to add (default end)
58379 * @param {Array} of objects of column configuration see {@link Roo.grid.ColumnModel}
58381 addColumns : function(pos, ar)
58384 for (var i =0;i< ar.length;i++) {
58386 cfg.id = typeof(cfg.id) == 'undefined' ? Roo.id() : cfg.id; // don't normally use this..
58387 this.cm.lookup[cfg.id] = cfg;
58391 if (typeof(pos) == 'undefined' || pos >= this.cm.config.length) {
58392 pos = this.cm.config.length; //this.cm.config.push(cfg);
58394 pos = Math.max(0,pos);
58397 this.cm.config.splice.apply(this.cm.config, ar);
58401 this.view.generateRules(this.cm);
58402 this.view.refresh(true);
58410 onKeyDown : function(e){
58411 this.fireEvent("keydown", e);
58415 * Destroy this grid.
58416 * @param {Boolean} removeEl True to remove the element
58418 destroy : function(removeEl, keepListeners){
58420 this.loadMask.destroy();
58422 var c = this.container;
58423 c.removeAllListeners();
58424 this.view.destroy();
58425 this.colModel.purgeListeners();
58426 if(!keepListeners){
58427 this.purgeListeners();
58430 if(removeEl === true){
58436 processEvent : function(name, e){
58437 // does this fire select???
58438 //Roo.log('grid:processEvent ' + name);
58440 if (name != 'touchstart' ) {
58441 this.fireEvent(name, e);
58444 var t = e.getTarget();
58446 var header = v.findHeaderIndex(t);
58447 if(header !== false){
58448 var ename = name == 'touchstart' ? 'click' : name;
58450 this.fireEvent("header" + ename, this, header, e);
58452 var row = v.findRowIndex(t);
58453 var cell = v.findCellIndex(t);
58454 if (name == 'touchstart') {
58455 // first touch is always a click.
58456 // hopefull this happens after selection is updated.?
58459 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
58460 var cs = this.selModel.getSelectedCell();
58461 if (row == cs[0] && cell == cs[1]){
58465 if (typeof(this.selModel.getSelections) != 'undefined') {
58466 var cs = this.selModel.getSelections();
58467 var ds = this.dataSource;
58468 if (cs.length == 1 && ds.getAt(row) == cs[0]){
58479 this.fireEvent("row" + name, this, row, e);
58480 if(cell !== false){
58481 this.fireEvent("cell" + name, this, row, cell, e);
58488 onClick : function(e){
58489 this.processEvent("click", e);
58492 onTouchStart : function(e){
58493 this.processEvent("touchstart", e);
58497 onContextMenu : function(e, t){
58498 this.processEvent("contextmenu", e);
58502 onDblClick : function(e){
58503 this.processEvent("dblclick", e);
58507 walkCells : function(row, col, step, fn, scope){
58508 var cm = this.colModel, clen = cm.getColumnCount();
58509 var ds = this.dataSource, rlen = ds.getCount(), first = true;
58521 if(fn.call(scope || this, row, col, cm) === true){
58539 if(fn.call(scope || this, row, col, cm) === true){
58551 getSelections : function(){
58552 return this.selModel.getSelections();
58556 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
58557 * but if manual update is required this method will initiate it.
58559 autoSize : function(){
58561 this.view.layout();
58562 if(this.view.adjustForScroll){
58563 this.view.adjustForScroll();
58569 * Returns the grid's underlying element.
58570 * @return {Element} The element
58572 getGridEl : function(){
58573 return this.container;
58576 // private for compatibility, overridden by editor grid
58577 stopEditing : function(){},
58580 * Returns the grid's SelectionModel.
58581 * @return {SelectionModel}
58583 getSelectionModel : function(){
58584 if(!this.selModel){
58585 this.selModel = new Roo.grid.RowSelectionModel();
58587 return this.selModel;
58591 * Returns the grid's DataSource.
58592 * @return {DataSource}
58594 getDataSource : function(){
58595 return this.dataSource;
58599 * Returns the grid's ColumnModel.
58600 * @return {ColumnModel}
58602 getColumnModel : function(){
58603 return this.colModel;
58607 * Returns the grid's GridView object.
58608 * @return {GridView}
58610 getView : function(){
58612 this.view = new Roo.grid.GridView(this.viewConfig);
58613 this.relayEvents(this.view, [
58614 "beforerowremoved", "beforerowsinserted",
58615 "beforerefresh", "rowremoved",
58616 "rowsinserted", "rowupdated" ,"refresh"
58622 * Called to get grid's drag proxy text, by default returns this.ddText.
58623 * Override this to put something different in the dragged text.
58626 getDragDropText : function(){
58627 var count = this.selModel.getCount();
58628 return String.format(this.ddText, count, count == 1 ? '' : 's');
58633 * Ext JS Library 1.1.1
58634 * Copyright(c) 2006-2007, Ext JS, LLC.
58636 * Originally Released Under LGPL - original licence link has changed is not relivant.
58639 * <script type="text/javascript">
58642 * @class Roo.grid.AbstractGridView
58643 * @extends Roo.util.Observable
58645 * Abstract base class for grid Views
58648 Roo.grid.AbstractGridView = function(){
58652 "beforerowremoved" : true,
58653 "beforerowsinserted" : true,
58654 "beforerefresh" : true,
58655 "rowremoved" : true,
58656 "rowsinserted" : true,
58657 "rowupdated" : true,
58660 Roo.grid.AbstractGridView.superclass.constructor.call(this);
58663 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
58664 rowClass : "x-grid-row",
58665 cellClass : "x-grid-cell",
58666 tdClass : "x-grid-td",
58667 hdClass : "x-grid-hd",
58668 splitClass : "x-grid-hd-split",
58670 init: function(grid){
58672 var cid = this.grid.getGridEl().id;
58673 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
58674 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
58675 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
58676 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
58679 getColumnRenderers : function(){
58680 var renderers = [];
58681 var cm = this.grid.colModel;
58682 var colCount = cm.getColumnCount();
58683 for(var i = 0; i < colCount; i++){
58684 renderers[i] = cm.getRenderer(i);
58689 getColumnIds : function(){
58691 var cm = this.grid.colModel;
58692 var colCount = cm.getColumnCount();
58693 for(var i = 0; i < colCount; i++){
58694 ids[i] = cm.getColumnId(i);
58699 getDataIndexes : function(){
58700 if(!this.indexMap){
58701 this.indexMap = this.buildIndexMap();
58703 return this.indexMap.colToData;
58706 getColumnIndexByDataIndex : function(dataIndex){
58707 if(!this.indexMap){
58708 this.indexMap = this.buildIndexMap();
58710 return this.indexMap.dataToCol[dataIndex];
58714 * Set a css style for a column dynamically.
58715 * @param {Number} colIndex The index of the column
58716 * @param {String} name The css property name
58717 * @param {String} value The css value
58719 setCSSStyle : function(colIndex, name, value){
58720 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
58721 Roo.util.CSS.updateRule(selector, name, value);
58724 generateRules : function(cm){
58725 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
58726 Roo.util.CSS.removeStyleSheet(rulesId);
58727 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
58728 var cid = cm.getColumnId(i);
58729 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
58730 this.tdSelector, cid, " {\n}\n",
58731 this.hdSelector, cid, " {\n}\n",
58732 this.splitSelector, cid, " {\n}\n");
58734 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
58738 * Ext JS Library 1.1.1
58739 * Copyright(c) 2006-2007, Ext JS, LLC.
58741 * Originally Released Under LGPL - original licence link has changed is not relivant.
58744 * <script type="text/javascript">
58748 // This is a support class used internally by the Grid components
58749 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
58751 this.view = grid.getView();
58752 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
58753 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
58755 this.setHandleElId(Roo.id(hd));
58756 this.setOuterHandleElId(Roo.id(hd2));
58758 this.scroll = false;
58760 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
58762 getDragData : function(e){
58763 var t = Roo.lib.Event.getTarget(e);
58764 var h = this.view.findHeaderCell(t);
58766 return {ddel: h.firstChild, header:h};
58771 onInitDrag : function(e){
58772 this.view.headersDisabled = true;
58773 var clone = this.dragData.ddel.cloneNode(true);
58774 clone.id = Roo.id();
58775 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
58776 this.proxy.update(clone);
58780 afterValidDrop : function(){
58782 setTimeout(function(){
58783 v.headersDisabled = false;
58787 afterInvalidDrop : function(){
58789 setTimeout(function(){
58790 v.headersDisabled = false;
58796 * Ext JS Library 1.1.1
58797 * Copyright(c) 2006-2007, Ext JS, LLC.
58799 * Originally Released Under LGPL - original licence link has changed is not relivant.
58802 * <script type="text/javascript">
58805 // This is a support class used internally by the Grid components
58806 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
58808 this.view = grid.getView();
58809 // split the proxies so they don't interfere with mouse events
58810 this.proxyTop = Roo.DomHelper.append(document.body, {
58811 cls:"col-move-top", html:" "
58813 this.proxyBottom = Roo.DomHelper.append(document.body, {
58814 cls:"col-move-bottom", html:" "
58816 this.proxyTop.hide = this.proxyBottom.hide = function(){
58817 this.setLeftTop(-100,-100);
58818 this.setStyle("visibility", "hidden");
58820 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
58821 // temporarily disabled
58822 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
58823 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
58825 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
58826 proxyOffsets : [-4, -9],
58827 fly: Roo.Element.fly,
58829 getTargetFromEvent : function(e){
58830 var t = Roo.lib.Event.getTarget(e);
58831 var cindex = this.view.findCellIndex(t);
58832 if(cindex !== false){
58833 return this.view.getHeaderCell(cindex);
58838 nextVisible : function(h){
58839 var v = this.view, cm = this.grid.colModel;
58842 if(!cm.isHidden(v.getCellIndex(h))){
58850 prevVisible : function(h){
58851 var v = this.view, cm = this.grid.colModel;
58854 if(!cm.isHidden(v.getCellIndex(h))){
58862 positionIndicator : function(h, n, e){
58863 var x = Roo.lib.Event.getPageX(e);
58864 var r = Roo.lib.Dom.getRegion(n.firstChild);
58865 var px, pt, py = r.top + this.proxyOffsets[1];
58866 if((r.right - x) <= (r.right-r.left)/2){
58867 px = r.right+this.view.borderWidth;
58873 var oldIndex = this.view.getCellIndex(h);
58874 var newIndex = this.view.getCellIndex(n);
58876 if(this.grid.colModel.isFixed(newIndex)){
58880 var locked = this.grid.colModel.isLocked(newIndex);
58885 if(oldIndex < newIndex){
58888 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
58891 px += this.proxyOffsets[0];
58892 this.proxyTop.setLeftTop(px, py);
58893 this.proxyTop.show();
58894 if(!this.bottomOffset){
58895 this.bottomOffset = this.view.mainHd.getHeight();
58897 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
58898 this.proxyBottom.show();
58902 onNodeEnter : function(n, dd, e, data){
58903 if(data.header != n){
58904 this.positionIndicator(data.header, n, e);
58908 onNodeOver : function(n, dd, e, data){
58909 var result = false;
58910 if(data.header != n){
58911 result = this.positionIndicator(data.header, n, e);
58914 this.proxyTop.hide();
58915 this.proxyBottom.hide();
58917 return result ? this.dropAllowed : this.dropNotAllowed;
58920 onNodeOut : function(n, dd, e, data){
58921 this.proxyTop.hide();
58922 this.proxyBottom.hide();
58925 onNodeDrop : function(n, dd, e, data){
58926 var h = data.header;
58928 var cm = this.grid.colModel;
58929 var x = Roo.lib.Event.getPageX(e);
58930 var r = Roo.lib.Dom.getRegion(n.firstChild);
58931 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
58932 var oldIndex = this.view.getCellIndex(h);
58933 var newIndex = this.view.getCellIndex(n);
58934 var locked = cm.isLocked(newIndex);
58938 if(oldIndex < newIndex){
58941 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
58944 cm.setLocked(oldIndex, locked, true);
58945 cm.moveColumn(oldIndex, newIndex);
58946 this.grid.fireEvent("columnmove", oldIndex, newIndex);
58954 * Ext JS Library 1.1.1
58955 * Copyright(c) 2006-2007, Ext JS, LLC.
58957 * Originally Released Under LGPL - original licence link has changed is not relivant.
58960 * <script type="text/javascript">
58964 * @class Roo.grid.GridView
58965 * @extends Roo.util.Observable
58968 * @param {Object} config
58970 Roo.grid.GridView = function(config){
58971 Roo.grid.GridView.superclass.constructor.call(this);
58974 Roo.apply(this, config);
58977 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
58979 unselectable : 'unselectable="on"',
58980 unselectableCls : 'x-unselectable',
58983 rowClass : "x-grid-row",
58985 cellClass : "x-grid-col",
58987 tdClass : "x-grid-td",
58989 hdClass : "x-grid-hd",
58991 splitClass : "x-grid-split",
58993 sortClasses : ["sort-asc", "sort-desc"],
58995 enableMoveAnim : false,
58999 dh : Roo.DomHelper,
59001 fly : Roo.Element.fly,
59003 css : Roo.util.CSS,
59009 scrollIncrement : 22,
59011 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
59013 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
59015 bind : function(ds, cm){
59017 this.ds.un("load", this.onLoad, this);
59018 this.ds.un("datachanged", this.onDataChange, this);
59019 this.ds.un("add", this.onAdd, this);
59020 this.ds.un("remove", this.onRemove, this);
59021 this.ds.un("update", this.onUpdate, this);
59022 this.ds.un("clear", this.onClear, this);
59025 ds.on("load", this.onLoad, this);
59026 ds.on("datachanged", this.onDataChange, this);
59027 ds.on("add", this.onAdd, this);
59028 ds.on("remove", this.onRemove, this);
59029 ds.on("update", this.onUpdate, this);
59030 ds.on("clear", this.onClear, this);
59035 this.cm.un("widthchange", this.onColWidthChange, this);
59036 this.cm.un("headerchange", this.onHeaderChange, this);
59037 this.cm.un("hiddenchange", this.onHiddenChange, this);
59038 this.cm.un("columnmoved", this.onColumnMove, this);
59039 this.cm.un("columnlockchange", this.onColumnLock, this);
59042 this.generateRules(cm);
59043 cm.on("widthchange", this.onColWidthChange, this);
59044 cm.on("headerchange", this.onHeaderChange, this);
59045 cm.on("hiddenchange", this.onHiddenChange, this);
59046 cm.on("columnmoved", this.onColumnMove, this);
59047 cm.on("columnlockchange", this.onColumnLock, this);
59052 init: function(grid){
59053 Roo.grid.GridView.superclass.init.call(this, grid);
59055 this.bind(grid.dataSource, grid.colModel);
59057 grid.on("headerclick", this.handleHeaderClick, this);
59059 if(grid.trackMouseOver){
59060 grid.on("mouseover", this.onRowOver, this);
59061 grid.on("mouseout", this.onRowOut, this);
59063 grid.cancelTextSelection = function(){};
59064 this.gridId = grid.id;
59066 var tpls = this.templates || {};
59069 tpls.master = new Roo.Template(
59070 '<div class="x-grid" hidefocus="true">',
59071 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
59072 '<div class="x-grid-topbar"></div>',
59073 '<div class="x-grid-scroller"><div></div></div>',
59074 '<div class="x-grid-locked">',
59075 '<div class="x-grid-header">{lockedHeader}</div>',
59076 '<div class="x-grid-body">{lockedBody}</div>',
59078 '<div class="x-grid-viewport">',
59079 '<div class="x-grid-header">{header}</div>',
59080 '<div class="x-grid-body">{body}</div>',
59082 '<div class="x-grid-bottombar"></div>',
59084 '<div class="x-grid-resize-proxy"> </div>',
59087 tpls.master.disableformats = true;
59091 tpls.header = new Roo.Template(
59092 '<table border="0" cellspacing="0" cellpadding="0">',
59093 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
59096 tpls.header.disableformats = true;
59098 tpls.header.compile();
59101 tpls.hcell = new Roo.Template(
59102 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
59103 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
59106 tpls.hcell.disableFormats = true;
59108 tpls.hcell.compile();
59111 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
59112 this.unselectableCls + '" ' + this.unselectable +'> </div>');
59113 tpls.hsplit.disableFormats = true;
59115 tpls.hsplit.compile();
59118 tpls.body = new Roo.Template(
59119 '<table border="0" cellspacing="0" cellpadding="0">',
59120 "<tbody>{rows}</tbody>",
59123 tpls.body.disableFormats = true;
59125 tpls.body.compile();
59128 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
59129 tpls.row.disableFormats = true;
59131 tpls.row.compile();
59134 tpls.cell = new Roo.Template(
59135 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
59136 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
59137 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
59140 tpls.cell.disableFormats = true;
59142 tpls.cell.compile();
59144 this.templates = tpls;
59147 // remap these for backwards compat
59148 onColWidthChange : function(){
59149 this.updateColumns.apply(this, arguments);
59151 onHeaderChange : function(){
59152 this.updateHeaders.apply(this, arguments);
59154 onHiddenChange : function(){
59155 this.handleHiddenChange.apply(this, arguments);
59157 onColumnMove : function(){
59158 this.handleColumnMove.apply(this, arguments);
59160 onColumnLock : function(){
59161 this.handleLockChange.apply(this, arguments);
59164 onDataChange : function(){
59166 this.updateHeaderSortState();
59169 onClear : function(){
59173 onUpdate : function(ds, record){
59174 this.refreshRow(record);
59177 refreshRow : function(record){
59178 var ds = this.ds, index;
59179 if(typeof record == 'number'){
59181 record = ds.getAt(index);
59183 index = ds.indexOf(record);
59185 this.insertRows(ds, index, index, true);
59186 this.onRemove(ds, record, index+1, true);
59187 this.syncRowHeights(index, index);
59189 this.fireEvent("rowupdated", this, index, record);
59192 onAdd : function(ds, records, index){
59193 this.insertRows(ds, index, index + (records.length-1));
59196 onRemove : function(ds, record, index, isUpdate){
59197 if(isUpdate !== true){
59198 this.fireEvent("beforerowremoved", this, index, record);
59200 var bt = this.getBodyTable(), lt = this.getLockedTable();
59201 if(bt.rows[index]){
59202 bt.firstChild.removeChild(bt.rows[index]);
59204 if(lt.rows[index]){
59205 lt.firstChild.removeChild(lt.rows[index]);
59207 if(isUpdate !== true){
59208 this.stripeRows(index);
59209 this.syncRowHeights(index, index);
59211 this.fireEvent("rowremoved", this, index, record);
59215 onLoad : function(){
59216 this.scrollToTop();
59220 * Scrolls the grid to the top
59222 scrollToTop : function(){
59224 this.scroller.dom.scrollTop = 0;
59230 * Gets a panel in the header of the grid that can be used for toolbars etc.
59231 * After modifying the contents of this panel a call to grid.autoSize() may be
59232 * required to register any changes in size.
59233 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
59234 * @return Roo.Element
59236 getHeaderPanel : function(doShow){
59238 this.headerPanel.show();
59240 return this.headerPanel;
59244 * Gets a panel in the footer of the grid that can be used for toolbars etc.
59245 * After modifying the contents of this panel a call to grid.autoSize() may be
59246 * required to register any changes in size.
59247 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
59248 * @return Roo.Element
59250 getFooterPanel : function(doShow){
59252 this.footerPanel.show();
59254 return this.footerPanel;
59257 initElements : function(){
59258 var E = Roo.Element;
59259 var el = this.grid.getGridEl().dom.firstChild;
59260 var cs = el.childNodes;
59262 this.el = new E(el);
59264 this.focusEl = new E(el.firstChild);
59265 this.focusEl.swallowEvent("click", true);
59267 this.headerPanel = new E(cs[1]);
59268 this.headerPanel.enableDisplayMode("block");
59270 this.scroller = new E(cs[2]);
59271 this.scrollSizer = new E(this.scroller.dom.firstChild);
59273 this.lockedWrap = new E(cs[3]);
59274 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
59275 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
59277 this.mainWrap = new E(cs[4]);
59278 this.mainHd = new E(this.mainWrap.dom.firstChild);
59279 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
59281 this.footerPanel = new E(cs[5]);
59282 this.footerPanel.enableDisplayMode("block");
59284 this.resizeProxy = new E(cs[6]);
59286 this.headerSelector = String.format(
59287 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
59288 this.lockedHd.id, this.mainHd.id
59291 this.splitterSelector = String.format(
59292 '#{0} div.x-grid-split, #{1} div.x-grid-split',
59293 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
59296 idToCssName : function(s)
59298 return s.replace(/[^a-z0-9]+/ig, '-');
59301 getHeaderCell : function(index){
59302 return Roo.DomQuery.select(this.headerSelector)[index];
59305 getHeaderCellMeasure : function(index){
59306 return this.getHeaderCell(index).firstChild;
59309 getHeaderCellText : function(index){
59310 return this.getHeaderCell(index).firstChild.firstChild;
59313 getLockedTable : function(){
59314 return this.lockedBody.dom.firstChild;
59317 getBodyTable : function(){
59318 return this.mainBody.dom.firstChild;
59321 getLockedRow : function(index){
59322 return this.getLockedTable().rows[index];
59325 getRow : function(index){
59326 return this.getBodyTable().rows[index];
59329 getRowComposite : function(index){
59331 this.rowEl = new Roo.CompositeElementLite();
59333 var els = [], lrow, mrow;
59334 if(lrow = this.getLockedRow(index)){
59337 if(mrow = this.getRow(index)){
59340 this.rowEl.elements = els;
59344 * Gets the 'td' of the cell
59346 * @param {Integer} rowIndex row to select
59347 * @param {Integer} colIndex column to select
59351 getCell : function(rowIndex, colIndex){
59352 var locked = this.cm.getLockedCount();
59354 if(colIndex < locked){
59355 source = this.lockedBody.dom.firstChild;
59357 source = this.mainBody.dom.firstChild;
59358 colIndex -= locked;
59360 return source.rows[rowIndex].childNodes[colIndex];
59363 getCellText : function(rowIndex, colIndex){
59364 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
59367 getCellBox : function(cell){
59368 var b = this.fly(cell).getBox();
59369 if(Roo.isOpera){ // opera fails to report the Y
59370 b.y = cell.offsetTop + this.mainBody.getY();
59375 getCellIndex : function(cell){
59376 var id = String(cell.className).match(this.cellRE);
59378 return parseInt(id[1], 10);
59383 findHeaderIndex : function(n){
59384 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
59385 return r ? this.getCellIndex(r) : false;
59388 findHeaderCell : function(n){
59389 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
59390 return r ? r : false;
59393 findRowIndex : function(n){
59397 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
59398 return r ? r.rowIndex : false;
59401 findCellIndex : function(node){
59402 var stop = this.el.dom;
59403 while(node && node != stop){
59404 if(this.findRE.test(node.className)){
59405 return this.getCellIndex(node);
59407 node = node.parentNode;
59412 getColumnId : function(index){
59413 return this.cm.getColumnId(index);
59416 getSplitters : function()
59418 if(this.splitterSelector){
59419 return Roo.DomQuery.select(this.splitterSelector);
59425 getSplitter : function(index){
59426 return this.getSplitters()[index];
59429 onRowOver : function(e, t){
59431 if((row = this.findRowIndex(t)) !== false){
59432 this.getRowComposite(row).addClass("x-grid-row-over");
59436 onRowOut : function(e, t){
59438 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
59439 this.getRowComposite(row).removeClass("x-grid-row-over");
59443 renderHeaders : function(){
59445 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
59446 var cb = [], lb = [], sb = [], lsb = [], p = {};
59447 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
59448 p.cellId = "x-grid-hd-0-" + i;
59449 p.splitId = "x-grid-csplit-0-" + i;
59450 p.id = cm.getColumnId(i);
59451 p.value = cm.getColumnHeader(i) || "";
59452 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
59453 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
59454 if(!cm.isLocked(i)){
59455 cb[cb.length] = ct.apply(p);
59456 sb[sb.length] = st.apply(p);
59458 lb[lb.length] = ct.apply(p);
59459 lsb[lsb.length] = st.apply(p);
59462 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
59463 ht.apply({cells: cb.join(""), splits:sb.join("")})];
59466 updateHeaders : function(){
59467 var html = this.renderHeaders();
59468 this.lockedHd.update(html[0]);
59469 this.mainHd.update(html[1]);
59473 * Focuses the specified row.
59474 * @param {Number} row The row index
59476 focusRow : function(row)
59478 //Roo.log('GridView.focusRow');
59479 var x = this.scroller.dom.scrollLeft;
59480 this.focusCell(row, 0, false);
59481 this.scroller.dom.scrollLeft = x;
59485 * Focuses the specified cell.
59486 * @param {Number} row The row index
59487 * @param {Number} col The column index
59488 * @param {Boolean} hscroll false to disable horizontal scrolling
59490 focusCell : function(row, col, hscroll)
59492 //Roo.log('GridView.focusCell');
59493 var el = this.ensureVisible(row, col, hscroll);
59494 this.focusEl.alignTo(el, "tl-tl");
59496 this.focusEl.focus();
59498 this.focusEl.focus.defer(1, this.focusEl);
59503 * Scrolls the specified cell into view
59504 * @param {Number} row The row index
59505 * @param {Number} col The column index
59506 * @param {Boolean} hscroll false to disable horizontal scrolling
59508 ensureVisible : function(row, col, hscroll)
59510 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
59511 //return null; //disable for testing.
59512 if(typeof row != "number"){
59513 row = row.rowIndex;
59515 if(row < 0 && row >= this.ds.getCount()){
59518 col = (col !== undefined ? col : 0);
59519 var cm = this.grid.colModel;
59520 while(cm.isHidden(col)){
59524 var el = this.getCell(row, col);
59528 var c = this.scroller.dom;
59530 var ctop = parseInt(el.offsetTop, 10);
59531 var cleft = parseInt(el.offsetLeft, 10);
59532 var cbot = ctop + el.offsetHeight;
59533 var cright = cleft + el.offsetWidth;
59535 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
59536 var stop = parseInt(c.scrollTop, 10);
59537 var sleft = parseInt(c.scrollLeft, 10);
59538 var sbot = stop + ch;
59539 var sright = sleft + c.clientWidth;
59541 Roo.log('GridView.ensureVisible:' +
59543 ' c.clientHeight:' + c.clientHeight +
59544 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
59552 c.scrollTop = ctop;
59553 //Roo.log("set scrolltop to ctop DISABLE?");
59554 }else if(cbot > sbot){
59555 //Roo.log("set scrolltop to cbot-ch");
59556 c.scrollTop = cbot-ch;
59559 if(hscroll !== false){
59561 c.scrollLeft = cleft;
59562 }else if(cright > sright){
59563 c.scrollLeft = cright-c.clientWidth;
59570 updateColumns : function(){
59571 this.grid.stopEditing();
59572 var cm = this.grid.colModel, colIds = this.getColumnIds();
59573 //var totalWidth = cm.getTotalWidth();
59575 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
59576 //if(cm.isHidden(i)) continue;
59577 var w = cm.getColumnWidth(i);
59578 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
59579 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
59581 this.updateSplitters();
59584 generateRules : function(cm){
59585 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
59586 Roo.util.CSS.removeStyleSheet(rulesId);
59587 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
59588 var cid = cm.getColumnId(i);
59590 if(cm.config[i].align){
59591 align = 'text-align:'+cm.config[i].align+';';
59594 if(cm.isHidden(i)){
59595 hidden = 'display:none;';
59597 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
59599 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
59600 this.hdSelector, cid, " {\n", align, width, "}\n",
59601 this.tdSelector, cid, " {\n",hidden,"\n}\n",
59602 this.splitSelector, cid, " {\n", hidden , "\n}\n");
59604 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
59607 updateSplitters : function(){
59608 var cm = this.cm, s = this.getSplitters();
59609 if(s){ // splitters not created yet
59610 var pos = 0, locked = true;
59611 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
59612 if(cm.isHidden(i)) {
59615 var w = cm.getColumnWidth(i); // make sure it's a number
59616 if(!cm.isLocked(i) && locked){
59621 s[i].style.left = (pos-this.splitOffset) + "px";
59626 handleHiddenChange : function(colModel, colIndex, hidden){
59628 this.hideColumn(colIndex);
59630 this.unhideColumn(colIndex);
59634 hideColumn : function(colIndex){
59635 var cid = this.getColumnId(colIndex);
59636 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
59637 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
59639 this.updateHeaders();
59641 this.updateSplitters();
59645 unhideColumn : function(colIndex){
59646 var cid = this.getColumnId(colIndex);
59647 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
59648 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
59651 this.updateHeaders();
59653 this.updateSplitters();
59657 insertRows : function(dm, firstRow, lastRow, isUpdate){
59658 if(firstRow == 0 && lastRow == dm.getCount()-1){
59662 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
59664 var s = this.getScrollState();
59665 var markup = this.renderRows(firstRow, lastRow);
59666 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
59667 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
59668 this.restoreScroll(s);
59670 this.fireEvent("rowsinserted", this, firstRow, lastRow);
59671 this.syncRowHeights(firstRow, lastRow);
59672 this.stripeRows(firstRow);
59678 bufferRows : function(markup, target, index){
59679 var before = null, trows = target.rows, tbody = target.tBodies[0];
59680 if(index < trows.length){
59681 before = trows[index];
59683 var b = document.createElement("div");
59684 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
59685 var rows = b.firstChild.rows;
59686 for(var i = 0, len = rows.length; i < len; i++){
59688 tbody.insertBefore(rows[0], before);
59690 tbody.appendChild(rows[0]);
59697 deleteRows : function(dm, firstRow, lastRow){
59698 if(dm.getRowCount()<1){
59699 this.fireEvent("beforerefresh", this);
59700 this.mainBody.update("");
59701 this.lockedBody.update("");
59702 this.fireEvent("refresh", this);
59704 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
59705 var bt = this.getBodyTable();
59706 var tbody = bt.firstChild;
59707 var rows = bt.rows;
59708 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
59709 tbody.removeChild(rows[firstRow]);
59711 this.stripeRows(firstRow);
59712 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
59716 updateRows : function(dataSource, firstRow, lastRow){
59717 var s = this.getScrollState();
59719 this.restoreScroll(s);
59722 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
59726 this.updateHeaderSortState();
59729 getScrollState : function(){
59731 var sb = this.scroller.dom;
59732 return {left: sb.scrollLeft, top: sb.scrollTop};
59735 stripeRows : function(startRow){
59736 if(!this.grid.stripeRows || this.ds.getCount() < 1){
59739 startRow = startRow || 0;
59740 var rows = this.getBodyTable().rows;
59741 var lrows = this.getLockedTable().rows;
59742 var cls = ' x-grid-row-alt ';
59743 for(var i = startRow, len = rows.length; i < len; i++){
59744 var row = rows[i], lrow = lrows[i];
59745 var isAlt = ((i+1) % 2 == 0);
59746 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
59747 if(isAlt == hasAlt){
59751 row.className += " x-grid-row-alt";
59753 row.className = row.className.replace("x-grid-row-alt", "");
59756 lrow.className = row.className;
59761 restoreScroll : function(state){
59762 //Roo.log('GridView.restoreScroll');
59763 var sb = this.scroller.dom;
59764 sb.scrollLeft = state.left;
59765 sb.scrollTop = state.top;
59769 syncScroll : function(){
59770 //Roo.log('GridView.syncScroll');
59771 var sb = this.scroller.dom;
59772 var sh = this.mainHd.dom;
59773 var bs = this.mainBody.dom;
59774 var lv = this.lockedBody.dom;
59775 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
59776 lv.scrollTop = bs.scrollTop = sb.scrollTop;
59779 handleScroll : function(e){
59781 var sb = this.scroller.dom;
59782 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
59786 handleWheel : function(e){
59787 var d = e.getWheelDelta();
59788 this.scroller.dom.scrollTop -= d*22;
59789 // set this here to prevent jumpy scrolling on large tables
59790 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
59794 renderRows : function(startRow, endRow){
59795 // pull in all the crap needed to render rows
59796 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
59797 var colCount = cm.getColumnCount();
59799 if(ds.getCount() < 1){
59803 // build a map for all the columns
59805 for(var i = 0; i < colCount; i++){
59806 var name = cm.getDataIndex(i);
59808 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
59809 renderer : cm.getRenderer(i),
59810 id : cm.getColumnId(i),
59811 locked : cm.isLocked(i),
59812 has_editor : cm.isCellEditable(i)
59816 startRow = startRow || 0;
59817 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
59819 // records to render
59820 var rs = ds.getRange(startRow, endRow);
59822 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
59825 // As much as I hate to duplicate code, this was branched because FireFox really hates
59826 // [].join("") on strings. The performance difference was substantial enough to
59827 // branch this function
59828 doRender : Roo.isGecko ?
59829 function(cs, rs, ds, startRow, colCount, stripe){
59830 var ts = this.templates, ct = ts.cell, rt = ts.row;
59832 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
59834 var hasListener = this.grid.hasListener('rowclass');
59836 for(var j = 0, len = rs.length; j < len; j++){
59837 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
59838 for(var i = 0; i < colCount; i++){
59840 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
59842 p.css = p.attr = "";
59843 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
59844 if(p.value == undefined || p.value === "") {
59845 p.value = " ";
59848 p.css += ' x-grid-editable-cell';
59850 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
59851 p.css += ' x-grid-dirty-cell';
59853 var markup = ct.apply(p);
59861 if(stripe && ((rowIndex+1) % 2 == 0)){
59862 alt.push("x-grid-row-alt")
59865 alt.push( " x-grid-dirty-row");
59868 if(this.getRowClass){
59869 alt.push(this.getRowClass(r, rowIndex));
59875 rowIndex : rowIndex,
59878 this.grid.fireEvent('rowclass', this, rowcfg);
59879 alt.push(rowcfg.rowClass);
59881 rp.alt = alt.join(" ");
59882 lbuf+= rt.apply(rp);
59884 buf+= rt.apply(rp);
59886 return [lbuf, buf];
59888 function(cs, rs, ds, startRow, colCount, stripe){
59889 var ts = this.templates, ct = ts.cell, rt = ts.row;
59891 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
59892 var hasListener = this.grid.hasListener('rowclass');
59895 for(var j = 0, len = rs.length; j < len; j++){
59896 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
59897 for(var i = 0; i < colCount; i++){
59899 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
59901 p.css = p.attr = "";
59902 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
59903 if(p.value == undefined || p.value === "") {
59904 p.value = " ";
59908 p.css += ' x-grid-editable-cell';
59910 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
59911 p.css += ' x-grid-dirty-cell'
59914 var markup = ct.apply(p);
59916 cb[cb.length] = markup;
59918 lcb[lcb.length] = markup;
59922 if(stripe && ((rowIndex+1) % 2 == 0)){
59923 alt.push( "x-grid-row-alt");
59926 alt.push(" x-grid-dirty-row");
59929 if(this.getRowClass){
59930 alt.push( this.getRowClass(r, rowIndex));
59936 rowIndex : rowIndex,
59939 this.grid.fireEvent('rowclass', this, rowcfg);
59940 alt.push(rowcfg.rowClass);
59943 rp.alt = alt.join(" ");
59944 rp.cells = lcb.join("");
59945 lbuf[lbuf.length] = rt.apply(rp);
59946 rp.cells = cb.join("");
59947 buf[buf.length] = rt.apply(rp);
59949 return [lbuf.join(""), buf.join("")];
59952 renderBody : function(){
59953 var markup = this.renderRows();
59954 var bt = this.templates.body;
59955 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
59959 * Refreshes the grid
59960 * @param {Boolean} headersToo
59962 refresh : function(headersToo){
59963 this.fireEvent("beforerefresh", this);
59964 this.grid.stopEditing();
59965 var result = this.renderBody();
59966 this.lockedBody.update(result[0]);
59967 this.mainBody.update(result[1]);
59968 if(headersToo === true){
59969 this.updateHeaders();
59970 this.updateColumns();
59971 this.updateSplitters();
59972 this.updateHeaderSortState();
59974 this.syncRowHeights();
59976 this.fireEvent("refresh", this);
59979 handleColumnMove : function(cm, oldIndex, newIndex){
59980 this.indexMap = null;
59981 var s = this.getScrollState();
59982 this.refresh(true);
59983 this.restoreScroll(s);
59984 this.afterMove(newIndex);
59987 afterMove : function(colIndex){
59988 if(this.enableMoveAnim && Roo.enableFx){
59989 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
59991 // if multisort - fix sortOrder, and reload..
59992 if (this.grid.dataSource.multiSort) {
59993 // the we can call sort again..
59994 var dm = this.grid.dataSource;
59995 var cm = this.grid.colModel;
59997 for(var i = 0; i < cm.config.length; i++ ) {
59999 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
60000 continue; // dont' bother, it's not in sort list or being set.
60003 so.push(cm.config[i].dataIndex);
60006 dm.load(dm.lastOptions);
60013 updateCell : function(dm, rowIndex, dataIndex){
60014 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
60015 if(typeof colIndex == "undefined"){ // not present in grid
60018 var cm = this.grid.colModel;
60019 var cell = this.getCell(rowIndex, colIndex);
60020 var cellText = this.getCellText(rowIndex, colIndex);
60023 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
60024 id : cm.getColumnId(colIndex),
60025 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
60027 var renderer = cm.getRenderer(colIndex);
60028 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
60029 if(typeof val == "undefined" || val === "") {
60032 cellText.innerHTML = val;
60033 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
60034 this.syncRowHeights(rowIndex, rowIndex);
60037 calcColumnWidth : function(colIndex, maxRowsToMeasure){
60039 if(this.grid.autoSizeHeaders){
60040 var h = this.getHeaderCellMeasure(colIndex);
60041 maxWidth = Math.max(maxWidth, h.scrollWidth);
60044 if(this.cm.isLocked(colIndex)){
60045 tb = this.getLockedTable();
60048 tb = this.getBodyTable();
60049 index = colIndex - this.cm.getLockedCount();
60052 var rows = tb.rows;
60053 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
60054 for(var i = 0; i < stopIndex; i++){
60055 var cell = rows[i].childNodes[index].firstChild;
60056 maxWidth = Math.max(maxWidth, cell.scrollWidth);
60059 return maxWidth + /*margin for error in IE*/ 5;
60062 * Autofit a column to its content.
60063 * @param {Number} colIndex
60064 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
60066 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
60067 if(this.cm.isHidden(colIndex)){
60068 return; // can't calc a hidden column
60071 var cid = this.cm.getColumnId(colIndex);
60072 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
60073 if(this.grid.autoSizeHeaders){
60074 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
60077 var newWidth = this.calcColumnWidth(colIndex);
60078 this.cm.setColumnWidth(colIndex,
60079 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
60080 if(!suppressEvent){
60081 this.grid.fireEvent("columnresize", colIndex, newWidth);
60086 * Autofits all columns to their content and then expands to fit any extra space in the grid
60088 autoSizeColumns : function(){
60089 var cm = this.grid.colModel;
60090 var colCount = cm.getColumnCount();
60091 for(var i = 0; i < colCount; i++){
60092 this.autoSizeColumn(i, true, true);
60094 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
60097 this.updateColumns();
60103 * Autofits all columns to the grid's width proportionate with their current size
60104 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
60106 fitColumns : function(reserveScrollSpace){
60107 var cm = this.grid.colModel;
60108 var colCount = cm.getColumnCount();
60112 for (i = 0; i < colCount; i++){
60113 if(!cm.isHidden(i) && !cm.isFixed(i)){
60114 w = cm.getColumnWidth(i);
60120 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
60121 if(reserveScrollSpace){
60124 var frac = (avail - cm.getTotalWidth())/width;
60125 while (cols.length){
60128 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
60130 this.updateColumns();
60134 onRowSelect : function(rowIndex){
60135 var row = this.getRowComposite(rowIndex);
60136 row.addClass("x-grid-row-selected");
60139 onRowDeselect : function(rowIndex){
60140 var row = this.getRowComposite(rowIndex);
60141 row.removeClass("x-grid-row-selected");
60144 onCellSelect : function(row, col){
60145 var cell = this.getCell(row, col);
60147 Roo.fly(cell).addClass("x-grid-cell-selected");
60151 onCellDeselect : function(row, col){
60152 var cell = this.getCell(row, col);
60154 Roo.fly(cell).removeClass("x-grid-cell-selected");
60158 updateHeaderSortState : function(){
60160 // sort state can be single { field: xxx, direction : yyy}
60161 // or { xxx=>ASC , yyy : DESC ..... }
60164 if (!this.ds.multiSort) {
60165 var state = this.ds.getSortState();
60169 mstate[state.field] = state.direction;
60170 // FIXME... - this is not used here.. but might be elsewhere..
60171 this.sortState = state;
60174 mstate = this.ds.sortToggle;
60176 //remove existing sort classes..
60178 var sc = this.sortClasses;
60179 var hds = this.el.select(this.headerSelector).removeClass(sc);
60181 for(var f in mstate) {
60183 var sortColumn = this.cm.findColumnIndex(f);
60185 if(sortColumn != -1){
60186 var sortDir = mstate[f];
60187 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
60196 handleHeaderClick : function(g, index,e){
60198 Roo.log("header click");
60201 // touch events on header are handled by context
60202 this.handleHdCtx(g,index,e);
60207 if(this.headersDisabled){
60210 var dm = g.dataSource, cm = g.colModel;
60211 if(!cm.isSortable(index)){
60216 if (dm.multiSort) {
60217 // update the sortOrder
60219 for(var i = 0; i < cm.config.length; i++ ) {
60221 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
60222 continue; // dont' bother, it's not in sort list or being set.
60225 so.push(cm.config[i].dataIndex);
60231 dm.sort(cm.getDataIndex(index));
60235 destroy : function(){
60237 this.colMenu.removeAll();
60238 Roo.menu.MenuMgr.unregister(this.colMenu);
60239 this.colMenu.getEl().remove();
60240 delete this.colMenu;
60243 this.hmenu.removeAll();
60244 Roo.menu.MenuMgr.unregister(this.hmenu);
60245 this.hmenu.getEl().remove();
60248 if(this.grid.enableColumnMove){
60249 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
60251 for(var dd in dds){
60252 if(!dds[dd].config.isTarget && dds[dd].dragElId){
60253 var elid = dds[dd].dragElId;
60255 Roo.get(elid).remove();
60256 } else if(dds[dd].config.isTarget){
60257 dds[dd].proxyTop.remove();
60258 dds[dd].proxyBottom.remove();
60261 if(Roo.dd.DDM.locationCache[dd]){
60262 delete Roo.dd.DDM.locationCache[dd];
60265 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
60268 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
60269 this.bind(null, null);
60270 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
60273 handleLockChange : function(){
60274 this.refresh(true);
60277 onDenyColumnLock : function(){
60281 onDenyColumnHide : function(){
60285 handleHdMenuClick : function(item){
60286 var index = this.hdCtxIndex;
60287 var cm = this.cm, ds = this.ds;
60290 ds.sort(cm.getDataIndex(index), "ASC");
60293 ds.sort(cm.getDataIndex(index), "DESC");
60296 var lc = cm.getLockedCount();
60297 if(cm.getColumnCount(true) <= lc+1){
60298 this.onDenyColumnLock();
60302 cm.setLocked(index, true, true);
60303 cm.moveColumn(index, lc);
60304 this.grid.fireEvent("columnmove", index, lc);
60306 cm.setLocked(index, true);
60310 var lc = cm.getLockedCount();
60311 if((lc-1) != index){
60312 cm.setLocked(index, false, true);
60313 cm.moveColumn(index, lc-1);
60314 this.grid.fireEvent("columnmove", index, lc-1);
60316 cm.setLocked(index, false);
60319 case 'wider': // used to expand cols on touch..
60321 var cw = cm.getColumnWidth(index);
60322 cw += (item.id == 'wider' ? 1 : -1) * 50;
60323 cw = Math.max(0, cw);
60324 cw = Math.min(cw,4000);
60325 cm.setColumnWidth(index, cw);
60329 index = cm.getIndexById(item.id.substr(4));
60331 if(item.checked && cm.getColumnCount(true) <= 1){
60332 this.onDenyColumnHide();
60335 cm.setHidden(index, item.checked);
60341 beforeColMenuShow : function(){
60342 var cm = this.cm, colCount = cm.getColumnCount();
60343 this.colMenu.removeAll();
60346 for(var i = 0; i < colCount; i++){
60348 id: "col-"+cm.getColumnId(i),
60349 text: cm.getColumnHeader(i),
60350 checked: !cm.isHidden(i),
60355 if (this.grid.sortColMenu) {
60356 items.sort(function(a,b) {
60357 if (a.text == b.text) {
60360 return a.text.toUpperCase() > b.text.toUpperCase() ? 1 : -1;
60364 for(var i = 0; i < colCount; i++){
60365 this.colMenu.add(new Roo.menu.CheckItem(items[i]));
60369 handleHdCtx : function(g, index, e){
60371 var hd = this.getHeaderCell(index);
60372 this.hdCtxIndex = index;
60373 var ms = this.hmenu.items, cm = this.cm;
60374 ms.get("asc").setDisabled(!cm.isSortable(index));
60375 ms.get("desc").setDisabled(!cm.isSortable(index));
60376 if(this.grid.enableColLock !== false){
60377 ms.get("lock").setDisabled(cm.isLocked(index));
60378 ms.get("unlock").setDisabled(!cm.isLocked(index));
60380 this.hmenu.show(hd, "tl-bl");
60383 handleHdOver : function(e){
60384 var hd = this.findHeaderCell(e.getTarget());
60385 if(hd && !this.headersDisabled){
60386 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
60387 this.fly(hd).addClass("x-grid-hd-over");
60392 handleHdOut : function(e){
60393 var hd = this.findHeaderCell(e.getTarget());
60395 this.fly(hd).removeClass("x-grid-hd-over");
60399 handleSplitDblClick : function(e, t){
60400 var i = this.getCellIndex(t);
60401 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
60402 this.autoSizeColumn(i, true);
60407 render : function(){
60410 var colCount = cm.getColumnCount();
60412 if(this.grid.monitorWindowResize === true){
60413 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
60415 var header = this.renderHeaders();
60416 var body = this.templates.body.apply({rows:""});
60417 var html = this.templates.master.apply({
60420 lockedHeader: header[0],
60424 //this.updateColumns();
60426 this.grid.getGridEl().dom.innerHTML = html;
60428 this.initElements();
60430 // a kludge to fix the random scolling effect in webkit
60431 this.el.on("scroll", function() {
60432 this.el.dom.scrollTop=0; // hopefully not recursive..
60435 this.scroller.on("scroll", this.handleScroll, this);
60436 this.lockedBody.on("mousewheel", this.handleWheel, this);
60437 this.mainBody.on("mousewheel", this.handleWheel, this);
60439 this.mainHd.on("mouseover", this.handleHdOver, this);
60440 this.mainHd.on("mouseout", this.handleHdOut, this);
60441 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
60442 {delegate: "."+this.splitClass});
60444 this.lockedHd.on("mouseover", this.handleHdOver, this);
60445 this.lockedHd.on("mouseout", this.handleHdOut, this);
60446 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
60447 {delegate: "."+this.splitClass});
60449 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
60450 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
60453 this.updateSplitters();
60455 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
60456 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
60457 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
60460 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
60461 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
60463 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
60464 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
60466 if(this.grid.enableColLock !== false){
60467 this.hmenu.add('-',
60468 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
60469 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
60473 this.hmenu.add('-',
60474 {id:"wider", text: this.columnsWiderText},
60475 {id:"narrow", text: this.columnsNarrowText }
60481 if(this.grid.enableColumnHide !== false){
60483 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
60484 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
60485 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
60487 this.hmenu.add('-',
60488 {id:"columns", text: this.columnsText, menu: this.colMenu}
60491 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
60493 this.grid.on("headercontextmenu", this.handleHdCtx, this);
60496 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
60497 this.dd = new Roo.grid.GridDragZone(this.grid, {
60498 ddGroup : this.grid.ddGroup || 'GridDD'
60504 for(var i = 0; i < colCount; i++){
60505 if(cm.isHidden(i)){
60506 this.hideColumn(i);
60508 if(cm.config[i].align){
60509 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
60510 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
60514 this.updateHeaderSortState();
60516 this.beforeInitialResize();
60519 // two part rendering gives faster view to the user
60520 this.renderPhase2.defer(1, this);
60523 renderPhase2 : function(){
60524 // render the rows now
60526 if(this.grid.autoSizeColumns){
60527 this.autoSizeColumns();
60531 beforeInitialResize : function(){
60535 onColumnSplitterMoved : function(i, w){
60536 this.userResized = true;
60537 var cm = this.grid.colModel;
60538 cm.setColumnWidth(i, w, true);
60539 var cid = cm.getColumnId(i);
60540 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
60541 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
60542 this.updateSplitters();
60544 this.grid.fireEvent("columnresize", i, w);
60547 syncRowHeights : function(startIndex, endIndex){
60548 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
60549 startIndex = startIndex || 0;
60550 var mrows = this.getBodyTable().rows;
60551 var lrows = this.getLockedTable().rows;
60552 var len = mrows.length-1;
60553 endIndex = Math.min(endIndex || len, len);
60554 for(var i = startIndex; i <= endIndex; i++){
60555 var m = mrows[i], l = lrows[i];
60556 var h = Math.max(m.offsetHeight, l.offsetHeight);
60557 m.style.height = l.style.height = h + "px";
60562 layout : function(initialRender, is2ndPass)
60565 var auto = g.autoHeight;
60566 var scrollOffset = 16;
60567 var c = g.getGridEl(), cm = this.cm,
60568 expandCol = g.autoExpandColumn,
60570 //c.beginMeasure();
60572 if(!c.dom.offsetWidth){ // display:none?
60574 this.lockedWrap.show();
60575 this.mainWrap.show();
60580 var hasLock = this.cm.isLocked(0);
60582 var tbh = this.headerPanel.getHeight();
60583 var bbh = this.footerPanel.getHeight();
60586 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
60587 var newHeight = ch + c.getBorderWidth("tb");
60589 newHeight = Math.min(g.maxHeight, newHeight);
60591 c.setHeight(newHeight);
60595 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
60598 var s = this.scroller;
60600 var csize = c.getSize(true);
60602 this.el.setSize(csize.width, csize.height);
60604 this.headerPanel.setWidth(csize.width);
60605 this.footerPanel.setWidth(csize.width);
60607 var hdHeight = this.mainHd.getHeight();
60608 var vw = csize.width;
60609 var vh = csize.height - (tbh + bbh);
60613 var bt = this.getBodyTable();
60615 if(cm.getLockedCount() == cm.config.length){
60616 bt = this.getLockedTable();
60619 var ltWidth = hasLock ?
60620 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
60622 var scrollHeight = bt.offsetHeight;
60623 var scrollWidth = ltWidth + bt.offsetWidth;
60624 var vscroll = false, hscroll = false;
60626 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
60628 var lw = this.lockedWrap, mw = this.mainWrap;
60629 var lb = this.lockedBody, mb = this.mainBody;
60631 setTimeout(function(){
60632 var t = s.dom.offsetTop;
60633 var w = s.dom.clientWidth,
60634 h = s.dom.clientHeight;
60637 lw.setSize(ltWidth, h);
60639 mw.setLeftTop(ltWidth, t);
60640 mw.setSize(w-ltWidth, h);
60642 lb.setHeight(h-hdHeight);
60643 mb.setHeight(h-hdHeight);
60645 if(is2ndPass !== true && !gv.userResized && expandCol){
60646 // high speed resize without full column calculation
60648 var ci = cm.getIndexById(expandCol);
60650 ci = cm.findColumnIndex(expandCol);
60652 ci = Math.max(0, ci); // make sure it's got at least the first col.
60653 var expandId = cm.getColumnId(ci);
60654 var tw = cm.getTotalWidth(false);
60655 var currentWidth = cm.getColumnWidth(ci);
60656 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
60657 if(currentWidth != cw){
60658 cm.setColumnWidth(ci, cw, true);
60659 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
60660 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
60661 gv.updateSplitters();
60662 gv.layout(false, true);
60674 onWindowResize : function(){
60675 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
60681 appendFooter : function(parentEl){
60685 sortAscText : "Sort Ascending",
60686 sortDescText : "Sort Descending",
60687 lockText : "Lock Column",
60688 unlockText : "Unlock Column",
60689 columnsText : "Columns",
60691 columnsWiderText : "Wider",
60692 columnsNarrowText : "Thinner"
60696 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
60697 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
60698 this.proxy.el.addClass('x-grid3-col-dd');
60701 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
60702 handleMouseDown : function(e){
60706 callHandleMouseDown : function(e){
60707 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
60712 * Ext JS Library 1.1.1
60713 * Copyright(c) 2006-2007, Ext JS, LLC.
60715 * Originally Released Under LGPL - original licence link has changed is not relivant.
60718 * <script type="text/javascript">
60721 * @extends Roo.dd.DDProxy
60722 * @class Roo.grid.SplitDragZone
60723 * Support for Column Header resizing
60725 * @param {Object} config
60728 // This is a support class used internally by the Grid components
60729 Roo.grid.SplitDragZone = function(grid, hd, hd2){
60731 this.view = grid.getView();
60732 this.proxy = this.view.resizeProxy;
60733 Roo.grid.SplitDragZone.superclass.constructor.call(
60736 "gridSplitters" + this.grid.getGridEl().id, // SGROUP
60738 dragElId : Roo.id(this.proxy.dom),
60743 this.setHandleElId(Roo.id(hd));
60744 if (hd2 !== false) {
60745 this.setOuterHandleElId(Roo.id(hd2));
60748 this.scroll = false;
60750 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
60751 fly: Roo.Element.fly,
60753 b4StartDrag : function(x, y){
60754 this.view.headersDisabled = true;
60755 var h = this.view.mainWrap ? this.view.mainWrap.getHeight() : (
60756 this.view.headEl.getHeight() + this.view.bodyEl.getHeight()
60758 this.proxy.setHeight(h);
60760 // for old system colWidth really stored the actual width?
60761 // in bootstrap we tried using xs/ms/etc.. to do % sizing?
60762 // which in reality did not work.. - it worked only for fixed sizes
60763 // for resizable we need to use actual sizes.
60764 var w = this.cm.getColumnWidth(this.cellIndex);
60765 if (!this.view.mainWrap) {
60767 w = this.view.getHeaderIndex(this.cellIndex).getWidth();
60772 // this was w-this.grid.minColumnWidth;
60773 // doesnt really make sense? - w = thie curren width or the rendered one?
60774 var minw = Math.max(w-this.grid.minColumnWidth, 0);
60775 this.resetConstraints();
60776 this.setXConstraint(minw, 1000);
60777 this.setYConstraint(0, 0);
60778 this.minX = x - minw;
60779 this.maxX = x + 1000;
60781 if (!this.view.mainWrap) { // this is Bootstrap code..
60782 this.getDragEl().style.display='block';
60785 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
60789 handleMouseDown : function(e){
60790 ev = Roo.EventObject.setEvent(e);
60791 var t = this.fly(ev.getTarget());
60792 if(t.hasClass("x-grid-split")){
60793 this.cellIndex = this.view.getCellIndex(t.dom);
60794 this.split = t.dom;
60795 this.cm = this.grid.colModel;
60796 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
60797 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
60802 endDrag : function(e){
60803 this.view.headersDisabled = false;
60804 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
60805 var diff = endX - this.startPos;
60807 var w = this.cm.getColumnWidth(this.cellIndex);
60808 if (!this.view.mainWrap) {
60811 this.view.onColumnSplitterMoved(this.cellIndex, w+diff);
60814 autoOffset : function(){
60815 this.setDelta(0,0);
60819 * Ext JS Library 1.1.1
60820 * Copyright(c) 2006-2007, Ext JS, LLC.
60822 * Originally Released Under LGPL - original licence link has changed is not relivant.
60825 * <script type="text/javascript">
60829 // This is a support class used internally by the Grid components
60830 Roo.grid.GridDragZone = function(grid, config){
60831 this.view = grid.getView();
60832 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
60833 if(this.view.lockedBody){
60834 this.setHandleElId(Roo.id(this.view.mainBody.dom));
60835 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
60837 this.scroll = false;
60839 this.ddel = document.createElement('div');
60840 this.ddel.className = 'x-grid-dd-wrap';
60843 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
60844 ddGroup : "GridDD",
60846 getDragData : function(e){
60847 var t = Roo.lib.Event.getTarget(e);
60848 var rowIndex = this.view.findRowIndex(t);
60849 var sm = this.grid.selModel;
60851 //Roo.log(rowIndex);
60853 if (sm.getSelectedCell) {
60854 // cell selection..
60855 if (!sm.getSelectedCell()) {
60858 if (rowIndex != sm.getSelectedCell()[0]) {
60863 if (sm.getSelections && sm.getSelections().length < 1) {
60868 // before it used to all dragging of unseleted... - now we dont do that.
60869 if(rowIndex !== false){
60874 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
60876 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
60879 if (e.hasModifier()){
60880 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
60883 Roo.log("getDragData");
60888 rowIndex: rowIndex,
60889 selections: sm.getSelections ? sm.getSelections() : (
60890 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : [])
60897 onInitDrag : function(e){
60898 var data = this.dragData;
60899 this.ddel.innerHTML = this.grid.getDragDropText();
60900 this.proxy.update(this.ddel);
60901 // fire start drag?
60904 afterRepair : function(){
60905 this.dragging = false;
60908 getRepairXY : function(e, data){
60912 onEndDrag : function(data, e){
60916 onValidDrop : function(dd, e, id){
60921 beforeInvalidDrop : function(e, id){
60926 * Ext JS Library 1.1.1
60927 * Copyright(c) 2006-2007, Ext JS, LLC.
60929 * Originally Released Under LGPL - original licence link has changed is not relivant.
60932 * <script type="text/javascript">
60937 * @class Roo.grid.ColumnModel
60938 * @extends Roo.util.Observable
60939 * This is the default implementation of a ColumnModel used by the Grid. It defines
60940 * the columns in the grid.
60943 var colModel = new Roo.grid.ColumnModel([
60944 {header: "Ticker", width: 60, sortable: true, locked: true},
60945 {header: "Company Name", width: 150, sortable: true},
60946 {header: "Market Cap.", width: 100, sortable: true},
60947 {header: "$ Sales", width: 100, sortable: true, renderer: money},
60948 {header: "Employees", width: 100, sortable: true, resizable: false}
60953 * The config options listed for this class are options which may appear in each
60954 * individual column definition.
60955 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
60957 * @param {Object} config An Array of column config objects. See this class's
60958 * config objects for details.
60960 Roo.grid.ColumnModel = function(config){
60962 * The config passed into the constructor
60964 this.config = []; //config;
60967 // if no id, create one
60968 // if the column does not have a dataIndex mapping,
60969 // map it to the order it is in the config
60970 for(var i = 0, len = config.length; i < len; i++){
60971 this.addColumn(config[i]);
60976 * The width of columns which have no width specified (defaults to 100)
60979 this.defaultWidth = 100;
60982 * Default sortable of columns which have no sortable specified (defaults to false)
60985 this.defaultSortable = false;
60989 * @event widthchange
60990 * Fires when the width of a column changes.
60991 * @param {ColumnModel} this
60992 * @param {Number} columnIndex The column index
60993 * @param {Number} newWidth The new width
60995 "widthchange": true,
60997 * @event headerchange
60998 * Fires when the text of a header changes.
60999 * @param {ColumnModel} this
61000 * @param {Number} columnIndex The column index
61001 * @param {Number} newText The new header text
61003 "headerchange": true,
61005 * @event hiddenchange
61006 * Fires when a column is hidden or "unhidden".
61007 * @param {ColumnModel} this
61008 * @param {Number} columnIndex The column index
61009 * @param {Boolean} hidden true if hidden, false otherwise
61011 "hiddenchange": true,
61013 * @event columnmoved
61014 * Fires when a column is moved.
61015 * @param {ColumnModel} this
61016 * @param {Number} oldIndex
61017 * @param {Number} newIndex
61019 "columnmoved" : true,
61021 * @event columlockchange
61022 * Fires when a column's locked state is changed
61023 * @param {ColumnModel} this
61024 * @param {Number} colIndex
61025 * @param {Boolean} locked true if locked
61027 "columnlockchange" : true
61029 Roo.grid.ColumnModel.superclass.constructor.call(this);
61031 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
61033 * @cfg {String} header The header text to display in the Grid view.
61036 * @cfg {String} xsHeader Header at Bootsrap Extra Small width (default for all)
61039 * @cfg {String} smHeader Header at Bootsrap Small width
61042 * @cfg {String} mdHeader Header at Bootsrap Medium width
61045 * @cfg {String} lgHeader Header at Bootsrap Large width
61048 * @cfg {String} xlHeader Header at Bootsrap extra Large width
61051 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
61052 * {@link Roo.data.Record} definition from which to draw the column's value. If not
61053 * specified, the column's index is used as an index into the Record's data Array.
61056 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
61057 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
61060 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
61061 * Defaults to the value of the {@link #defaultSortable} property.
61062 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
61065 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
61068 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
61071 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
61074 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
61077 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
61078 * given the cell's data value. See {@link #setRenderer}. If not specified, the
61079 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
61080 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
61083 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
61086 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
61089 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
61092 * @cfg {String} cursor (Optional)
61095 * @cfg {String} tooltip (Optional)
61098 * @cfg {Number} xs (Optional) can be '0' for hidden at this size (number less than 12)
61101 * @cfg {Number} sm (Optional) can be '0' for hidden at this size (number less than 12)
61104 * @cfg {Number} md (Optional) can be '0' for hidden at this size (number less than 12)
61107 * @cfg {Number} lg (Optional) can be '0' for hidden at this size (number less than 12)
61110 * @cfg {Number} xl (Optional) can be '0' for hidden at this size (number less than 12)
61113 * Returns the id of the column at the specified index.
61114 * @param {Number} index The column index
61115 * @return {String} the id
61117 getColumnId : function(index){
61118 return this.config[index].id;
61122 * Returns the column for a specified id.
61123 * @param {String} id The column id
61124 * @return {Object} the column
61126 getColumnById : function(id){
61127 return this.lookup[id];
61132 * Returns the column Object for a specified dataIndex.
61133 * @param {String} dataIndex The column dataIndex
61134 * @return {Object|Boolean} the column or false if not found
61136 getColumnByDataIndex: function(dataIndex){
61137 var index = this.findColumnIndex(dataIndex);
61138 return index > -1 ? this.config[index] : false;
61142 * Returns the index for a specified column id.
61143 * @param {String} id The column id
61144 * @return {Number} the index, or -1 if not found
61146 getIndexById : function(id){
61147 for(var i = 0, len = this.config.length; i < len; i++){
61148 if(this.config[i].id == id){
61156 * Returns the index for a specified column dataIndex.
61157 * @param {String} dataIndex The column dataIndex
61158 * @return {Number} the index, or -1 if not found
61161 findColumnIndex : function(dataIndex){
61162 for(var i = 0, len = this.config.length; i < len; i++){
61163 if(this.config[i].dataIndex == dataIndex){
61171 moveColumn : function(oldIndex, newIndex){
61172 var c = this.config[oldIndex];
61173 this.config.splice(oldIndex, 1);
61174 this.config.splice(newIndex, 0, c);
61175 this.dataMap = null;
61176 this.fireEvent("columnmoved", this, oldIndex, newIndex);
61179 isLocked : function(colIndex){
61180 return this.config[colIndex].locked === true;
61183 setLocked : function(colIndex, value, suppressEvent){
61184 if(this.isLocked(colIndex) == value){
61187 this.config[colIndex].locked = value;
61188 if(!suppressEvent){
61189 this.fireEvent("columnlockchange", this, colIndex, value);
61193 getTotalLockedWidth : function(){
61194 var totalWidth = 0;
61195 for(var i = 0; i < this.config.length; i++){
61196 if(this.isLocked(i) && !this.isHidden(i)){
61197 this.totalWidth += this.getColumnWidth(i);
61203 getLockedCount : function(){
61204 for(var i = 0, len = this.config.length; i < len; i++){
61205 if(!this.isLocked(i)){
61210 return this.config.length;
61214 * Returns the number of columns.
61217 getColumnCount : function(visibleOnly){
61218 if(visibleOnly === true){
61220 for(var i = 0, len = this.config.length; i < len; i++){
61221 if(!this.isHidden(i)){
61227 return this.config.length;
61231 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
61232 * @param {Function} fn
61233 * @param {Object} scope (optional)
61234 * @return {Array} result
61236 getColumnsBy : function(fn, scope){
61238 for(var i = 0, len = this.config.length; i < len; i++){
61239 var c = this.config[i];
61240 if(fn.call(scope||this, c, i) === true){
61248 * Returns true if the specified column is sortable.
61249 * @param {Number} col The column index
61250 * @return {Boolean}
61252 isSortable : function(col){
61253 if(typeof this.config[col].sortable == "undefined"){
61254 return this.defaultSortable;
61256 return this.config[col].sortable;
61260 * Returns the rendering (formatting) function defined for the column.
61261 * @param {Number} col The column index.
61262 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
61264 getRenderer : function(col){
61265 if(!this.config[col].renderer){
61266 return Roo.grid.ColumnModel.defaultRenderer;
61268 return this.config[col].renderer;
61272 * Sets the rendering (formatting) function for a column.
61273 * @param {Number} col The column index
61274 * @param {Function} fn The function to use to process the cell's raw data
61275 * to return HTML markup for the grid view. The render function is called with
61276 * the following parameters:<ul>
61277 * <li>Data value.</li>
61278 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
61279 * <li>css A CSS style string to apply to the table cell.</li>
61280 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
61281 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
61282 * <li>Row index</li>
61283 * <li>Column index</li>
61284 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
61286 setRenderer : function(col, fn){
61287 this.config[col].renderer = fn;
61291 * Returns the width for the specified column.
61292 * @param {Number} col The column index
61293 * @param (optional) {String} gridSize bootstrap width size.
61296 getColumnWidth : function(col, gridSize)
61298 var cfg = this.config[col];
61300 if (typeof(gridSize) == 'undefined') {
61301 return cfg.width * 1 || this.defaultWidth;
61303 if (gridSize === false) { // if we set it..
61304 return cfg.width || false;
61306 var sizes = ['xl', 'lg', 'md', 'sm', 'xs'];
61308 for(var i = sizes.indexOf(gridSize); i < sizes.length; i++) {
61309 if (typeof(cfg[ sizes[i] ] ) == 'undefined') {
61312 return cfg[ sizes[i] ];
61319 * Sets the width for a column.
61320 * @param {Number} col The column index
61321 * @param {Number} width The new width
61323 setColumnWidth : function(col, width, suppressEvent){
61324 this.config[col].width = width;
61325 this.totalWidth = null;
61326 if(!suppressEvent){
61327 this.fireEvent("widthchange", this, col, width);
61332 * Returns the total width of all columns.
61333 * @param {Boolean} includeHidden True to include hidden column widths
61336 getTotalWidth : function(includeHidden){
61337 if(!this.totalWidth){
61338 this.totalWidth = 0;
61339 for(var i = 0, len = this.config.length; i < len; i++){
61340 if(includeHidden || !this.isHidden(i)){
61341 this.totalWidth += this.getColumnWidth(i);
61345 return this.totalWidth;
61349 * Returns the header for the specified column.
61350 * @param {Number} col The column index
61353 getColumnHeader : function(col){
61354 return this.config[col].header;
61358 * Sets the header for a column.
61359 * @param {Number} col The column index
61360 * @param {String} header The new header
61362 setColumnHeader : function(col, header){
61363 this.config[col].header = header;
61364 this.fireEvent("headerchange", this, col, header);
61368 * Returns the tooltip for the specified column.
61369 * @param {Number} col The column index
61372 getColumnTooltip : function(col){
61373 return this.config[col].tooltip;
61376 * Sets the tooltip for a column.
61377 * @param {Number} col The column index
61378 * @param {String} tooltip The new tooltip
61380 setColumnTooltip : function(col, tooltip){
61381 this.config[col].tooltip = tooltip;
61385 * Returns the dataIndex for the specified column.
61386 * @param {Number} col The column index
61389 getDataIndex : function(col){
61390 return this.config[col].dataIndex;
61394 * Sets the dataIndex for a column.
61395 * @param {Number} col The column index
61396 * @param {Number} dataIndex The new dataIndex
61398 setDataIndex : function(col, dataIndex){
61399 this.config[col].dataIndex = dataIndex;
61405 * Returns true if the cell is editable.
61406 * @param {Number} colIndex The column index
61407 * @param {Number} rowIndex The row index - this is nto actually used..?
61408 * @return {Boolean}
61410 isCellEditable : function(colIndex, rowIndex){
61411 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
61415 * Returns the editor defined for the cell/column.
61416 * return false or null to disable editing.
61417 * @param {Number} colIndex The column index
61418 * @param {Number} rowIndex The row index
61421 getCellEditor : function(colIndex, rowIndex){
61422 return this.config[colIndex].editor;
61426 * Sets if a column is editable.
61427 * @param {Number} col The column index
61428 * @param {Boolean} editable True if the column is editable
61430 setEditable : function(col, editable){
61431 this.config[col].editable = editable;
61436 * Returns true if the column is hidden.
61437 * @param {Number} colIndex The column index
61438 * @return {Boolean}
61440 isHidden : function(colIndex){
61441 return this.config[colIndex].hidden;
61446 * Returns true if the column width cannot be changed
61448 isFixed : function(colIndex){
61449 return this.config[colIndex].fixed;
61453 * Returns true if the column can be resized
61454 * @return {Boolean}
61456 isResizable : function(colIndex){
61457 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
61460 * Sets if a column is hidden.
61461 * @param {Number} colIndex The column index
61462 * @param {Boolean} hidden True if the column is hidden
61464 setHidden : function(colIndex, hidden){
61465 this.config[colIndex].hidden = hidden;
61466 this.totalWidth = null;
61467 this.fireEvent("hiddenchange", this, colIndex, hidden);
61471 * Sets the editor for a column.
61472 * @param {Number} col The column index
61473 * @param {Object} editor The editor object
61475 setEditor : function(col, editor){
61476 this.config[col].editor = editor;
61479 * Add a column (experimental...) - defaults to adding to the end..
61480 * @param {Object} config
61482 addColumn : function(c)
61485 var i = this.config.length;
61486 this.config[i] = c;
61488 if(typeof c.dataIndex == "undefined"){
61491 if(typeof c.renderer == "string"){
61492 c.renderer = Roo.util.Format[c.renderer];
61494 if(typeof c.id == "undefined"){
61497 if(c.editor && c.editor.xtype){
61498 c.editor = Roo.factory(c.editor, Roo.grid);
61500 if(c.editor && c.editor.isFormField){
61501 c.editor = new Roo.grid.GridEditor(c.editor);
61503 this.lookup[c.id] = c;
61508 Roo.grid.ColumnModel.defaultRenderer = function(value)
61510 if(typeof value == "object") {
61513 if(typeof value == "string" && value.length < 1){
61517 return String.format("{0}", value);
61520 // Alias for backwards compatibility
61521 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
61524 * Ext JS Library 1.1.1
61525 * Copyright(c) 2006-2007, Ext JS, LLC.
61527 * Originally Released Under LGPL - original licence link has changed is not relivant.
61530 * <script type="text/javascript">
61534 * @class Roo.grid.AbstractSelectionModel
61535 * @extends Roo.util.Observable
61537 * Abstract base class for grid SelectionModels. It provides the interface that should be
61538 * implemented by descendant classes. This class should not be directly instantiated.
61541 Roo.grid.AbstractSelectionModel = function(){
61542 this.locked = false;
61543 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
61546 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
61547 /** @ignore Called by the grid automatically. Do not call directly. */
61548 init : function(grid){
61554 * Locks the selections.
61557 this.locked = true;
61561 * Unlocks the selections.
61563 unlock : function(){
61564 this.locked = false;
61568 * Returns true if the selections are locked.
61569 * @return {Boolean}
61571 isLocked : function(){
61572 return this.locked;
61576 * Ext JS Library 1.1.1
61577 * Copyright(c) 2006-2007, Ext JS, LLC.
61579 * Originally Released Under LGPL - original licence link has changed is not relivant.
61582 * <script type="text/javascript">
61585 * @extends Roo.grid.AbstractSelectionModel
61586 * @class Roo.grid.RowSelectionModel
61587 * The default SelectionModel used by {@link Roo.grid.Grid}.
61588 * It supports multiple selections and keyboard selection/navigation.
61590 * @param {Object} config
61592 Roo.grid.RowSelectionModel = function(config){
61593 Roo.apply(this, config);
61594 this.selections = new Roo.util.MixedCollection(false, function(o){
61599 this.lastActive = false;
61603 * @event selectionchange
61604 * Fires when the selection changes
61605 * @param {SelectionModel} this
61607 "selectionchange" : true,
61609 * @event afterselectionchange
61610 * Fires after the selection changes (eg. by key press or clicking)
61611 * @param {SelectionModel} this
61613 "afterselectionchange" : true,
61615 * @event beforerowselect
61616 * Fires when a row is selected being selected, return false to cancel.
61617 * @param {SelectionModel} this
61618 * @param {Number} rowIndex The selected index
61619 * @param {Boolean} keepExisting False if other selections will be cleared
61621 "beforerowselect" : true,
61624 * Fires when a row is selected.
61625 * @param {SelectionModel} this
61626 * @param {Number} rowIndex The selected index
61627 * @param {Roo.data.Record} r The record
61629 "rowselect" : true,
61631 * @event rowdeselect
61632 * Fires when a row is deselected.
61633 * @param {SelectionModel} this
61634 * @param {Number} rowIndex The selected index
61636 "rowdeselect" : true
61638 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
61639 this.locked = false;
61642 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
61644 * @cfg {Boolean} singleSelect
61645 * True to allow selection of only one row at a time (defaults to false)
61647 singleSelect : false,
61650 initEvents : function(){
61652 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
61653 this.grid.on("mousedown", this.handleMouseDown, this);
61654 }else{ // allow click to work like normal
61655 this.grid.on("rowclick", this.handleDragableRowClick, this);
61657 // bootstrap does not have a view..
61658 var view = this.grid.view ? this.grid.view : this.grid;
61659 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
61660 "up" : function(e){
61662 this.selectPrevious(e.shiftKey);
61663 }else if(this.last !== false && this.lastActive !== false){
61664 var last = this.last;
61665 this.selectRange(this.last, this.lastActive-1);
61666 view.focusRow(this.lastActive);
61667 if(last !== false){
61671 this.selectFirstRow();
61673 this.fireEvent("afterselectionchange", this);
61675 "down" : function(e){
61677 this.selectNext(e.shiftKey);
61678 }else if(this.last !== false && this.lastActive !== false){
61679 var last = this.last;
61680 this.selectRange(this.last, this.lastActive+1);
61681 view.focusRow(this.lastActive);
61682 if(last !== false){
61686 this.selectFirstRow();
61688 this.fireEvent("afterselectionchange", this);
61694 view.on("refresh", this.onRefresh, this);
61695 view.on("rowupdated", this.onRowUpdated, this);
61696 view.on("rowremoved", this.onRemove, this);
61700 onRefresh : function(){
61701 var ds = this.grid.ds, i, v = this.grid.view;
61702 var s = this.selections;
61703 s.each(function(r){
61704 if((i = ds.indexOfId(r.id)) != -1){
61706 s.add(ds.getAt(i)); // updating the selection relate data
61714 onRemove : function(v, index, r){
61715 this.selections.remove(r);
61719 onRowUpdated : function(v, index, r){
61720 if(this.isSelected(r)){
61721 v.onRowSelect(index);
61727 * @param {Array} records The records to select
61728 * @param {Boolean} keepExisting (optional) True to keep existing selections
61730 selectRecords : function(records, keepExisting){
61732 this.clearSelections();
61734 var ds = this.grid.ds;
61735 for(var i = 0, len = records.length; i < len; i++){
61736 this.selectRow(ds.indexOf(records[i]), true);
61741 * Gets the number of selected rows.
61744 getCount : function(){
61745 return this.selections.length;
61749 * Selects the first row in the grid.
61751 selectFirstRow : function(){
61756 * Select the last row.
61757 * @param {Boolean} keepExisting (optional) True to keep existing selections
61759 selectLastRow : function(keepExisting){
61760 this.selectRow(this.grid.ds.getCount() - 1, keepExisting);
61764 * Selects the row immediately following the last selected row.
61765 * @param {Boolean} keepExisting (optional) True to keep existing selections
61767 selectNext : function(keepExisting){
61768 if(this.last !== false && (this.last+1) < this.grid.ds.getCount()){
61769 this.selectRow(this.last+1, keepExisting);
61770 var view = this.grid.view ? this.grid.view : this.grid;
61771 view.focusRow(this.last);
61776 * Selects the row that precedes the last selected row.
61777 * @param {Boolean} keepExisting (optional) True to keep existing selections
61779 selectPrevious : function(keepExisting){
61781 this.selectRow(this.last-1, keepExisting);
61782 var view = this.grid.view ? this.grid.view : this.grid;
61783 view.focusRow(this.last);
61788 * Returns the selected records
61789 * @return {Array} Array of selected records
61791 getSelections : function(){
61792 return [].concat(this.selections.items);
61796 * Returns the first selected record.
61799 getSelected : function(){
61800 return this.selections.itemAt(0);
61805 * Clears all selections.
61807 clearSelections : function(fast){
61812 var ds = this.grid.ds;
61813 var s = this.selections;
61814 s.each(function(r){
61815 this.deselectRow(ds.indexOfId(r.id));
61819 this.selections.clear();
61826 * Selects all rows.
61828 selectAll : function(){
61832 this.selections.clear();
61833 for(var i = 0, len = this.grid.ds.getCount(); i < len; i++){
61834 this.selectRow(i, true);
61839 * Returns True if there is a selection.
61840 * @return {Boolean}
61842 hasSelection : function(){
61843 return this.selections.length > 0;
61847 * Returns True if the specified row is selected.
61848 * @param {Number/Record} record The record or index of the record to check
61849 * @return {Boolean}
61851 isSelected : function(index){
61852 var r = typeof index == "number" ? this.grid.ds.getAt(index) : index;
61853 return (r && this.selections.key(r.id) ? true : false);
61857 * Returns True if the specified record id is selected.
61858 * @param {String} id The id of record to check
61859 * @return {Boolean}
61861 isIdSelected : function(id){
61862 return (this.selections.key(id) ? true : false);
61866 handleMouseDown : function(e, t)
61868 var view = this.grid.view ? this.grid.view : this.grid;
61870 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
61873 if(e.shiftKey && this.last !== false){
61874 var last = this.last;
61875 this.selectRange(last, rowIndex, e.ctrlKey);
61876 this.last = last; // reset the last
61877 view.focusRow(rowIndex);
61879 var isSelected = this.isSelected(rowIndex);
61880 if(e.button !== 0 && isSelected){
61881 view.focusRow(rowIndex);
61882 }else if(e.ctrlKey && isSelected){
61883 this.deselectRow(rowIndex);
61884 }else if(!isSelected){
61885 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
61886 view.focusRow(rowIndex);
61889 this.fireEvent("afterselectionchange", this);
61892 handleDragableRowClick : function(grid, rowIndex, e)
61894 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
61895 this.selectRow(rowIndex, false);
61896 var view = this.grid.view ? this.grid.view : this.grid;
61897 view.focusRow(rowIndex);
61898 this.fireEvent("afterselectionchange", this);
61903 * Selects multiple rows.
61904 * @param {Array} rows Array of the indexes of the row to select
61905 * @param {Boolean} keepExisting (optional) True to keep existing selections
61907 selectRows : function(rows, keepExisting){
61909 this.clearSelections();
61911 for(var i = 0, len = rows.length; i < len; i++){
61912 this.selectRow(rows[i], true);
61917 * Selects a range of rows. All rows in between startRow and endRow are also selected.
61918 * @param {Number} startRow The index of the first row in the range
61919 * @param {Number} endRow The index of the last row in the range
61920 * @param {Boolean} keepExisting (optional) True to retain existing selections
61922 selectRange : function(startRow, endRow, keepExisting){
61927 this.clearSelections();
61929 if(startRow <= endRow){
61930 for(var i = startRow; i <= endRow; i++){
61931 this.selectRow(i, true);
61934 for(var i = startRow; i >= endRow; i--){
61935 this.selectRow(i, true);
61941 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
61942 * @param {Number} startRow The index of the first row in the range
61943 * @param {Number} endRow The index of the last row in the range
61945 deselectRange : function(startRow, endRow, preventViewNotify){
61949 for(var i = startRow; i <= endRow; i++){
61950 this.deselectRow(i, preventViewNotify);
61956 * @param {Number} row The index of the row to select
61957 * @param {Boolean} keepExisting (optional) True to keep existing selections
61959 selectRow : function(index, keepExisting, preventViewNotify){
61960 if(this.locked || (index < 0 || index >= this.grid.ds.getCount())) {
61963 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
61964 if(!keepExisting || this.singleSelect){
61965 this.clearSelections();
61967 var r = this.grid.ds.getAt(index);
61968 this.selections.add(r);
61969 this.last = this.lastActive = index;
61970 if(!preventViewNotify){
61971 var view = this.grid.view ? this.grid.view : this.grid;
61972 view.onRowSelect(index);
61974 this.fireEvent("rowselect", this, index, r);
61975 this.fireEvent("selectionchange", this);
61981 * @param {Number} row The index of the row to deselect
61983 deselectRow : function(index, preventViewNotify){
61987 if(this.last == index){
61990 if(this.lastActive == index){
61991 this.lastActive = false;
61993 var r = this.grid.ds.getAt(index);
61994 this.selections.remove(r);
61995 if(!preventViewNotify){
61996 var view = this.grid.view ? this.grid.view : this.grid;
61997 view.onRowDeselect(index);
61999 this.fireEvent("rowdeselect", this, index);
62000 this.fireEvent("selectionchange", this);
62004 restoreLast : function(){
62006 this.last = this._last;
62011 acceptsNav : function(row, col, cm){
62012 return !cm.isHidden(col) && cm.isCellEditable(col, row);
62016 onEditorKey : function(field, e){
62017 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
62022 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
62024 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
62026 }else if(k == e.ENTER && !e.ctrlKey){
62030 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
62032 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
62034 }else if(k == e.ESC){
62038 g.startEditing(newCell[0], newCell[1]);
62043 * Ext JS Library 1.1.1
62044 * Copyright(c) 2006-2007, Ext JS, LLC.
62046 * Originally Released Under LGPL - original licence link has changed is not relivant.
62049 * <script type="text/javascript">
62052 * @class Roo.grid.CellSelectionModel
62053 * @extends Roo.grid.AbstractSelectionModel
62054 * This class provides the basic implementation for cell selection in a grid.
62056 * @param {Object} config The object containing the configuration of this model.
62057 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
62059 Roo.grid.CellSelectionModel = function(config){
62060 Roo.apply(this, config);
62062 this.selection = null;
62066 * @event beforerowselect
62067 * Fires before a cell is selected.
62068 * @param {SelectionModel} this
62069 * @param {Number} rowIndex The selected row index
62070 * @param {Number} colIndex The selected cell index
62072 "beforecellselect" : true,
62074 * @event cellselect
62075 * Fires when a cell is selected.
62076 * @param {SelectionModel} this
62077 * @param {Number} rowIndex The selected row index
62078 * @param {Number} colIndex The selected cell index
62080 "cellselect" : true,
62082 * @event selectionchange
62083 * Fires when the active selection changes.
62084 * @param {SelectionModel} this
62085 * @param {Object} selection null for no selection or an object (o) with two properties
62087 <li>o.record: the record object for the row the selection is in</li>
62088 <li>o.cell: An array of [rowIndex, columnIndex]</li>
62091 "selectionchange" : true,
62094 * Fires when the tab (or enter) was pressed on the last editable cell
62095 * You can use this to trigger add new row.
62096 * @param {SelectionModel} this
62100 * @event beforeeditnext
62101 * Fires before the next editable sell is made active
62102 * You can use this to skip to another cell or fire the tabend
62103 * if you set cell to false
62104 * @param {Object} eventdata object : { cell : [ row, col ] }
62106 "beforeeditnext" : true
62108 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
62111 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
62113 enter_is_tab: false,
62116 initEvents : function(){
62117 this.grid.on("mousedown", this.handleMouseDown, this);
62118 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
62119 var view = this.grid.view;
62120 view.on("refresh", this.onViewChange, this);
62121 view.on("rowupdated", this.onRowUpdated, this);
62122 view.on("beforerowremoved", this.clearSelections, this);
62123 view.on("beforerowsinserted", this.clearSelections, this);
62124 if(this.grid.isEditor){
62125 this.grid.on("beforeedit", this.beforeEdit, this);
62130 beforeEdit : function(e){
62131 this.select(e.row, e.column, false, true, e.record);
62135 onRowUpdated : function(v, index, r){
62136 if(this.selection && this.selection.record == r){
62137 v.onCellSelect(index, this.selection.cell[1]);
62142 onViewChange : function(){
62143 this.clearSelections(true);
62147 * Returns the currently selected cell,.
62148 * @return {Array} The selected cell (row, column) or null if none selected.
62150 getSelectedCell : function(){
62151 return this.selection ? this.selection.cell : null;
62155 * Clears all selections.
62156 * @param {Boolean} true to prevent the gridview from being notified about the change.
62158 clearSelections : function(preventNotify){
62159 var s = this.selection;
62161 if(preventNotify !== true){
62162 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
62164 this.selection = null;
62165 this.fireEvent("selectionchange", this, null);
62170 * Returns true if there is a selection.
62171 * @return {Boolean}
62173 hasSelection : function(){
62174 return this.selection ? true : false;
62178 handleMouseDown : function(e, t){
62179 var v = this.grid.getView();
62180 if(this.isLocked()){
62183 var row = v.findRowIndex(t);
62184 var cell = v.findCellIndex(t);
62185 if(row !== false && cell !== false){
62186 this.select(row, cell);
62192 * @param {Number} rowIndex
62193 * @param {Number} collIndex
62195 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
62196 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
62197 this.clearSelections();
62198 r = r || this.grid.dataSource.getAt(rowIndex);
62201 cell : [rowIndex, colIndex]
62203 if(!preventViewNotify){
62204 var v = this.grid.getView();
62205 v.onCellSelect(rowIndex, colIndex);
62206 if(preventFocus !== true){
62207 v.focusCell(rowIndex, colIndex);
62210 this.fireEvent("cellselect", this, rowIndex, colIndex);
62211 this.fireEvent("selectionchange", this, this.selection);
62216 isSelectable : function(rowIndex, colIndex, cm){
62217 return !cm.isHidden(colIndex);
62221 handleKeyDown : function(e){
62222 //Roo.log('Cell Sel Model handleKeyDown');
62223 if(!e.isNavKeyPress()){
62226 var g = this.grid, s = this.selection;
62229 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
62231 this.select(cell[0], cell[1]);
62236 var walk = function(row, col, step){
62237 return g.walkCells(row, col, step, sm.isSelectable, sm);
62239 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
62246 // handled by onEditorKey
62247 if (g.isEditor && g.editing) {
62251 newCell = walk(r, c-1, -1);
62253 newCell = walk(r, c+1, 1);
62258 newCell = walk(r+1, c, 1);
62262 newCell = walk(r-1, c, -1);
62266 newCell = walk(r, c+1, 1);
62270 newCell = walk(r, c-1, -1);
62275 if(g.isEditor && !g.editing){
62276 g.startEditing(r, c);
62285 this.select(newCell[0], newCell[1]);
62291 acceptsNav : function(row, col, cm){
62292 return !cm.isHidden(col) && cm.isCellEditable(col, row);
62296 * @param {Number} field (not used) - as it's normally used as a listener
62297 * @param {Number} e - event - fake it by using
62299 * var e = Roo.EventObjectImpl.prototype;
62300 * e.keyCode = e.TAB
62304 onEditorKey : function(field, e){
62306 var k = e.getKey(),
62309 ed = g.activeEditor,
62311 ///Roo.log('onEditorKey' + k);
62314 if (this.enter_is_tab && k == e.ENTER) {
62320 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
62322 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
62328 } else if(k == e.ENTER && !e.ctrlKey){
62331 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
62333 } else if(k == e.ESC){
62338 var ecall = { cell : newCell, forward : forward };
62339 this.fireEvent('beforeeditnext', ecall );
62340 newCell = ecall.cell;
62341 forward = ecall.forward;
62345 //Roo.log('next cell after edit');
62346 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
62347 } else if (forward) {
62348 // tabbed past last
62349 this.fireEvent.defer(100, this, ['tabend',this]);
62354 * Ext JS Library 1.1.1
62355 * Copyright(c) 2006-2007, Ext JS, LLC.
62357 * Originally Released Under LGPL - original licence link has changed is not relivant.
62360 * <script type="text/javascript">
62364 * @class Roo.grid.EditorGrid
62365 * @extends Roo.grid.Grid
62366 * Class for creating and editable grid.
62367 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
62368 * The container MUST have some type of size defined for the grid to fill. The container will be
62369 * automatically set to position relative if it isn't already.
62370 * @param {Object} dataSource The data model to bind to
62371 * @param {Object} colModel The column model with info about this grid's columns
62373 Roo.grid.EditorGrid = function(container, config){
62374 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
62375 this.getGridEl().addClass("xedit-grid");
62377 if(!this.selModel){
62378 this.selModel = new Roo.grid.CellSelectionModel();
62381 this.activeEditor = null;
62385 * @event beforeedit
62386 * Fires before cell editing is triggered. The edit event object has the following properties <br />
62387 * <ul style="padding:5px;padding-left:16px;">
62388 * <li>grid - This grid</li>
62389 * <li>record - The record being edited</li>
62390 * <li>field - The field name being edited</li>
62391 * <li>value - The value for the field being edited.</li>
62392 * <li>row - The grid row index</li>
62393 * <li>column - The grid column index</li>
62394 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
62396 * @param {Object} e An edit event (see above for description)
62398 "beforeedit" : true,
62401 * Fires after a cell is edited. <br />
62402 * <ul style="padding:5px;padding-left:16px;">
62403 * <li>grid - This grid</li>
62404 * <li>record - The record being edited</li>
62405 * <li>field - The field name being edited</li>
62406 * <li>value - The value being set</li>
62407 * <li>originalValue - The original value for the field, before the edit.</li>
62408 * <li>row - The grid row index</li>
62409 * <li>column - The grid column index</li>
62411 * @param {Object} e An edit event (see above for description)
62413 "afteredit" : true,
62415 * @event validateedit
62416 * Fires after a cell is edited, but before the value is set in the record.
62417 * You can use this to modify the value being set in the field, Return false
62418 * to cancel the change. The edit event object has the following properties <br />
62419 * <ul style="padding:5px;padding-left:16px;">
62420 * <li>editor - This editor</li>
62421 * <li>grid - This grid</li>
62422 * <li>record - The record being edited</li>
62423 * <li>field - The field name being edited</li>
62424 * <li>value - The value being set</li>
62425 * <li>originalValue - The original value for the field, before the edit.</li>
62426 * <li>row - The grid row index</li>
62427 * <li>column - The grid column index</li>
62428 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
62430 * @param {Object} e An edit event (see above for description)
62432 "validateedit" : true
62434 this.on("bodyscroll", this.stopEditing, this);
62435 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
62438 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
62440 * @cfg {Number} clicksToEdit
62441 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
62448 trackMouseOver: false, // causes very odd FF errors
62450 onCellDblClick : function(g, row, col){
62451 this.startEditing(row, col);
62454 onEditComplete : function(ed, value, startValue){
62455 this.editing = false;
62456 this.activeEditor = null;
62457 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
62459 var field = this.colModel.getDataIndex(ed.col);
62464 originalValue: startValue,
62471 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
62474 if(String(value) !== String(startValue)){
62476 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
62477 r.set(field, e.value);
62478 // if we are dealing with a combo box..
62479 // then we also set the 'name' colum to be the displayField
62480 if (ed.field.displayField && ed.field.name) {
62481 r.set(ed.field.name, ed.field.el.dom.value);
62484 delete e.cancel; //?? why!!!
62485 this.fireEvent("afteredit", e);
62488 this.fireEvent("afteredit", e); // always fire it!
62490 this.view.focusCell(ed.row, ed.col);
62494 * Starts editing the specified for the specified row/column
62495 * @param {Number} rowIndex
62496 * @param {Number} colIndex
62498 startEditing : function(row, col){
62499 this.stopEditing();
62500 if(this.colModel.isCellEditable(col, row)){
62501 this.view.ensureVisible(row, col, true);
62503 var r = this.dataSource.getAt(row);
62504 var field = this.colModel.getDataIndex(col);
62505 var cell = Roo.get(this.view.getCell(row,col));
62510 value: r.data[field],
62515 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
62516 this.editing = true;
62517 var ed = this.colModel.getCellEditor(col, row);
62523 ed.render(ed.parentEl || document.body);
62529 (function(){ // complex but required for focus issues in safari, ie and opera
62533 ed.on("complete", this.onEditComplete, this, {single: true});
62534 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
62535 this.activeEditor = ed;
62536 var v = r.data[field];
62537 ed.startEdit(this.view.getCell(row, col), v);
62538 // combo's with 'displayField and name set
62539 if (ed.field.displayField && ed.field.name) {
62540 ed.field.el.dom.value = r.data[ed.field.name];
62544 }).defer(50, this);
62550 * Stops any active editing
62552 stopEditing : function(){
62553 if(this.activeEditor){
62554 this.activeEditor.completeEdit();
62556 this.activeEditor = null;
62560 * Called to get grid's drag proxy text, by default returns this.ddText.
62563 getDragDropText : function(){
62564 var count = this.selModel.getSelectedCell() ? 1 : 0;
62565 return String.format(this.ddText, count, count == 1 ? '' : 's');
62570 * Ext JS Library 1.1.1
62571 * Copyright(c) 2006-2007, Ext JS, LLC.
62573 * Originally Released Under LGPL - original licence link has changed is not relivant.
62576 * <script type="text/javascript">
62579 // private - not really -- you end up using it !
62580 // This is a support class used internally by the Grid components
62583 * @class Roo.grid.GridEditor
62584 * @extends Roo.Editor
62585 * Class for creating and editable grid elements.
62586 * @param {Object} config any settings (must include field)
62588 Roo.grid.GridEditor = function(field, config){
62589 if (!config && field.field) {
62591 field = Roo.factory(config.field, Roo.form);
62593 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
62594 field.monitorTab = false;
62597 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
62600 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
62603 alignment: "tl-tl",
62606 cls: "x-small-editor x-grid-editor",
62611 * Ext JS Library 1.1.1
62612 * Copyright(c) 2006-2007, Ext JS, LLC.
62614 * Originally Released Under LGPL - original licence link has changed is not relivant.
62617 * <script type="text/javascript">
62622 Roo.grid.PropertyRecord = Roo.data.Record.create([
62623 {name:'name',type:'string'}, 'value'
62627 Roo.grid.PropertyStore = function(grid, source){
62629 this.store = new Roo.data.Store({
62630 recordType : Roo.grid.PropertyRecord
62632 this.store.on('update', this.onUpdate, this);
62634 this.setSource(source);
62636 Roo.grid.PropertyStore.superclass.constructor.call(this);
62641 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
62642 setSource : function(o){
62644 this.store.removeAll();
62647 if(this.isEditableValue(o[k])){
62648 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
62651 this.store.loadRecords({records: data}, {}, true);
62654 onUpdate : function(ds, record, type){
62655 if(type == Roo.data.Record.EDIT){
62656 var v = record.data['value'];
62657 var oldValue = record.modified['value'];
62658 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
62659 this.source[record.id] = v;
62661 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
62668 getProperty : function(row){
62669 return this.store.getAt(row);
62672 isEditableValue: function(val){
62673 if(val && val instanceof Date){
62675 }else if(typeof val == 'object' || typeof val == 'function'){
62681 setValue : function(prop, value){
62682 this.source[prop] = value;
62683 this.store.getById(prop).set('value', value);
62686 getSource : function(){
62687 return this.source;
62691 Roo.grid.PropertyColumnModel = function(grid, store){
62694 g.PropertyColumnModel.superclass.constructor.call(this, [
62695 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
62696 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
62698 this.store = store;
62699 this.bselect = Roo.DomHelper.append(document.body, {
62700 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
62701 {tag: 'option', value: 'true', html: 'true'},
62702 {tag: 'option', value: 'false', html: 'false'}
62705 Roo.id(this.bselect);
62708 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
62709 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
62710 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
62711 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
62712 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
62714 this.renderCellDelegate = this.renderCell.createDelegate(this);
62715 this.renderPropDelegate = this.renderProp.createDelegate(this);
62718 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
62722 valueText : 'Value',
62724 dateFormat : 'm/j/Y',
62727 renderDate : function(dateVal){
62728 return dateVal.dateFormat(this.dateFormat);
62731 renderBool : function(bVal){
62732 return bVal ? 'true' : 'false';
62735 isCellEditable : function(colIndex, rowIndex){
62736 return colIndex == 1;
62739 getRenderer : function(col){
62741 this.renderCellDelegate : this.renderPropDelegate;
62744 renderProp : function(v){
62745 return this.getPropertyName(v);
62748 renderCell : function(val){
62750 if(val instanceof Date){
62751 rv = this.renderDate(val);
62752 }else if(typeof val == 'boolean'){
62753 rv = this.renderBool(val);
62755 return Roo.util.Format.htmlEncode(rv);
62758 getPropertyName : function(name){
62759 var pn = this.grid.propertyNames;
62760 return pn && pn[name] ? pn[name] : name;
62763 getCellEditor : function(colIndex, rowIndex){
62764 var p = this.store.getProperty(rowIndex);
62765 var n = p.data['name'], val = p.data['value'];
62767 if(typeof(this.grid.customEditors[n]) == 'string'){
62768 return this.editors[this.grid.customEditors[n]];
62770 if(typeof(this.grid.customEditors[n]) != 'undefined'){
62771 return this.grid.customEditors[n];
62773 if(val instanceof Date){
62774 return this.editors['date'];
62775 }else if(typeof val == 'number'){
62776 return this.editors['number'];
62777 }else if(typeof val == 'boolean'){
62778 return this.editors['boolean'];
62780 return this.editors['string'];
62786 * @class Roo.grid.PropertyGrid
62787 * @extends Roo.grid.EditorGrid
62788 * This class represents the interface of a component based property grid control.
62789 * <br><br>Usage:<pre><code>
62790 var grid = new Roo.grid.PropertyGrid("my-container-id", {
62798 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
62799 * The container MUST have some type of size defined for the grid to fill. The container will be
62800 * automatically set to position relative if it isn't already.
62801 * @param {Object} config A config object that sets properties on this grid.
62803 Roo.grid.PropertyGrid = function(container, config){
62804 config = config || {};
62805 var store = new Roo.grid.PropertyStore(this);
62806 this.store = store;
62807 var cm = new Roo.grid.PropertyColumnModel(this, store);
62808 store.store.sort('name', 'ASC');
62809 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
62812 enableColLock:false,
62813 enableColumnMove:false,
62815 trackMouseOver: false,
62818 this.getGridEl().addClass('x-props-grid');
62819 this.lastEditRow = null;
62820 this.on('columnresize', this.onColumnResize, this);
62823 * @event beforepropertychange
62824 * Fires before a property changes (return false to stop?)
62825 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
62826 * @param {String} id Record Id
62827 * @param {String} newval New Value
62828 * @param {String} oldval Old Value
62830 "beforepropertychange": true,
62832 * @event propertychange
62833 * Fires after a property changes
62834 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
62835 * @param {String} id Record Id
62836 * @param {String} newval New Value
62837 * @param {String} oldval Old Value
62839 "propertychange": true
62841 this.customEditors = this.customEditors || {};
62843 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
62846 * @cfg {Object} customEditors map of colnames=> custom editors.
62847 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
62848 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
62849 * false disables editing of the field.
62853 * @cfg {Object} propertyNames map of property Names to their displayed value
62856 render : function(){
62857 Roo.grid.PropertyGrid.superclass.render.call(this);
62858 this.autoSize.defer(100, this);
62861 autoSize : function(){
62862 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
62864 this.view.fitColumns();
62868 onColumnResize : function(){
62869 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
62873 * Sets the data for the Grid
62874 * accepts a Key => Value object of all the elements avaiable.
62875 * @param {Object} data to appear in grid.
62877 setSource : function(source){
62878 this.store.setSource(source);
62882 * Gets all the data from the grid.
62883 * @return {Object} data data stored in grid
62885 getSource : function(){
62886 return this.store.getSource();
62895 * @class Roo.grid.Calendar
62896 * @extends Roo.grid.Grid
62897 * This class extends the Grid to provide a calendar widget
62898 * <br><br>Usage:<pre><code>
62899 var grid = new Roo.grid.Calendar("my-container-id", {
62902 selModel: mySelectionModel,
62903 autoSizeColumns: true,
62904 monitorWindowResize: false,
62905 trackMouseOver: true
62906 eventstore : real data store..
62912 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
62913 * The container MUST have some type of size defined for the grid to fill. The container will be
62914 * automatically set to position relative if it isn't already.
62915 * @param {Object} config A config object that sets properties on this grid.
62917 Roo.grid.Calendar = function(container, config){
62918 // initialize the container
62919 this.container = Roo.get(container);
62920 this.container.update("");
62921 this.container.setStyle("overflow", "hidden");
62922 this.container.addClass('x-grid-container');
62924 this.id = this.container.id;
62926 Roo.apply(this, config);
62927 // check and correct shorthanded configs
62931 for (var r = 0;r < 6;r++) {
62934 for (var c =0;c < 7;c++) {
62938 if (this.eventStore) {
62939 this.eventStore= Roo.factory(this.eventStore, Roo.data);
62940 this.eventStore.on('load',this.onLoad, this);
62941 this.eventStore.on('beforeload',this.clearEvents, this);
62945 this.dataSource = new Roo.data.Store({
62946 proxy: new Roo.data.MemoryProxy(rows),
62947 reader: new Roo.data.ArrayReader({}, [
62948 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
62951 this.dataSource.load();
62952 this.ds = this.dataSource;
62953 this.ds.xmodule = this.xmodule || false;
62956 var cellRender = function(v,x,r)
62958 return String.format(
62959 '<div class="fc-day fc-widget-content"><div>' +
62960 '<div class="fc-event-container"></div>' +
62961 '<div class="fc-day-number">{0}</div>'+
62963 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
62964 '</div></div>', v);
62969 this.colModel = new Roo.grid.ColumnModel( [
62971 xtype: 'ColumnModel',
62973 dataIndex : 'weekday0',
62975 renderer : cellRender
62978 xtype: 'ColumnModel',
62980 dataIndex : 'weekday1',
62982 renderer : cellRender
62985 xtype: 'ColumnModel',
62987 dataIndex : 'weekday2',
62988 header : 'Tuesday',
62989 renderer : cellRender
62992 xtype: 'ColumnModel',
62994 dataIndex : 'weekday3',
62995 header : 'Wednesday',
62996 renderer : cellRender
62999 xtype: 'ColumnModel',
63001 dataIndex : 'weekday4',
63002 header : 'Thursday',
63003 renderer : cellRender
63006 xtype: 'ColumnModel',
63008 dataIndex : 'weekday5',
63010 renderer : cellRender
63013 xtype: 'ColumnModel',
63015 dataIndex : 'weekday6',
63016 header : 'Saturday',
63017 renderer : cellRender
63020 this.cm = this.colModel;
63021 this.cm.xmodule = this.xmodule || false;
63025 //this.selModel = new Roo.grid.CellSelectionModel();
63026 //this.sm = this.selModel;
63027 //this.selModel.init(this);
63031 this.container.setWidth(this.width);
63035 this.container.setHeight(this.height);
63042 * The raw click event for the entire grid.
63043 * @param {Roo.EventObject} e
63048 * The raw dblclick event for the entire grid.
63049 * @param {Roo.EventObject} e
63053 * @event contextmenu
63054 * The raw contextmenu event for the entire grid.
63055 * @param {Roo.EventObject} e
63057 "contextmenu" : true,
63060 * The raw mousedown event for the entire grid.
63061 * @param {Roo.EventObject} e
63063 "mousedown" : true,
63066 * The raw mouseup event for the entire grid.
63067 * @param {Roo.EventObject} e
63072 * The raw mouseover event for the entire grid.
63073 * @param {Roo.EventObject} e
63075 "mouseover" : true,
63078 * The raw mouseout event for the entire grid.
63079 * @param {Roo.EventObject} e
63084 * The raw keypress event for the entire grid.
63085 * @param {Roo.EventObject} e
63090 * The raw keydown event for the entire grid.
63091 * @param {Roo.EventObject} e
63099 * Fires when a cell is clicked
63100 * @param {Grid} this
63101 * @param {Number} rowIndex
63102 * @param {Number} columnIndex
63103 * @param {Roo.EventObject} e
63105 "cellclick" : true,
63107 * @event celldblclick
63108 * Fires when a cell is double clicked
63109 * @param {Grid} this
63110 * @param {Number} rowIndex
63111 * @param {Number} columnIndex
63112 * @param {Roo.EventObject} e
63114 "celldblclick" : true,
63117 * Fires when a row is clicked
63118 * @param {Grid} this
63119 * @param {Number} rowIndex
63120 * @param {Roo.EventObject} e
63124 * @event rowdblclick
63125 * Fires when a row is double clicked
63126 * @param {Grid} this
63127 * @param {Number} rowIndex
63128 * @param {Roo.EventObject} e
63130 "rowdblclick" : true,
63132 * @event headerclick
63133 * Fires when a header is clicked
63134 * @param {Grid} this
63135 * @param {Number} columnIndex
63136 * @param {Roo.EventObject} e
63138 "headerclick" : true,
63140 * @event headerdblclick
63141 * Fires when a header cell is double clicked
63142 * @param {Grid} this
63143 * @param {Number} columnIndex
63144 * @param {Roo.EventObject} e
63146 "headerdblclick" : true,
63148 * @event rowcontextmenu
63149 * Fires when a row is right clicked
63150 * @param {Grid} this
63151 * @param {Number} rowIndex
63152 * @param {Roo.EventObject} e
63154 "rowcontextmenu" : true,
63156 * @event cellcontextmenu
63157 * Fires when a cell is right clicked
63158 * @param {Grid} this
63159 * @param {Number} rowIndex
63160 * @param {Number} cellIndex
63161 * @param {Roo.EventObject} e
63163 "cellcontextmenu" : true,
63165 * @event headercontextmenu
63166 * Fires when a header is right clicked
63167 * @param {Grid} this
63168 * @param {Number} columnIndex
63169 * @param {Roo.EventObject} e
63171 "headercontextmenu" : true,
63173 * @event bodyscroll
63174 * Fires when the body element is scrolled
63175 * @param {Number} scrollLeft
63176 * @param {Number} scrollTop
63178 "bodyscroll" : true,
63180 * @event columnresize
63181 * Fires when the user resizes a column
63182 * @param {Number} columnIndex
63183 * @param {Number} newSize
63185 "columnresize" : true,
63187 * @event columnmove
63188 * Fires when the user moves a column
63189 * @param {Number} oldIndex
63190 * @param {Number} newIndex
63192 "columnmove" : true,
63195 * Fires when row(s) start being dragged
63196 * @param {Grid} this
63197 * @param {Roo.GridDD} dd The drag drop object
63198 * @param {event} e The raw browser event
63200 "startdrag" : true,
63203 * Fires when a drag operation is complete
63204 * @param {Grid} this
63205 * @param {Roo.GridDD} dd The drag drop object
63206 * @param {event} e The raw browser event
63211 * Fires when dragged row(s) are dropped on a valid DD target
63212 * @param {Grid} this
63213 * @param {Roo.GridDD} dd The drag drop object
63214 * @param {String} targetId The target drag drop object
63215 * @param {event} e The raw browser event
63220 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
63221 * @param {Grid} this
63222 * @param {Roo.GridDD} dd The drag drop object
63223 * @param {String} targetId The target drag drop object
63224 * @param {event} e The raw browser event
63229 * Fires when the dragged row(s) first cross another DD target while being dragged
63230 * @param {Grid} this
63231 * @param {Roo.GridDD} dd The drag drop object
63232 * @param {String} targetId The target drag drop object
63233 * @param {event} e The raw browser event
63235 "dragenter" : true,
63238 * Fires when the dragged row(s) leave another DD target while being dragged
63239 * @param {Grid} this
63240 * @param {Roo.GridDD} dd The drag drop object
63241 * @param {String} targetId The target drag drop object
63242 * @param {event} e The raw browser event
63247 * Fires when a row is rendered, so you can change add a style to it.
63248 * @param {GridView} gridview The grid view
63249 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
63255 * Fires when the grid is rendered
63256 * @param {Grid} grid
63261 * Fires when a date is selected
63262 * @param {DatePicker} this
63263 * @param {Date} date The selected date
63267 * @event monthchange
63268 * Fires when the displayed month changes
63269 * @param {DatePicker} this
63270 * @param {Date} date The selected month
63272 'monthchange': true,
63274 * @event evententer
63275 * Fires when mouse over an event
63276 * @param {Calendar} this
63277 * @param {event} Event
63279 'evententer': true,
63281 * @event eventleave
63282 * Fires when the mouse leaves an
63283 * @param {Calendar} this
63286 'eventleave': true,
63288 * @event eventclick
63289 * Fires when the mouse click an
63290 * @param {Calendar} this
63293 'eventclick': true,
63295 * @event eventrender
63296 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
63297 * @param {Calendar} this
63298 * @param {data} data to be modified
63300 'eventrender': true
63304 Roo.grid.Grid.superclass.constructor.call(this);
63305 this.on('render', function() {
63306 this.view.el.addClass('x-grid-cal');
63308 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
63312 if (!Roo.grid.Calendar.style) {
63313 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
63316 '.x-grid-cal .x-grid-col' : {
63317 height: 'auto !important',
63318 'vertical-align': 'top'
63320 '.x-grid-cal .fc-event-hori' : {
63331 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
63333 * @cfg {Store} eventStore The store that loads events.
63338 activeDate : false,
63341 monitorWindowResize : false,
63344 resizeColumns : function() {
63345 var col = (this.view.el.getWidth() / 7) - 3;
63346 // loop through cols, and setWidth
63347 for(var i =0 ; i < 7 ; i++){
63348 this.cm.setColumnWidth(i, col);
63351 setDate :function(date) {
63353 Roo.log('setDate?');
63355 this.resizeColumns();
63356 var vd = this.activeDate;
63357 this.activeDate = date;
63358 // if(vd && this.el){
63359 // var t = date.getTime();
63360 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
63361 // Roo.log('using add remove');
63363 // this.fireEvent('monthchange', this, date);
63365 // this.cells.removeClass("fc-state-highlight");
63366 // this.cells.each(function(c){
63367 // if(c.dateValue == t){
63368 // c.addClass("fc-state-highlight");
63369 // setTimeout(function(){
63370 // try{c.dom.firstChild.focus();}catch(e){}
63380 var days = date.getDaysInMonth();
63382 var firstOfMonth = date.getFirstDateOfMonth();
63383 var startingPos = firstOfMonth.getDay()-this.startDay;
63385 if(startingPos < this.startDay){
63389 var pm = date.add(Date.MONTH, -1);
63390 var prevStart = pm.getDaysInMonth()-startingPos;
63394 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
63396 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
63397 //this.cells.addClassOnOver('fc-state-hover');
63399 var cells = this.cells.elements;
63400 var textEls = this.textNodes;
63402 //Roo.each(cells, function(cell){
63403 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
63406 days += startingPos;
63408 // convert everything to numbers so it's fast
63409 var day = 86400000;
63410 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
63413 //Roo.log(prevStart);
63415 var today = new Date().clearTime().getTime();
63416 var sel = date.clearTime().getTime();
63417 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
63418 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
63419 var ddMatch = this.disabledDatesRE;
63420 var ddText = this.disabledDatesText;
63421 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
63422 var ddaysText = this.disabledDaysText;
63423 var format = this.format;
63425 var setCellClass = function(cal, cell){
63427 //Roo.log('set Cell Class');
63429 var t = d.getTime();
63434 cell.dateValue = t;
63436 cell.className += " fc-today";
63437 cell.className += " fc-state-highlight";
63438 cell.title = cal.todayText;
63441 // disable highlight in other month..
63442 cell.className += " fc-state-highlight";
63447 //cell.className = " fc-state-disabled";
63448 cell.title = cal.minText;
63452 //cell.className = " fc-state-disabled";
63453 cell.title = cal.maxText;
63457 if(ddays.indexOf(d.getDay()) != -1){
63458 // cell.title = ddaysText;
63459 // cell.className = " fc-state-disabled";
63462 if(ddMatch && format){
63463 var fvalue = d.dateFormat(format);
63464 if(ddMatch.test(fvalue)){
63465 cell.title = ddText.replace("%0", fvalue);
63466 cell.className = " fc-state-disabled";
63470 if (!cell.initialClassName) {
63471 cell.initialClassName = cell.dom.className;
63474 cell.dom.className = cell.initialClassName + ' ' + cell.className;
63479 for(; i < startingPos; i++) {
63480 cells[i].dayName = (++prevStart);
63481 Roo.log(textEls[i]);
63482 d.setDate(d.getDate()+1);
63484 //cells[i].className = "fc-past fc-other-month";
63485 setCellClass(this, cells[i]);
63490 for(; i < days; i++){
63491 intDay = i - startingPos + 1;
63492 cells[i].dayName = (intDay);
63493 d.setDate(d.getDate()+1);
63495 cells[i].className = ''; // "x-date-active";
63496 setCellClass(this, cells[i]);
63500 for(; i < 42; i++) {
63501 //textEls[i].innerHTML = (++extraDays);
63503 d.setDate(d.getDate()+1);
63504 cells[i].dayName = (++extraDays);
63505 cells[i].className = "fc-future fc-other-month";
63506 setCellClass(this, cells[i]);
63509 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
63511 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
63513 // this will cause all the cells to mis
63516 for (var r = 0;r < 6;r++) {
63517 for (var c =0;c < 7;c++) {
63518 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
63522 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
63523 for(i=0;i<cells.length;i++) {
63525 this.cells.elements[i].dayName = cells[i].dayName ;
63526 this.cells.elements[i].className = cells[i].className;
63527 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
63528 this.cells.elements[i].title = cells[i].title ;
63529 this.cells.elements[i].dateValue = cells[i].dateValue ;
63535 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
63536 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
63538 ////if(totalRows != 6){
63539 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
63540 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
63543 this.fireEvent('monthchange', this, date);
63548 * Returns the grid's SelectionModel.
63549 * @return {SelectionModel}
63551 getSelectionModel : function(){
63552 if(!this.selModel){
63553 this.selModel = new Roo.grid.CellSelectionModel();
63555 return this.selModel;
63559 this.eventStore.load()
63565 findCell : function(dt) {
63566 dt = dt.clearTime().getTime();
63568 this.cells.each(function(c){
63569 //Roo.log("check " +c.dateValue + '?=' + dt);
63570 if(c.dateValue == dt){
63580 findCells : function(rec) {
63581 var s = rec.data.start_dt.clone().clearTime().getTime();
63583 var e= rec.data.end_dt.clone().clearTime().getTime();
63586 this.cells.each(function(c){
63587 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
63589 if(c.dateValue > e){
63592 if(c.dateValue < s){
63601 findBestRow: function(cells)
63605 for (var i =0 ; i < cells.length;i++) {
63606 ret = Math.max(cells[i].rows || 0,ret);
63613 addItem : function(rec)
63615 // look for vertical location slot in
63616 var cells = this.findCells(rec);
63618 rec.row = this.findBestRow(cells);
63620 // work out the location.
63624 for(var i =0; i < cells.length; i++) {
63632 if (crow.start.getY() == cells[i].getY()) {
63634 crow.end = cells[i];
63650 for (var i = 0; i < cells.length;i++) {
63651 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
63658 clearEvents: function() {
63660 if (!this.eventStore.getCount()) {
63663 // reset number of rows in cells.
63664 Roo.each(this.cells.elements, function(c){
63668 this.eventStore.each(function(e) {
63669 this.clearEvent(e);
63674 clearEvent : function(ev)
63677 Roo.each(ev.els, function(el) {
63678 el.un('mouseenter' ,this.onEventEnter, this);
63679 el.un('mouseleave' ,this.onEventLeave, this);
63687 renderEvent : function(ev,ctr) {
63689 ctr = this.view.el.select('.fc-event-container',true).first();
63693 this.clearEvent(ev);
63699 var cells = ev.cells;
63700 var rows = ev.rows;
63701 this.fireEvent('eventrender', this, ev);
63703 for(var i =0; i < rows.length; i++) {
63707 cls += ' fc-event-start';
63709 if ((i+1) == rows.length) {
63710 cls += ' fc-event-end';
63713 //Roo.log(ev.data);
63714 // how many rows should it span..
63715 var cg = this.eventTmpl.append(ctr,Roo.apply({
63718 }, ev.data) , true);
63721 cg.on('mouseenter' ,this.onEventEnter, this, ev);
63722 cg.on('mouseleave' ,this.onEventLeave, this, ev);
63723 cg.on('click', this.onEventClick, this, ev);
63727 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
63728 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
63731 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
63732 cg.setWidth(ebox.right - sbox.x -2);
63736 renderEvents: function()
63738 // first make sure there is enough space..
63740 if (!this.eventTmpl) {
63741 this.eventTmpl = new Roo.Template(
63742 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
63743 '<div class="fc-event-inner">' +
63744 '<span class="fc-event-time">{time}</span>' +
63745 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
63747 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
63755 this.cells.each(function(c) {
63756 //Roo.log(c.select('.fc-day-content div',true).first());
63757 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
63760 var ctr = this.view.el.select('.fc-event-container',true).first();
63763 this.eventStore.each(function(ev){
63765 this.renderEvent(ev);
63769 this.view.layout();
63773 onEventEnter: function (e, el,event,d) {
63774 this.fireEvent('evententer', this, el, event);
63777 onEventLeave: function (e, el,event,d) {
63778 this.fireEvent('eventleave', this, el, event);
63781 onEventClick: function (e, el,event,d) {
63782 this.fireEvent('eventclick', this, el, event);
63785 onMonthChange: function () {
63789 onLoad: function () {
63791 //Roo.log('calendar onload');
63793 if(this.eventStore.getCount() > 0){
63797 this.eventStore.each(function(d){
63802 if (typeof(add.end_dt) == 'undefined') {
63803 Roo.log("Missing End time in calendar data: ");
63807 if (typeof(add.start_dt) == 'undefined') {
63808 Roo.log("Missing Start time in calendar data: ");
63812 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
63813 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
63814 add.id = add.id || d.id;
63815 add.title = add.title || '??';
63823 this.renderEvents();
63833 render : function ()
63837 if (!this.view.el.hasClass('course-timesheet')) {
63838 this.view.el.addClass('course-timesheet');
63840 if (this.tsStyle) {
63845 Roo.log(_this.grid.view.el.getWidth());
63848 this.tsStyle = Roo.util.CSS.createStyleSheet({
63849 '.course-timesheet .x-grid-row' : {
63852 '.x-grid-row td' : {
63853 'vertical-align' : 0
63855 '.course-edit-link' : {
63857 'text-overflow' : 'ellipsis',
63858 'overflow' : 'hidden',
63859 'white-space' : 'nowrap',
63860 'cursor' : 'pointer'
63865 '.de-act-sup-link' : {
63866 'color' : 'purple',
63867 'text-decoration' : 'line-through'
63871 'text-decoration' : 'line-through'
63873 '.course-timesheet .course-highlight' : {
63874 'border-top-style': 'dashed !important',
63875 'border-bottom-bottom': 'dashed !important'
63877 '.course-timesheet .course-item' : {
63878 'font-family' : 'tahoma, arial, helvetica',
63879 'font-size' : '11px',
63880 'overflow' : 'hidden',
63881 'padding-left' : '10px',
63882 'padding-right' : '10px',
63883 'padding-top' : '10px'
63891 monitorWindowResize : false,
63892 cellrenderer : function(v,x,r)
63897 xtype: 'CellSelectionModel',
63904 beforeload : function (_self, options)
63906 options.params = options.params || {};
63907 options.params._month = _this.monthField.getValue();
63908 options.params.limit = 9999;
63909 options.params['sort'] = 'when_dt';
63910 options.params['dir'] = 'ASC';
63911 this.proxy.loadResponse = this.loadResponse;
63913 //this.addColumns();
63915 load : function (_self, records, options)
63917 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
63918 // if you click on the translation.. you can edit it...
63919 var el = Roo.get(this);
63920 var id = el.dom.getAttribute('data-id');
63921 var d = el.dom.getAttribute('data-date');
63922 var t = el.dom.getAttribute('data-time');
63923 //var id = this.child('span').dom.textContent;
63926 Pman.Dialog.CourseCalendar.show({
63930 productitem_active : id ? 1 : 0
63932 _this.grid.ds.load({});
63937 _this.panel.fireEvent('resize', [ '', '' ]);
63940 loadResponse : function(o, success, response){
63941 // this is overridden on before load..
63943 Roo.log("our code?");
63944 //Roo.log(success);
63945 //Roo.log(response)
63946 delete this.activeRequest;
63948 this.fireEvent("loadexception", this, o, response);
63949 o.request.callback.call(o.request.scope, null, o.request.arg, false);
63954 result = o.reader.read(response);
63956 Roo.log("load exception?");
63957 this.fireEvent("loadexception", this, o, response, e);
63958 o.request.callback.call(o.request.scope, null, o.request.arg, false);
63961 Roo.log("ready...");
63962 // loop through result.records;
63963 // and set this.tdate[date] = [] << array of records..
63965 Roo.each(result.records, function(r){
63967 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
63968 _this.tdata[r.data.when_dt.format('j')] = [];
63970 _this.tdata[r.data.when_dt.format('j')].push(r.data);
63973 //Roo.log(_this.tdata);
63975 result.records = [];
63976 result.totalRecords = 6;
63978 // let's generate some duumy records for the rows.
63979 //var st = _this.dateField.getValue();
63981 // work out monday..
63982 //st = st.add(Date.DAY, -1 * st.format('w'));
63984 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
63986 var firstOfMonth = date.getFirstDayOfMonth();
63987 var days = date.getDaysInMonth();
63989 var firstAdded = false;
63990 for (var i = 0; i < result.totalRecords ; i++) {
63991 //var d= st.add(Date.DAY, i);
63994 for(var w = 0 ; w < 7 ; w++){
63995 if(!firstAdded && firstOfMonth != w){
64002 var dd = (d > 0 && d < 10) ? "0"+d : d;
64003 row['weekday'+w] = String.format(
64004 '<span style="font-size: 16px;"><b>{0}</b></span>'+
64005 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
64007 date.format('Y-m-')+dd
64010 if(typeof(_this.tdata[d]) != 'undefined'){
64011 Roo.each(_this.tdata[d], function(r){
64015 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
64016 if(r.parent_id*1>0){
64017 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
64020 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
64021 deactive = 'de-act-link';
64024 row['weekday'+w] += String.format(
64025 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
64027 r.product_id_name, //1
64028 r.when_dt.format('h:ia'), //2
64038 // only do this if something added..
64040 result.records.push(_this.grid.dataSource.reader.newRow(row));
64044 // push it twice. (second one with an hour..
64048 this.fireEvent("load", this, o, o.request.arg);
64049 o.request.callback.call(o.request.scope, result, o.request.arg, true);
64051 sortInfo : {field: 'when_dt', direction : 'ASC' },
64053 xtype: 'HttpProxy',
64056 url : baseURL + '/Roo/Shop_course.php'
64059 xtype: 'JsonReader',
64076 'name': 'parent_id',
64080 'name': 'product_id',
64084 'name': 'productitem_id',
64102 click : function (_self, e)
64104 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
64105 sd.setMonth(sd.getMonth()-1);
64106 _this.monthField.setValue(sd.format('Y-m-d'));
64107 _this.grid.ds.load({});
64113 xtype: 'Separator',
64117 xtype: 'MonthField',
64120 render : function (_self)
64122 _this.monthField = _self;
64123 // _this.monthField.set today
64125 select : function (combo, date)
64127 _this.grid.ds.load({});
64130 value : (function() { return new Date(); })()
64133 xtype: 'Separator',
64139 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
64149 click : function (_self, e)
64151 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
64152 sd.setMonth(sd.getMonth()+1);
64153 _this.monthField.setValue(sd.format('Y-m-d'));
64154 _this.grid.ds.load({});
64167 * Ext JS Library 1.1.1
64168 * Copyright(c) 2006-2007, Ext JS, LLC.
64170 * Originally Released Under LGPL - original licence link has changed is not relivant.
64173 * <script type="text/javascript">
64177 * @class Roo.LoadMask
64178 * A simple utility class for generically masking elements while loading data. If the element being masked has
64179 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
64180 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
64181 * element's UpdateManager load indicator and will be destroyed after the initial load.
64183 * Create a new LoadMask
64184 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
64185 * @param {Object} config The config object
64187 Roo.LoadMask = function(el, config){
64188 this.el = Roo.get(el);
64189 Roo.apply(this, config);
64191 this.store.on('beforeload', this.onBeforeLoad, this);
64192 this.store.on('load', this.onLoad, this);
64193 this.store.on('loadexception', this.onLoadException, this);
64194 this.removeMask = false;
64196 var um = this.el.getUpdateManager();
64197 um.showLoadIndicator = false; // disable the default indicator
64198 um.on('beforeupdate', this.onBeforeLoad, this);
64199 um.on('update', this.onLoad, this);
64200 um.on('failure', this.onLoad, this);
64201 this.removeMask = true;
64205 Roo.LoadMask.prototype = {
64207 * @cfg {Boolean} removeMask
64208 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
64209 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
64211 removeMask : false,
64213 * @cfg {String} msg
64214 * The text to display in a centered loading message box (defaults to 'Loading...')
64216 msg : 'Loading...',
64218 * @cfg {String} msgCls
64219 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
64221 msgCls : 'x-mask-loading',
64224 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
64230 * Disables the mask to prevent it from being displayed
64232 disable : function(){
64233 this.disabled = true;
64237 * Enables the mask so that it can be displayed
64239 enable : function(){
64240 this.disabled = false;
64243 onLoadException : function()
64245 Roo.log(arguments);
64247 if (typeof(arguments[3]) != 'undefined') {
64248 Roo.MessageBox.alert("Error loading",arguments[3]);
64252 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
64253 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
64260 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
64263 onLoad : function()
64265 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
64269 onBeforeLoad : function(){
64270 if(!this.disabled){
64271 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
64276 destroy : function(){
64278 this.store.un('beforeload', this.onBeforeLoad, this);
64279 this.store.un('load', this.onLoad, this);
64280 this.store.un('loadexception', this.onLoadException, this);
64282 var um = this.el.getUpdateManager();
64283 um.un('beforeupdate', this.onBeforeLoad, this);
64284 um.un('update', this.onLoad, this);
64285 um.un('failure', this.onLoad, this);
64290 * Ext JS Library 1.1.1
64291 * Copyright(c) 2006-2007, Ext JS, LLC.
64293 * Originally Released Under LGPL - original licence link has changed is not relivant.
64296 * <script type="text/javascript">
64301 * @class Roo.XTemplate
64302 * @extends Roo.Template
64303 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
64305 var t = new Roo.XTemplate(
64306 '<select name="{name}">',
64307 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
64311 // then append, applying the master template values
64314 * Supported features:
64319 {a_variable} - output encoded.
64320 {a_variable.format:("Y-m-d")} - call a method on the variable
64321 {a_variable:raw} - unencoded output
64322 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
64323 {a_variable:this.method_on_template(...)} - call a method on the template object.
64328 <tpl for="a_variable or condition.."></tpl>
64329 <tpl if="a_variable or condition"></tpl>
64330 <tpl exec="some javascript"></tpl>
64331 <tpl name="named_template"></tpl> (experimental)
64333 <tpl for="."></tpl> - just iterate the property..
64334 <tpl for=".."></tpl> - iterates with the parent (probably the template)
64338 Roo.XTemplate = function()
64340 Roo.XTemplate.superclass.constructor.apply(this, arguments);
64347 Roo.extend(Roo.XTemplate, Roo.Template, {
64350 * The various sub templates
64355 * basic tag replacing syntax
64358 * // you can fake an object call by doing this
64362 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
64365 * compile the template
64367 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
64370 compile: function()
64374 s = ['<tpl>', s, '</tpl>'].join('');
64376 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
64377 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
64378 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
64379 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
64380 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
64385 while(true == !!(m = s.match(re))){
64386 var forMatch = m[0].match(nameRe),
64387 ifMatch = m[0].match(ifRe),
64388 execMatch = m[0].match(execRe),
64389 namedMatch = m[0].match(namedRe),
64394 name = forMatch && forMatch[1] ? forMatch[1] : '';
64397 // if - puts fn into test..
64398 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
64400 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
64405 // exec - calls a function... returns empty if true is returned.
64406 exp = execMatch && execMatch[1] ? execMatch[1] : null;
64408 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
64416 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
64417 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
64418 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
64421 var uid = namedMatch ? namedMatch[1] : id;
64425 id: namedMatch ? namedMatch[1] : id,
64432 s = s.replace(m[0], '');
64434 s = s.replace(m[0], '{xtpl'+ id + '}');
64439 for(var i = tpls.length-1; i >= 0; --i){
64440 this.compileTpl(tpls[i]);
64441 this.tpls[tpls[i].id] = tpls[i];
64443 this.master = tpls[tpls.length-1];
64447 * same as applyTemplate, except it's done to one of the subTemplates
64448 * when using named templates, you can do:
64450 * var str = pl.applySubTemplate('your-name', values);
64453 * @param {Number} id of the template
64454 * @param {Object} values to apply to template
64455 * @param {Object} parent (normaly the instance of this object)
64457 applySubTemplate : function(id, values, parent)
64461 var t = this.tpls[id];
64465 if(t.test && !t.test.call(this, values, parent)){
64469 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
64470 Roo.log(e.toString());
64476 if(t.exec && t.exec.call(this, values, parent)){
64480 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
64481 Roo.log(e.toString());
64486 var vs = t.target ? t.target.call(this, values, parent) : values;
64487 parent = t.target ? values : parent;
64488 if(t.target && vs instanceof Array){
64490 for(var i = 0, len = vs.length; i < len; i++){
64491 buf[buf.length] = t.compiled.call(this, vs[i], parent);
64493 return buf.join('');
64495 return t.compiled.call(this, vs, parent);
64497 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
64498 Roo.log(e.toString());
64499 Roo.log(t.compiled);
64504 compileTpl : function(tpl)
64506 var fm = Roo.util.Format;
64507 var useF = this.disableFormats !== true;
64508 var sep = Roo.isGecko ? "+" : ",";
64509 var undef = function(str) {
64510 Roo.log("Property not found :" + str);
64514 var fn = function(m, name, format, args)
64516 //Roo.log(arguments);
64517 args = args ? args.replace(/\\'/g,"'") : args;
64518 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
64519 if (typeof(format) == 'undefined') {
64520 format= 'htmlEncode';
64522 if (format == 'raw' ) {
64526 if(name.substr(0, 4) == 'xtpl'){
64527 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
64530 // build an array of options to determine if value is undefined..
64532 // basically get 'xxxx.yyyy' then do
64533 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
64534 // (function () { Roo.log("Property not found"); return ''; })() :
64539 Roo.each(name.split('.'), function(st) {
64540 lookfor += (lookfor.length ? '.': '') + st;
64541 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
64544 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
64547 if(format && useF){
64549 args = args ? ',' + args : "";
64551 if(format.substr(0, 5) != "this."){
64552 format = "fm." + format + '(';
64554 format = 'this.call("'+ format.substr(5) + '", ';
64558 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
64562 // called with xxyx.yuu:(test,test)
64564 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
64566 // raw.. - :raw modifier..
64567 return "'"+ sep + udef_st + name + ")"+sep+"'";
64571 // branched to use + in gecko and [].join() in others
64573 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
64574 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
64577 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
64578 body.push(tpl.body.replace(/(\r\n|\n)/g,
64579 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
64580 body.push("'].join('');};};");
64581 body = body.join('');
64584 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
64586 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
64592 applyTemplate : function(values){
64593 return this.master.compiled.call(this, values, {});
64594 //var s = this.subs;
64597 apply : function(){
64598 return this.applyTemplate.apply(this, arguments);
64603 Roo.XTemplate.from = function(el){
64604 el = Roo.getDom(el);
64605 return new Roo.XTemplate(el.value || el.innerHTML);