4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isFirefox = ua.indexOf("firefox") > -1,
57 isIE = ua.indexOf("msie") > -1,
58 isIE7 = ua.indexOf("msie 7") > -1,
59 isIE11 = /trident.*rv\:11\./.test(ua),
60 isEdge = ua.indexOf("edge") > -1,
61 isGecko = !isSafari && ua.indexOf("gecko") > -1,
62 isBorderBox = isIE && !isStrict,
63 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
64 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
65 isLinux = (ua.indexOf("linux") != -1),
66 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
67 isIOS = /iphone|ipad/.test(ua),
68 isAndroid = /android/.test(ua),
69 isTouch = (function() {
71 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
72 window.addEventListener('touchstart', function __set_has_touch__ () {
74 window.removeEventListener('touchstart', __set_has_touch__);
76 return false; // no touch on chrome!?
78 document.createEvent("TouchEvent");
85 // remove css image flicker
88 document.execCommand("BackgroundImageCache", false, true);
94 * True if the browser is in strict mode
99 * True if the page is running over SSL
104 * True when the document is fully initialized and ready for action
109 * Turn on debugging output (currently only the factory uses this)
116 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
119 enableGarbageCollector : true,
122 * True to automatically purge event listeners after uncaching an element (defaults to false).
123 * Note: this only happens if enableGarbageCollector is true.
126 enableListenerCollection:false,
129 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
130 * the IE insecure content warning (defaults to javascript:false).
133 SSL_SECURE_URL : "javascript:false",
136 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
137 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
140 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
142 emptyFn : function(){},
145 * Copies all the properties of config to obj if they don't already exist.
146 * @param {Object} obj The receiver of the properties
147 * @param {Object} config The source of the properties
148 * @return {Object} returns obj
150 applyIf : function(o, c){
153 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
160 * Applies event listeners to elements by selectors when the document is ready.
161 * The event name is specified with an @ suffix.
164 // add a listener for click on all anchors in element with id foo
165 '#foo a@click' : function(e, t){
169 // add the same listener to multiple selectors (separated by comma BEFORE the @)
170 '#foo a, #bar span.some-class@mouseover' : function(){
175 * @param {Object} obj The list of behaviors to apply
177 addBehaviors : function(o){
179 Roo.onReady(function(){
184 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
186 var parts = b.split('@');
187 if(parts[1]){ // for Object prototype breakers
190 cache[s] = Roo.select(s);
192 cache[s].on(parts[1], o[b]);
199 * Generates unique ids. If the element already has an id, it is unchanged
200 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
201 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
202 * @return {String} The generated Id.
204 id : function(el, prefix){
205 prefix = prefix || "roo-gen";
207 var id = prefix + (++idSeed);
208 return el ? (el.id ? el.id : (el.id = id)) : id;
213 * Extends one class with another class and optionally overrides members with the passed literal. This class
214 * also adds the function "override()" to the class that can be used to override
215 * members on an instance.
216 * @param {Object} subclass The class inheriting the functionality
217 * @param {Object} superclass The class being extended
218 * @param {Object} overrides (optional) A literal with members
223 var io = function(o){
228 return function(sb, sp, overrides){
229 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
232 sb = function(){sp.apply(this, arguments);};
234 var F = function(){}, sbp, spp = sp.prototype;
236 sbp = sb.prototype = new F();
240 if(spp.constructor == Object.prototype.constructor){
245 sb.override = function(o){
249 Roo.override(sb, overrides);
255 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
257 Roo.override(MyClass, {
258 newMethod1: function(){
261 newMethod2: function(foo){
266 * @param {Object} origclass The class to override
267 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
268 * containing one or more methods.
271 override : function(origclass, overrides){
273 var p = origclass.prototype;
274 for(var method in overrides){
275 p[method] = overrides[method];
280 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
282 Roo.namespace('Company', 'Company.data');
283 Company.Widget = function() { ... }
284 Company.data.CustomStore = function(config) { ... }
286 * @param {String} namespace1
287 * @param {String} namespace2
288 * @param {String} etc
291 namespace : function(){
292 var a=arguments, o=null, i, j, d, rt;
293 for (i=0; i<a.length; ++i) {
297 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
298 for (j=1; j<d.length; ++j) {
299 o[d[j]]=o[d[j]] || {};
305 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
307 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
308 Roo.factory(conf, Roo.data);
310 * @param {String} classname
311 * @param {String} namespace (optional)
315 factory : function(c, ns)
317 // no xtype, no ns or c.xns - or forced off by c.xns
318 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
321 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
322 if (c.constructor == ns[c.xtype]) {// already created...
326 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
327 var ret = new ns[c.xtype](c);
331 c.xns = false; // prevent recursion..
335 * Logs to console if it can.
337 * @param {String|Object} string
342 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
349 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
353 urlEncode : function(o){
359 var ov = o[key], k = Roo.encodeURIComponent(key);
360 var type = typeof ov;
361 if(type == 'undefined'){
363 }else if(type != "function" && type != "object"){
364 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
365 }else if(ov instanceof Array){
367 for(var i = 0, len = ov.length; i < len; i++) {
368 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
379 * Safe version of encodeURIComponent
380 * @param {String} data
384 encodeURIComponent : function (data)
387 return encodeURIComponent(data);
388 } catch(e) {} // should be an uri encode error.
390 if (data == '' || data == null){
393 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
394 function nibble_to_hex(nibble){
395 var chars = '0123456789ABCDEF';
396 return chars.charAt(nibble);
398 data = data.toString();
400 for(var i=0; i<data.length; i++){
401 var c = data.charCodeAt(i);
402 var bs = new Array();
405 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
406 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
407 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
408 bs[3] = 0x80 | (c & 0x3F);
409 }else if (c > 0x800){
411 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
412 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
413 bs[2] = 0x80 | (c & 0x3F);
416 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
417 bs[1] = 0x80 | (c & 0x3F);
422 for(var j=0; j<bs.length; j++){
424 var hex = nibble_to_hex((b & 0xF0) >>> 4)
425 + nibble_to_hex(b &0x0F);
434 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
435 * @param {String} string
436 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
437 * @return {Object} A literal with members
439 urlDecode : function(string, overwrite){
440 if(!string || !string.length){
444 var pairs = string.split('&');
445 var pair, name, value;
446 for(var i = 0, len = pairs.length; i < len; i++){
447 pair = pairs[i].split('=');
448 name = decodeURIComponent(pair[0]);
449 value = decodeURIComponent(pair[1]);
450 if(overwrite !== true){
451 if(typeof obj[name] == "undefined"){
453 }else if(typeof obj[name] == "string"){
454 obj[name] = [obj[name]];
455 obj[name].push(value);
457 obj[name].push(value);
467 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
468 * passed array is not really an array, your function is called once with it.
469 * The supplied function is called with (Object item, Number index, Array allItems).
470 * @param {Array/NodeList/Mixed} array
471 * @param {Function} fn
472 * @param {Object} scope
474 each : function(array, fn, scope){
475 if(typeof array.length == "undefined" || typeof array == "string"){
478 for(var i = 0, len = array.length; i < len; i++){
479 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
484 combine : function(){
485 var as = arguments, l = as.length, r = [];
486 for(var i = 0; i < l; i++){
488 if(a instanceof Array){
490 }else if(a.length !== undefined && !a.substr){
491 r = r.concat(Array.prototype.slice.call(a, 0));
500 * Escapes the passed string for use in a regular expression
501 * @param {String} str
504 escapeRe : function(s) {
505 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
509 callback : function(cb, scope, args, delay){
510 if(typeof cb == "function"){
512 cb.defer(delay, scope, args || []);
514 cb.apply(scope, args || []);
520 * Return the dom node for the passed string (id), dom node, or Roo.Element
521 * @param {String/HTMLElement/Roo.Element} el
522 * @return HTMLElement
524 getDom : function(el){
528 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
532 * Shorthand for {@link Roo.ComponentMgr#get}
534 * @return Roo.Component
536 getCmp : function(id){
537 return Roo.ComponentMgr.get(id);
540 num : function(v, defaultValue){
541 if(typeof v != 'number'){
547 destroy : function(){
548 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
552 as.removeAllListeners();
556 if(typeof as.purgeListeners == 'function'){
559 if(typeof as.destroy == 'function'){
566 // inpired by a similar function in mootools library
568 * Returns the type of object that is passed in. If the object passed in is null or undefined it
569 * return false otherwise it returns one of the following values:<ul>
570 * <li><b>string</b>: If the object passed is a string</li>
571 * <li><b>number</b>: If the object passed is a number</li>
572 * <li><b>boolean</b>: If the object passed is a boolean value</li>
573 * <li><b>function</b>: If the object passed is a function reference</li>
574 * <li><b>object</b>: If the object passed is an object</li>
575 * <li><b>array</b>: If the object passed is an array</li>
576 * <li><b>regexp</b>: If the object passed is a regular expression</li>
577 * <li><b>element</b>: If the object passed is a DOM Element</li>
578 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
579 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
580 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
581 * @param {Mixed} object
585 if(o === undefined || o === null){
592 if(t == 'object' && o.nodeName) {
594 case 1: return 'element';
595 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
598 if(t == 'object' || t == 'function') {
599 switch(o.constructor) {
600 case Array: return 'array';
601 case RegExp: return 'regexp';
603 if(typeof o.length == 'number' && typeof o.item == 'function') {
611 * Returns true if the passed value is null, undefined or an empty string (optional).
612 * @param {Mixed} value The value to test
613 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
616 isEmpty : function(v, allowBlank){
617 return v === null || v === undefined || (!allowBlank ? v === '' : false);
625 isFirefox : isFirefox,
637 isBorderBox : isBorderBox,
639 isWindows : isWindows,
647 isAndroid : isAndroid,
652 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
653 * you may want to set this to true.
656 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
661 * Selects a single element as a Roo Element
662 * This is about as close as you can get to jQuery's $('do crazy stuff')
663 * @param {String} selector The selector/xpath query
664 * @param {Node} root (optional) The start of the query (defaults to document).
665 * @return {Roo.Element}
667 selectNode : function(selector, root)
669 var node = Roo.DomQuery.selectNode(selector,root);
670 return node ? Roo.get(node) : new Roo.Element(false);
673 * Find the current bootstrap width Grid size
674 * Note xs is the default for smaller.. - this is currently used by grids to render correct columns
675 * @returns {String} (xs|sm|md|lg|xl)
678 getGridSize : function()
680 var w = Roo.lib.Dom.getViewWidth();
701 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
702 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
707 * Ext JS Library 1.1.1
708 * Copyright(c) 2006-2007, Ext JS, LLC.
710 * Originally Released Under LGPL - original licence link has changed is not relivant.
713 * <script type="text/javascript">
717 // wrappedn so fnCleanup is not in global scope...
719 function fnCleanUp() {
720 var p = Function.prototype;
721 delete p.createSequence;
723 delete p.createDelegate;
724 delete p.createCallback;
725 delete p.createInterceptor;
727 window.detachEvent("onunload", fnCleanUp);
729 window.attachEvent("onunload", fnCleanUp);
736 * These functions are available on every Function object (any JavaScript function).
738 Roo.apply(Function.prototype, {
740 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
741 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
742 * Will create a function that is bound to those 2 args.
743 * @return {Function} The new function
745 createCallback : function(/*args...*/){
746 // make args available, in function below
747 var args = arguments;
750 return method.apply(window, args);
755 * Creates a delegate (callback) that sets the scope to obj.
756 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
757 * Will create a function that is automatically scoped to this.
758 * @param {Object} obj (optional) The object for which the scope is set
759 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
760 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
761 * if a number the args are inserted at the specified position
762 * @return {Function} The new function
764 createDelegate : function(obj, args, appendArgs){
767 var callArgs = args || arguments;
768 if(appendArgs === true){
769 callArgs = Array.prototype.slice.call(arguments, 0);
770 callArgs = callArgs.concat(args);
771 }else if(typeof appendArgs == "number"){
772 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
773 var applyArgs = [appendArgs, 0].concat(args); // create method call params
774 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
776 return method.apply(obj || window, callArgs);
781 * Calls this function after the number of millseconds specified.
782 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
783 * @param {Object} obj (optional) The object for which the scope is set
784 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
785 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
786 * if a number the args are inserted at the specified position
787 * @return {Number} The timeout id that can be used with clearTimeout
789 defer : function(millis, obj, args, appendArgs){
790 var fn = this.createDelegate(obj, args, appendArgs);
792 return setTimeout(fn, millis);
798 * Create a combined function call sequence of the original function + the passed function.
799 * The resulting function returns the results of the original function.
800 * The passed fcn is called with the parameters of the original function
801 * @param {Function} fcn The function to sequence
802 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
803 * @return {Function} The new function
805 createSequence : function(fcn, scope){
806 if(typeof fcn != "function"){
811 var retval = method.apply(this || window, arguments);
812 fcn.apply(scope || this || window, arguments);
818 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
819 * The resulting function returns the results of the original function.
820 * The passed fcn is called with the parameters of the original function.
822 * @param {Function} fcn The function to call before the original
823 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
824 * @return {Function} The new function
826 createInterceptor : function(fcn, scope){
827 if(typeof fcn != "function"){
834 if(fcn.apply(scope || this || window, arguments) === false){
837 return method.apply(this || window, arguments);
843 * Ext JS Library 1.1.1
844 * Copyright(c) 2006-2007, Ext JS, LLC.
846 * Originally Released Under LGPL - original licence link has changed is not relivant.
849 * <script type="text/javascript">
852 Roo.applyIf(String, {
857 * Escapes the passed string for ' and \
858 * @param {String} string The string to escape
859 * @return {String} The escaped string
862 escape : function(string) {
863 return string.replace(/('|\\)/g, "\\$1");
867 * Pads the left side of a string with a specified character. This is especially useful
868 * for normalizing number and date strings. Example usage:
870 var s = String.leftPad('123', 5, '0');
871 // s now contains the string: '00123'
873 * @param {String} string The original string
874 * @param {Number} size The total length of the output string
875 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
876 * @return {String} The padded string
879 leftPad : function (val, size, ch) {
880 var result = new String(val);
881 if(ch === null || ch === undefined || ch === '') {
884 while (result.length < size) {
885 result = ch + result;
891 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
892 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
894 var cls = 'my-class', text = 'Some text';
895 var s = String.format('<div class="{0}">{1}</div>', cls, text);
896 // s now contains the string: '<div class="my-class">Some text</div>'
898 * @param {String} string The tokenized string to be formatted
899 * @param {String} value1 The value to replace token {0}
900 * @param {String} value2 Etc...
901 * @return {String} The formatted string
904 format : function(format){
905 var args = Array.prototype.slice.call(arguments, 1);
906 return format.replace(/\{(\d+)\}/g, function(m, i){
907 return Roo.util.Format.htmlEncode(args[i]);
915 * Utility function that allows you to easily switch a string between two alternating values. The passed value
916 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
917 * they are already different, the first value passed in is returned. Note that this method returns the new value
918 * but does not change the current string.
920 // alternate sort directions
921 sort = sort.toggle('ASC', 'DESC');
923 // instead of conditional logic:
924 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
926 * @param {String} value The value to compare to the current string
927 * @param {String} other The new value to use if the string already equals the first value passed in
928 * @return {String} The new value
931 String.prototype.toggle = function(value, other){
932 return this == value ? other : value;
937 * Remove invalid unicode characters from a string
939 * @return {String} The clean string
941 String.prototype.unicodeClean = function () {
942 return this.replace(/[\s\S]/g,
943 function(character) {
944 if (character.charCodeAt()< 256) {
948 encodeURIComponent(character);
959 * Ext JS Library 1.1.1
960 * Copyright(c) 2006-2007, Ext JS, LLC.
962 * Originally Released Under LGPL - original licence link has changed is not relivant.
965 * <script type="text/javascript">
971 Roo.applyIf(Number.prototype, {
973 * Checks whether or not the current number is within a desired range. If the number is already within the
974 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
975 * exceeded. Note that this method returns the constrained value but does not change the current number.
976 * @param {Number} min The minimum number in the range
977 * @param {Number} max The maximum number in the range
978 * @return {Number} The constrained value if outside the range, otherwise the current value
980 constrain : function(min, max){
981 return Math.min(Math.max(this, min), max);
985 * Ext JS Library 1.1.1
986 * Copyright(c) 2006-2007, Ext JS, LLC.
988 * Originally Released Under LGPL - original licence link has changed is not relivant.
991 * <script type="text/javascript">
996 Roo.applyIf(Array.prototype, {
999 * Checks whether or not the specified object exists in the array.
1000 * @param {Object} o The object to check for
1001 * @return {Number} The index of o in the array (or -1 if it is not found)
1003 indexOf : function(o){
1004 for (var i = 0, len = this.length; i < len; i++){
1005 if(this[i] == o) { return i; }
1011 * Removes the specified object from the array. If the object is not found nothing happens.
1012 * @param {Object} o The object to remove
1014 remove : function(o){
1015 var index = this.indexOf(o);
1017 this.splice(index, 1);
1021 * Map (JS 1.6 compatibility)
1022 * @param {Function} function to call
1024 map : function(fun )
1026 var len = this.length >>> 0;
1027 if (typeof fun != "function") {
1028 throw new TypeError();
1030 var res = new Array(len);
1031 var thisp = arguments[1];
1032 for (var i = 0; i < len; i++)
1035 res[i] = fun.call(thisp, this[i], i, this);
1043 * @param {Array} o The array to compare to
1044 * @returns {Boolean} true if the same
1046 equals : function(b)
1048 // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
1055 if (this.length !== b.length) {
1059 // sort?? a.sort().equals(b.sort());
1061 for (var i = 0; i < this.length; ++i) {
1062 if (this[i] !== b[i]) {
1074 Roo.applyIf(Array, {
1078 * @param {Array} o Or Array like object (eg. nodelist)
1085 for (var i =0; i < o.length; i++) {
1094 * Ext JS Library 1.1.1
1095 * Copyright(c) 2006-2007, Ext JS, LLC.
1097 * Originally Released Under LGPL - original licence link has changed is not relivant.
1100 * <script type="text/javascript">
1106 * The date parsing and format syntax is a subset of
1107 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1108 * supported will provide results equivalent to their PHP versions.
1110 * Following is the list of all currently supported formats:
1113 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1115 Format Output Description
1116 ------ ---------- --------------------------------------------------------------
1117 d 10 Day of the month, 2 digits with leading zeros
1118 D Wed A textual representation of a day, three letters
1119 j 10 Day of the month without leading zeros
1120 l Wednesday A full textual representation of the day of the week
1121 S th English ordinal day of month suffix, 2 chars (use with j)
1122 w 3 Numeric representation of the day of the week
1123 z 9 The julian date, or day of the year (0-365)
1124 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1125 F January A full textual representation of the month
1126 m 01 Numeric representation of a month, with leading zeros
1127 M Jan Month name abbreviation, three letters
1128 n 1 Numeric representation of a month, without leading zeros
1129 t 31 Number of days in the given month
1130 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1131 Y 2007 A full numeric representation of a year, 4 digits
1132 y 07 A two digit representation of a year
1133 a pm Lowercase Ante meridiem and Post meridiem
1134 A PM Uppercase Ante meridiem and Post meridiem
1135 g 3 12-hour format of an hour without leading zeros
1136 G 15 24-hour format of an hour without leading zeros
1137 h 03 12-hour format of an hour with leading zeros
1138 H 15 24-hour format of an hour with leading zeros
1139 i 05 Minutes with leading zeros
1140 s 01 Seconds, with leading zeros
1141 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1142 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1143 T CST Timezone setting of the machine running the code
1144 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1147 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1149 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1150 document.write(dt.format('Y-m-d')); //2007-01-10
1151 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1152 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1155 * Here are some standard date/time patterns that you might find helpful. They
1156 * are not part of the source of Date.js, but to use them you can simply copy this
1157 * block of code into any script that is included after Date.js and they will also become
1158 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1161 ISO8601Long:"Y-m-d H:i:s",
1162 ISO8601Short:"Y-m-d",
1164 LongDate: "l, F d, Y",
1165 FullDateTime: "l, F d, Y g:i:s A",
1168 LongTime: "g:i:s A",
1169 SortableDateTime: "Y-m-d\\TH:i:s",
1170 UniversalSortableDateTime: "Y-m-d H:i:sO",
1177 var dt = new Date();
1178 document.write(dt.format(Date.patterns.ShortDate));
1183 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1184 * They generate precompiled functions from date formats instead of parsing and
1185 * processing the pattern every time you format a date. These functions are available
1186 * on every Date object (any javascript function).
1188 * The original article and download are here:
1189 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1196 Returns the number of milliseconds between this date and date
1197 @param {Date} date (optional) Defaults to now
1198 @return {Number} The diff in milliseconds
1199 @member Date getElapsed
1201 Date.prototype.getElapsed = function(date) {
1202 return Math.abs((date || new Date()).getTime()-this.getTime());
1204 // was in date file..
1208 Date.parseFunctions = {count:0};
1210 Date.parseRegexes = [];
1212 Date.formatFunctions = {count:0};
1215 Date.prototype.dateFormat = function(format) {
1216 if (Date.formatFunctions[format] == null) {
1217 Date.createNewFormat(format);
1219 var func = Date.formatFunctions[format];
1220 return this[func]();
1225 * Formats a date given the supplied format string
1226 * @param {String} format The format string
1227 * @return {String} The formatted date
1230 Date.prototype.format = Date.prototype.dateFormat;
1233 Date.createNewFormat = function(format) {
1234 var funcName = "format" + Date.formatFunctions.count++;
1235 Date.formatFunctions[format] = funcName;
1236 var code = "Date.prototype." + funcName + " = function(){return ";
1237 var special = false;
1239 for (var i = 0; i < format.length; ++i) {
1240 ch = format.charAt(i);
1241 if (!special && ch == "\\") {
1246 code += "'" + String.escape(ch) + "' + ";
1249 code += Date.getFormatCode(ch);
1252 /** eval:var:zzzzzzzzzzzzz */
1253 eval(code.substring(0, code.length - 3) + ";}");
1257 Date.getFormatCode = function(character) {
1258 switch (character) {
1260 return "String.leftPad(this.getDate(), 2, '0') + ";
1262 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1264 return "this.getDate() + ";
1266 return "Date.dayNames[this.getDay()] + ";
1268 return "this.getSuffix() + ";
1270 return "this.getDay() + ";
1272 return "this.getDayOfYear() + ";
1274 return "this.getWeekOfYear() + ";
1276 return "Date.monthNames[this.getMonth()] + ";
1278 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1280 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1282 return "(this.getMonth() + 1) + ";
1284 return "this.getDaysInMonth() + ";
1286 return "(this.isLeapYear() ? 1 : 0) + ";
1288 return "this.getFullYear() + ";
1290 return "('' + this.getFullYear()).substring(2, 4) + ";
1292 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1294 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1296 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1298 return "this.getHours() + ";
1300 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1302 return "String.leftPad(this.getHours(), 2, '0') + ";
1304 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1306 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1308 return "this.getGMTOffset() + ";
1310 return "this.getGMTColonOffset() + ";
1312 return "this.getTimezone() + ";
1314 return "(this.getTimezoneOffset() * -60) + ";
1316 return "'" + String.escape(character) + "' + ";
1321 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1322 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1323 * the date format that is not specified will default to the current date value for that part. Time parts can also
1324 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1325 * string or the parse operation will fail.
1328 //dt = Fri May 25 2007 (current date)
1329 var dt = new Date();
1331 //dt = Thu May 25 2006 (today's month/day in 2006)
1332 dt = Date.parseDate("2006", "Y");
1334 //dt = Sun Jan 15 2006 (all date parts specified)
1335 dt = Date.parseDate("2006-1-15", "Y-m-d");
1337 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1338 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1340 * @param {String} input The unparsed date as a string
1341 * @param {String} format The format the date is in
1342 * @return {Date} The parsed date
1345 Date.parseDate = function(input, format) {
1346 if (Date.parseFunctions[format] == null) {
1347 Date.createParser(format);
1349 var func = Date.parseFunctions[format];
1350 return Date[func](input);
1356 Date.createParser = function(format) {
1357 var funcName = "parse" + Date.parseFunctions.count++;
1358 var regexNum = Date.parseRegexes.length;
1359 var currentGroup = 1;
1360 Date.parseFunctions[format] = funcName;
1362 var code = "Date." + funcName + " = function(input){\n"
1363 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1364 + "var d = new Date();\n"
1365 + "y = d.getFullYear();\n"
1366 + "m = d.getMonth();\n"
1367 + "d = d.getDate();\n"
1368 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1369 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1370 + "if (results && results.length > 0) {";
1373 var special = false;
1375 for (var i = 0; i < format.length; ++i) {
1376 ch = format.charAt(i);
1377 if (!special && ch == "\\") {
1382 regex += String.escape(ch);
1385 var obj = Date.formatCodeToRegex(ch, currentGroup);
1386 currentGroup += obj.g;
1388 if (obj.g && obj.c) {
1394 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1395 + "{v = new Date(y, m, d, h, i, s); v.setFullYear(y);}\n"
1396 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1397 + "{v = new Date(y, m, d, h, i); v.setFullYear(y);}\n"
1398 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1399 + "{v = new Date(y, m, d, h); v.setFullYear(y);}\n"
1400 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1401 + "{v = new Date(y, m, d); v.setFullYear(y);}\n"
1402 + "else if (y >= 0 && m >= 0)\n"
1403 + "{v = new Date(y, m); v.setFullYear(y);}\n"
1404 + "else if (y >= 0)\n"
1405 + "{v = new Date(y); v.setFullYear(y);}\n"
1406 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1407 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1408 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1411 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1412 /** eval:var:zzzzzzzzzzzzz */
1417 Date.formatCodeToRegex = function(character, currentGroup) {
1418 switch (character) {
1422 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1425 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1426 s:"(\\d{1,2})"}; // day of month without leading zeroes
1429 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1430 s:"(\\d{2})"}; // day of month with leading zeroes
1434 s:"(?:" + Date.dayNames.join("|") + ")"};
1438 s:"(?:st|nd|rd|th)"};
1453 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1454 s:"(" + Date.monthNames.join("|") + ")"};
1457 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1458 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1461 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1462 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1465 c:"m = Math.max(0,parseInt(results[" + currentGroup + "], 10) - 1);\n",
1466 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1477 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1481 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1482 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1486 c:"if (results[" + currentGroup + "] == 'am') {\n"
1487 + "if (h == 12) { h = 0; }\n"
1488 + "} else { if (h < 12) { h += 12; }}",
1492 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1493 + "if (h == 12) { h = 0; }\n"
1494 + "} else { if (h < 12) { h += 12; }}",
1499 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1500 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1504 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1505 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1508 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1512 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1517 "o = results[", currentGroup, "];\n",
1518 "var sn = o.substring(0,1);\n", // get + / - sign
1519 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1520 "var mn = o.substring(3,5) % 60;\n", // get minutes
1521 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1522 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1524 s:"([+\-]\\d{2,4})"};
1530 "o = results[", currentGroup, "];\n",
1531 "var sn = o.substring(0,1);\n",
1532 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1533 "var mn = o.substring(4,6) % 60;\n",
1534 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1535 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1541 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1544 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1545 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1546 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1550 s:String.escape(character)};
1555 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1556 * @return {String} The abbreviated timezone name (e.g. 'CST')
1558 Date.prototype.getTimezone = function() {
1559 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1563 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1564 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1566 Date.prototype.getGMTOffset = function() {
1567 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1568 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1569 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1573 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1574 * @return {String} 2-characters representing hours and 2-characters representing minutes
1575 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1577 Date.prototype.getGMTColonOffset = function() {
1578 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1579 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1581 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1585 * Get the numeric day number of the year, adjusted for leap year.
1586 * @return {Number} 0 through 364 (365 in leap years)
1588 Date.prototype.getDayOfYear = function() {
1590 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1591 for (var i = 0; i < this.getMonth(); ++i) {
1592 num += Date.daysInMonth[i];
1594 return num + this.getDate() - 1;
1598 * Get the string representation of the numeric week number of the year
1599 * (equivalent to the format specifier 'W').
1600 * @return {String} '00' through '52'
1602 Date.prototype.getWeekOfYear = function() {
1603 // Skip to Thursday of this week
1604 var now = this.getDayOfYear() + (4 - this.getDay());
1605 // Find the first Thursday of the year
1606 var jan1 = new Date(this.getFullYear(), 0, 1);
1607 var then = (7 - jan1.getDay() + 4);
1608 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1612 * Whether or not the current date is in a leap year.
1613 * @return {Boolean} True if the current date is in a leap year, else false
1615 Date.prototype.isLeapYear = function() {
1616 var year = this.getFullYear();
1617 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1621 * Get the first day of the current month, adjusted for leap year. The returned value
1622 * is the numeric day index within the week (0-6) which can be used in conjunction with
1623 * the {@link #monthNames} array to retrieve the textual day name.
1626 var dt = new Date('1/10/2007');
1627 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1629 * @return {Number} The day number (0-6)
1631 Date.prototype.getFirstDayOfMonth = function() {
1632 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1633 return (day < 0) ? (day + 7) : day;
1637 * Get the last day of the current month, adjusted for leap year. The returned value
1638 * is the numeric day index within the week (0-6) which can be used in conjunction with
1639 * the {@link #monthNames} array to retrieve the textual day name.
1642 var dt = new Date('1/10/2007');
1643 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1645 * @return {Number} The day number (0-6)
1647 Date.prototype.getLastDayOfMonth = function() {
1648 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1649 return (day < 0) ? (day + 7) : day;
1654 * Get the first date of this date's month
1657 Date.prototype.getFirstDateOfMonth = function() {
1658 return new Date(this.getFullYear(), this.getMonth(), 1);
1662 * Get the last date of this date's month
1665 Date.prototype.getLastDateOfMonth = function() {
1666 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1669 * Get the number of days in the current month, adjusted for leap year.
1670 * @return {Number} The number of days in the month
1672 Date.prototype.getDaysInMonth = function() {
1673 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1674 return Date.daysInMonth[this.getMonth()];
1678 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1679 * @return {String} 'st, 'nd', 'rd' or 'th'
1681 Date.prototype.getSuffix = function() {
1682 switch (this.getDate()) {
1699 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1702 * An array of textual month names.
1703 * Override these values for international dates, for example...
1704 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1723 * An array of textual day names.
1724 * Override these values for international dates, for example...
1725 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1741 Date.monthNumbers = {
1756 * Creates and returns a new Date instance with the exact same date value as the called instance.
1757 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1758 * variable will also be changed. When the intention is to create a new variable that will not
1759 * modify the original instance, you should create a clone.
1761 * Example of correctly cloning a date:
1764 var orig = new Date('10/1/2006');
1767 document.write(orig); //returns 'Thu Oct 05 2006'!
1770 var orig = new Date('10/1/2006');
1771 var copy = orig.clone();
1773 document.write(orig); //returns 'Thu Oct 01 2006'
1775 * @return {Date} The new Date instance
1777 Date.prototype.clone = function() {
1778 return new Date(this.getTime());
1782 * Clears any time information from this date
1783 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1784 @return {Date} this or the clone
1786 Date.prototype.clearTime = function(clone){
1788 return this.clone().clearTime();
1793 this.setMilliseconds(0);
1798 // safari setMonth is broken -- check that this is only donw once...
1799 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1800 Date.brokenSetMonth = Date.prototype.setMonth;
1801 Date.prototype.setMonth = function(num){
1803 var n = Math.ceil(-num);
1804 var back_year = Math.ceil(n/12);
1805 var month = (n % 12) ? 12 - n % 12 : 0 ;
1806 this.setFullYear(this.getFullYear() - back_year);
1807 return Date.brokenSetMonth.call(this, month);
1809 return Date.brokenSetMonth.apply(this, arguments);
1814 /** Date interval constant
1818 /** Date interval constant
1822 /** Date interval constant
1826 /** Date interval constant
1830 /** Date interval constant
1834 /** Date interval constant
1838 /** Date interval constant
1844 * Provides a convenient method of performing basic date arithmetic. This method
1845 * does not modify the Date instance being called - it creates and returns
1846 * a new Date instance containing the resulting date value.
1851 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1852 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1854 //Negative values will subtract correctly:
1855 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1856 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1858 //You can even chain several calls together in one line!
1859 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1860 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1863 * @param {String} interval A valid date interval enum value
1864 * @param {Number} value The amount to add to the current date
1865 * @return {Date} The new Date instance
1867 Date.prototype.add = function(interval, value){
1868 var d = this.clone();
1869 if (!interval || value === 0) { return d; }
1870 switch(interval.toLowerCase()){
1872 d.setMilliseconds(this.getMilliseconds() + value);
1875 d.setSeconds(this.getSeconds() + value);
1878 d.setMinutes(this.getMinutes() + value);
1881 d.setHours(this.getHours() + value);
1884 d.setDate(this.getDate() + value);
1887 var day = this.getDate();
1889 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1892 d.setMonth(this.getMonth() + value);
1895 d.setFullYear(this.getFullYear() + value);
1901 * @class Roo.lib.Dom
1905 * Dom utils (from YIU afaik)
1911 * Get the view width
1912 * @param {Boolean} full True will get the full document, otherwise it's the view width
1913 * @return {Number} The width
1916 getViewWidth : function(full) {
1917 return full ? this.getDocumentWidth() : this.getViewportWidth();
1920 * Get the view height
1921 * @param {Boolean} full True will get the full document, otherwise it's the view height
1922 * @return {Number} The height
1924 getViewHeight : function(full) {
1925 return full ? this.getDocumentHeight() : this.getViewportHeight();
1928 * Get the Full Document height
1929 * @return {Number} The height
1931 getDocumentHeight: function() {
1932 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1933 return Math.max(scrollHeight, this.getViewportHeight());
1936 * Get the Full Document width
1937 * @return {Number} The width
1939 getDocumentWidth: function() {
1940 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1941 return Math.max(scrollWidth, this.getViewportWidth());
1944 * Get the Window Viewport height
1945 * @return {Number} The height
1947 getViewportHeight: function() {
1948 var height = self.innerHeight;
1949 var mode = document.compatMode;
1951 if ((mode || Roo.isIE) && !Roo.isOpera) {
1952 height = (mode == "CSS1Compat") ?
1953 document.documentElement.clientHeight :
1954 document.body.clientHeight;
1960 * Get the Window Viewport width
1961 * @return {Number} The width
1963 getViewportWidth: function() {
1964 var width = self.innerWidth;
1965 var mode = document.compatMode;
1967 if (mode || Roo.isIE) {
1968 width = (mode == "CSS1Compat") ?
1969 document.documentElement.clientWidth :
1970 document.body.clientWidth;
1975 isAncestor : function(p, c) {
1982 if (p.contains && !Roo.isSafari) {
1983 return p.contains(c);
1984 } else if (p.compareDocumentPosition) {
1985 return !!(p.compareDocumentPosition(c) & 16);
1987 var parent = c.parentNode;
1992 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1995 parent = parent.parentNode;
2001 getRegion : function(el) {
2002 return Roo.lib.Region.getRegion(el);
2005 getY : function(el) {
2006 return this.getXY(el)[1];
2009 getX : function(el) {
2010 return this.getXY(el)[0];
2013 getXY : function(el) {
2014 var p, pe, b, scroll, bd = document.body;
2015 el = Roo.getDom(el);
2016 var fly = Roo.lib.AnimBase.fly;
2017 if (el.getBoundingClientRect) {
2018 b = el.getBoundingClientRect();
2019 scroll = fly(document).getScroll();
2020 return [b.left + scroll.left, b.top + scroll.top];
2026 var hasAbsolute = fly(el).getStyle("position") == "absolute";
2033 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
2040 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
2041 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2048 if (p != el && pe.getStyle('overflow') != 'visible') {
2056 if (Roo.isSafari && hasAbsolute) {
2061 if (Roo.isGecko && !hasAbsolute) {
2063 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2064 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2068 while (p && p != bd) {
2069 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2081 setXY : function(el, xy) {
2082 el = Roo.fly(el, '_setXY');
2084 var pts = el.translatePoints(xy);
2085 if (xy[0] !== false) {
2086 el.dom.style.left = pts.left + "px";
2088 if (xy[1] !== false) {
2089 el.dom.style.top = pts.top + "px";
2093 setX : function(el, x) {
2094 this.setXY(el, [x, false]);
2097 setY : function(el, y) {
2098 this.setXY(el, [false, y]);
2102 * Portions of this file are based on pieces of Yahoo User Interface Library
2103 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2104 * YUI licensed under the BSD License:
2105 * http://developer.yahoo.net/yui/license.txt
2106 * <script type="text/javascript">
2110 Roo.lib.Event = function() {
2111 var loadComplete = false;
2113 var unloadListeners = [];
2115 var onAvailStack = [];
2117 var lastError = null;
2130 startInterval: function() {
2131 if (!this._interval) {
2133 var callback = function() {
2134 self._tryPreloadAttach();
2136 this._interval = setInterval(callback, this.POLL_INTERVAL);
2141 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2142 onAvailStack.push({ id: p_id,
2145 override: p_override,
2146 checkReady: false });
2148 retryCount = this.POLL_RETRYS;
2149 this.startInterval();
2153 addListener: function(el, eventName, fn) {
2154 el = Roo.getDom(el);
2159 if ("unload" == eventName) {
2160 unloadListeners[unloadListeners.length] =
2161 [el, eventName, fn];
2165 var wrappedFn = function(e) {
2166 return fn(Roo.lib.Event.getEvent(e));
2169 var li = [el, eventName, fn, wrappedFn];
2171 var index = listeners.length;
2172 listeners[index] = li;
2174 this.doAdd(el, eventName, wrappedFn, false);
2180 removeListener: function(el, eventName, fn) {
2183 el = Roo.getDom(el);
2186 return this.purgeElement(el, false, eventName);
2190 if ("unload" == eventName) {
2192 for (i = 0,len = unloadListeners.length; i < len; i++) {
2193 var li = unloadListeners[i];
2196 li[1] == eventName &&
2198 unloadListeners.splice(i, 1);
2206 var cacheItem = null;
2209 var index = arguments[3];
2211 if ("undefined" == typeof index) {
2212 index = this._getCacheIndex(el, eventName, fn);
2216 cacheItem = listeners[index];
2219 if (!el || !cacheItem) {
2223 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2225 delete listeners[index][this.WFN];
2226 delete listeners[index][this.FN];
2227 listeners.splice(index, 1);
2234 getTarget: function(ev, resolveTextNode) {
2235 ev = ev.browserEvent || ev;
2236 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2237 var t = ev.target || ev.srcElement;
2238 return this.resolveTextNode(t);
2242 resolveTextNode: function(node) {
2243 if (Roo.isSafari && node && 3 == node.nodeType) {
2244 return node.parentNode;
2251 getPageX: function(ev) {
2252 ev = ev.browserEvent || ev;
2253 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2255 if (!x && 0 !== x) {
2256 x = ev.clientX || 0;
2259 x += this.getScroll()[1];
2267 getPageY: function(ev) {
2268 ev = ev.browserEvent || ev;
2269 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2271 if (!y && 0 !== y) {
2272 y = ev.clientY || 0;
2275 y += this.getScroll()[0];
2284 getXY: function(ev) {
2285 ev = ev.browserEvent || ev;
2286 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2287 return [this.getPageX(ev), this.getPageY(ev)];
2291 getRelatedTarget: function(ev) {
2292 ev = ev.browserEvent || ev;
2293 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2294 var t = ev.relatedTarget;
2296 if (ev.type == "mouseout") {
2298 } else if (ev.type == "mouseover") {
2303 return this.resolveTextNode(t);
2307 getTime: function(ev) {
2308 ev = ev.browserEvent || ev;
2309 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2311 var t = new Date().getTime();
2315 this.lastError = ex;
2324 stopEvent: function(ev) {
2325 this.stopPropagation(ev);
2326 this.preventDefault(ev);
2330 stopPropagation: function(ev) {
2331 ev = ev.browserEvent || ev;
2332 if (ev.stopPropagation) {
2333 ev.stopPropagation();
2335 ev.cancelBubble = true;
2340 preventDefault: function(ev) {
2341 ev = ev.browserEvent || ev;
2342 if(ev.preventDefault) {
2343 ev.preventDefault();
2345 ev.returnValue = false;
2350 getEvent: function(e) {
2351 var ev = e || window.event;
2353 var c = this.getEvent.caller;
2355 ev = c.arguments[0];
2356 if (ev && Event == ev.constructor) {
2366 getCharCode: function(ev) {
2367 ev = ev.browserEvent || ev;
2368 return ev.charCode || ev.keyCode || 0;
2372 _getCacheIndex: function(el, eventName, fn) {
2373 for (var i = 0,len = listeners.length; i < len; ++i) {
2374 var li = listeners[i];
2376 li[this.FN] == fn &&
2377 li[this.EL] == el &&
2378 li[this.TYPE] == eventName) {
2390 getEl: function(id) {
2391 return document.getElementById(id);
2395 clearCache: function() {
2399 _load: function(e) {
2400 loadComplete = true;
2401 var EU = Roo.lib.Event;
2405 EU.doRemove(window, "load", EU._load);
2410 _tryPreloadAttach: function() {
2419 var tryAgain = !loadComplete;
2421 tryAgain = (retryCount > 0);
2426 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2427 var item = onAvailStack[i];
2429 var el = this.getEl(item.id);
2432 if (!item.checkReady ||
2435 (document && document.body)) {
2438 if (item.override) {
2439 if (item.override === true) {
2442 scope = item.override;
2445 item.fn.call(scope, item.obj);
2446 onAvailStack[i] = null;
2449 notAvail.push(item);
2454 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2458 this.startInterval();
2460 clearInterval(this._interval);
2461 this._interval = null;
2464 this.locked = false;
2471 purgeElement: function(el, recurse, eventName) {
2472 var elListeners = this.getListeners(el, eventName);
2474 for (var i = 0,len = elListeners.length; i < len; ++i) {
2475 var l = elListeners[i];
2476 this.removeListener(el, l.type, l.fn);
2480 if (recurse && el && el.childNodes) {
2481 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2482 this.purgeElement(el.childNodes[i], recurse, eventName);
2488 getListeners: function(el, eventName) {
2489 var results = [], searchLists;
2491 searchLists = [listeners, unloadListeners];
2492 } else if (eventName == "unload") {
2493 searchLists = [unloadListeners];
2495 searchLists = [listeners];
2498 for (var j = 0; j < searchLists.length; ++j) {
2499 var searchList = searchLists[j];
2500 if (searchList && searchList.length > 0) {
2501 for (var i = 0,len = searchList.length; i < len; ++i) {
2502 var l = searchList[i];
2503 if (l && l[this.EL] === el &&
2504 (!eventName || eventName === l[this.TYPE])) {
2509 adjust: l[this.ADJ_SCOPE],
2517 return (results.length) ? results : null;
2521 _unload: function(e) {
2523 var EU = Roo.lib.Event, i, j, l, len, index;
2525 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2526 l = unloadListeners[i];
2529 if (l[EU.ADJ_SCOPE]) {
2530 if (l[EU.ADJ_SCOPE] === true) {
2533 scope = l[EU.ADJ_SCOPE];
2536 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2537 unloadListeners[i] = null;
2543 unloadListeners = null;
2545 if (listeners && listeners.length > 0) {
2546 j = listeners.length;
2549 l = listeners[index];
2551 EU.removeListener(l[EU.EL], l[EU.TYPE],
2561 EU.doRemove(window, "unload", EU._unload);
2566 getScroll: function() {
2567 var dd = document.documentElement, db = document.body;
2568 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2569 return [dd.scrollTop, dd.scrollLeft];
2571 return [db.scrollTop, db.scrollLeft];
2578 doAdd: function () {
2579 if (window.addEventListener) {
2580 return function(el, eventName, fn, capture) {
2581 el.addEventListener(eventName, fn, (capture));
2583 } else if (window.attachEvent) {
2584 return function(el, eventName, fn, capture) {
2585 el.attachEvent("on" + eventName, fn);
2594 doRemove: function() {
2595 if (window.removeEventListener) {
2596 return function (el, eventName, fn, capture) {
2597 el.removeEventListener(eventName, fn, (capture));
2599 } else if (window.detachEvent) {
2600 return function (el, eventName, fn) {
2601 el.detachEvent("on" + eventName, fn);
2613 var E = Roo.lib.Event;
2614 E.on = E.addListener;
2615 E.un = E.removeListener;
2617 if (document && document.body) {
2620 E.doAdd(window, "load", E._load);
2622 E.doAdd(window, "unload", E._unload);
2623 E._tryPreloadAttach();
2630 * @class Roo.lib.Ajax
2632 * provide a simple Ajax request utility functions
2634 * Portions of this file are based on pieces of Yahoo User Interface Library
2635 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2636 * YUI licensed under the BSD License:
2637 * http://developer.yahoo.net/yui/license.txt
2638 * <script type="text/javascript">
2646 request : function(method, uri, cb, data, options) {
2648 var hs = options.headers;
2651 if(hs.hasOwnProperty(h)){
2652 this.initHeader(h, hs[h], false);
2656 if(options.xmlData){
2657 this.initHeader('Content-Type', 'text/xml', false);
2659 data = options.xmlData;
2663 return this.asyncRequest(method, uri, cb, data);
2669 * @param {DomForm} form element
2670 * @return {String} urlencode form output.
2672 serializeForm : function(form) {
2673 if(typeof form == 'string') {
2674 form = (document.getElementById(form) || document.forms[form]);
2677 var el, name, val, disabled, data = '', hasSubmit = false;
2678 for (var i = 0; i < form.elements.length; i++) {
2679 el = form.elements[i];
2680 disabled = form.elements[i].disabled;
2681 name = form.elements[i].name;
2682 val = form.elements[i].value;
2684 if (!disabled && name){
2688 case 'select-multiple':
2689 for (var j = 0; j < el.options.length; j++) {
2690 if (el.options[j].selected) {
2692 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2695 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2703 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2716 if(hasSubmit == false) {
2717 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2722 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2727 data = data.substr(0, data.length - 1);
2735 useDefaultHeader:true,
2737 defaultPostHeader:'application/x-www-form-urlencoded',
2739 useDefaultXhrHeader:true,
2741 defaultXhrHeader:'XMLHttpRequest',
2743 hasDefaultHeaders:true,
2755 setProgId:function(id)
2757 this.activeX.unshift(id);
2760 setDefaultPostHeader:function(b)
2762 this.useDefaultHeader = b;
2765 setDefaultXhrHeader:function(b)
2767 this.useDefaultXhrHeader = b;
2770 setPollingInterval:function(i)
2772 if (typeof i == 'number' && isFinite(i)) {
2773 this.pollInterval = i;
2777 createXhrObject:function(transactionId)
2783 http = new XMLHttpRequest();
2785 obj = { conn:http, tId:transactionId };
2789 for (var i = 0; i < this.activeX.length; ++i) {
2793 http = new ActiveXObject(this.activeX[i]);
2795 obj = { conn:http, tId:transactionId };
2808 getConnectionObject:function()
2811 var tId = this.transactionId;
2815 o = this.createXhrObject(tId);
2817 this.transactionId++;
2828 asyncRequest:function(method, uri, callback, postData)
2830 var o = this.getConnectionObject();
2836 o.conn.open(method, uri, true);
2838 if (this.useDefaultXhrHeader) {
2839 if (!this.defaultHeaders['X-Requested-With']) {
2840 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2844 if(postData && this.useDefaultHeader){
2845 this.initHeader('Content-Type', this.defaultPostHeader);
2848 if (this.hasDefaultHeaders || this.hasHeaders) {
2852 this.handleReadyState(o, callback);
2853 o.conn.send(postData || null);
2859 handleReadyState:function(o, callback)
2863 if (callback && callback.timeout) {
2865 this.timeout[o.tId] = window.setTimeout(function() {
2866 oConn.abort(o, callback, true);
2867 }, callback.timeout);
2870 this.poll[o.tId] = window.setInterval(
2872 if (o.conn && o.conn.readyState == 4) {
2873 window.clearInterval(oConn.poll[o.tId]);
2874 delete oConn.poll[o.tId];
2876 if(callback && callback.timeout) {
2877 window.clearTimeout(oConn.timeout[o.tId]);
2878 delete oConn.timeout[o.tId];
2881 oConn.handleTransactionResponse(o, callback);
2884 , this.pollInterval);
2887 handleTransactionResponse:function(o, callback, isAbort)
2891 this.releaseObject(o);
2895 var httpStatus, responseObject;
2899 if (o.conn.status !== undefined && o.conn.status != 0) {
2900 httpStatus = o.conn.status;
2912 if (httpStatus >= 200 && httpStatus < 300) {
2913 responseObject = this.createResponseObject(o, callback.argument);
2914 if (callback.success) {
2915 if (!callback.scope) {
2916 callback.success(responseObject);
2921 callback.success.apply(callback.scope, [responseObject]);
2926 switch (httpStatus) {
2934 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2935 if (callback.failure) {
2936 if (!callback.scope) {
2937 callback.failure(responseObject);
2940 callback.failure.apply(callback.scope, [responseObject]);
2945 responseObject = this.createResponseObject(o, callback.argument);
2946 if (callback.failure) {
2947 if (!callback.scope) {
2948 callback.failure(responseObject);
2951 callback.failure.apply(callback.scope, [responseObject]);
2957 this.releaseObject(o);
2958 responseObject = null;
2961 createResponseObject:function(o, callbackArg)
2968 var headerStr = o.conn.getAllResponseHeaders();
2969 var header = headerStr.split('\n');
2970 for (var i = 0; i < header.length; i++) {
2971 var delimitPos = header[i].indexOf(':');
2972 if (delimitPos != -1) {
2973 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2981 obj.status = o.conn.status;
2982 obj.statusText = o.conn.statusText;
2983 obj.getResponseHeader = headerObj;
2984 obj.getAllResponseHeaders = headerStr;
2985 obj.responseText = o.conn.responseText;
2986 obj.responseXML = o.conn.responseXML;
2988 if (typeof callbackArg !== undefined) {
2989 obj.argument = callbackArg;
2995 createExceptionObject:function(tId, callbackArg, isAbort)
2998 var COMM_ERROR = 'communication failure';
2999 var ABORT_CODE = -1;
3000 var ABORT_ERROR = 'transaction aborted';
3006 obj.status = ABORT_CODE;
3007 obj.statusText = ABORT_ERROR;
3010 obj.status = COMM_CODE;
3011 obj.statusText = COMM_ERROR;
3015 obj.argument = callbackArg;
3021 initHeader:function(label, value, isDefault)
3023 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
3025 if (headerObj[label] === undefined) {
3026 headerObj[label] = value;
3031 headerObj[label] = value + "," + headerObj[label];
3035 this.hasDefaultHeaders = true;
3038 this.hasHeaders = true;
3043 setHeader:function(o)
3045 if (this.hasDefaultHeaders) {
3046 for (var prop in this.defaultHeaders) {
3047 if (this.defaultHeaders.hasOwnProperty(prop)) {
3048 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3053 if (this.hasHeaders) {
3054 for (var prop in this.headers) {
3055 if (this.headers.hasOwnProperty(prop)) {
3056 o.conn.setRequestHeader(prop, this.headers[prop]);
3060 this.hasHeaders = false;
3064 resetDefaultHeaders:function() {
3065 delete this.defaultHeaders;
3066 this.defaultHeaders = {};
3067 this.hasDefaultHeaders = false;
3070 abort:function(o, callback, isTimeout)
3072 if(this.isCallInProgress(o)) {
3074 window.clearInterval(this.poll[o.tId]);
3075 delete this.poll[o.tId];
3077 delete this.timeout[o.tId];
3080 this.handleTransactionResponse(o, callback, true);
3090 isCallInProgress:function(o)
3093 return o.conn.readyState != 4 && o.conn.readyState != 0;
3102 releaseObject:function(o)
3111 'MSXML2.XMLHTTP.3.0',
3119 * Portions of this file are based on pieces of Yahoo User Interface Library
3120 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3121 * YUI licensed under the BSD License:
3122 * http://developer.yahoo.net/yui/license.txt
3123 * <script type="text/javascript">
3127 Roo.lib.Region = function(t, r, b, l) {
3137 Roo.lib.Region.prototype = {
3138 contains : function(region) {
3139 return ( region.left >= this.left &&
3140 region.right <= this.right &&
3141 region.top >= this.top &&
3142 region.bottom <= this.bottom );
3146 getArea : function() {
3147 return ( (this.bottom - this.top) * (this.right - this.left) );
3150 intersect : function(region) {
3151 var t = Math.max(this.top, region.top);
3152 var r = Math.min(this.right, region.right);
3153 var b = Math.min(this.bottom, region.bottom);
3154 var l = Math.max(this.left, region.left);
3156 if (b >= t && r >= l) {
3157 return new Roo.lib.Region(t, r, b, l);
3162 union : function(region) {
3163 var t = Math.min(this.top, region.top);
3164 var r = Math.max(this.right, region.right);
3165 var b = Math.max(this.bottom, region.bottom);
3166 var l = Math.min(this.left, region.left);
3168 return new Roo.lib.Region(t, r, b, l);
3171 adjust : function(t, l, b, r) {
3180 Roo.lib.Region.getRegion = function(el) {
3181 var p = Roo.lib.Dom.getXY(el);
3184 var r = p[0] + el.offsetWidth;
3185 var b = p[1] + el.offsetHeight;
3188 return new Roo.lib.Region(t, r, b, l);
3191 * Portions of this file are based on pieces of Yahoo User Interface Library
3192 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3193 * YUI licensed under the BSD License:
3194 * http://developer.yahoo.net/yui/license.txt
3195 * <script type="text/javascript">
3198 //@@dep Roo.lib.Region
3201 Roo.lib.Point = function(x, y) {
3202 if (x instanceof Array) {
3206 this.x = this.right = this.left = this[0] = x;
3207 this.y = this.top = this.bottom = this[1] = y;
3210 Roo.lib.Point.prototype = new Roo.lib.Region();
3212 * Portions of this file are based on pieces of Yahoo User Interface Library
3213 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3214 * YUI licensed under the BSD License:
3215 * http://developer.yahoo.net/yui/license.txt
3216 * <script type="text/javascript">
3223 scroll : function(el, args, duration, easing, cb, scope) {
3224 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3227 motion : function(el, args, duration, easing, cb, scope) {
3228 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3231 color : function(el, args, duration, easing, cb, scope) {
3232 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3235 run : function(el, args, duration, easing, cb, scope, type) {
3236 type = type || Roo.lib.AnimBase;
3237 if (typeof easing == "string") {
3238 easing = Roo.lib.Easing[easing];
3240 var anim = new type(el, args, duration, easing);
3241 anim.animateX(function() {
3242 Roo.callback(cb, scope);
3248 * Portions of this file are based on pieces of Yahoo User Interface Library
3249 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3250 * YUI licensed under the BSD License:
3251 * http://developer.yahoo.net/yui/license.txt
3252 * <script type="text/javascript">
3260 if (!libFlyweight) {
3261 libFlyweight = new Roo.Element.Flyweight();
3263 libFlyweight.dom = el;
3264 return libFlyweight;
3267 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3271 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3273 this.init(el, attributes, duration, method);
3277 Roo.lib.AnimBase.fly = fly;
3281 Roo.lib.AnimBase.prototype = {
3283 toString: function() {
3284 var el = this.getEl();
3285 var id = el.id || el.tagName;
3286 return ("Anim " + id);
3290 noNegatives: /width|height|opacity|padding/i,
3291 offsetAttribute: /^((width|height)|(top|left))$/,
3292 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3293 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3297 doMethod: function(attr, start, end) {
3298 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3302 setAttribute: function(attr, val, unit) {
3303 if (this.patterns.noNegatives.test(attr)) {
3304 val = (val > 0) ? val : 0;
3307 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3311 getAttribute: function(attr) {
3312 var el = this.getEl();
3313 var val = fly(el).getStyle(attr);
3315 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3316 return parseFloat(val);
3319 var a = this.patterns.offsetAttribute.exec(attr) || [];
3320 var pos = !!( a[3] );
3321 var box = !!( a[2] );
3324 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3325 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3334 getDefaultUnit: function(attr) {
3335 if (this.patterns.defaultUnit.test(attr)) {
3342 animateX : function(callback, scope) {
3343 var f = function() {
3344 this.onComplete.removeListener(f);
3345 if (typeof callback == "function") {
3346 callback.call(scope || this, this);
3349 this.onComplete.addListener(f, this);
3354 setRuntimeAttribute: function(attr) {
3357 var attributes = this.attributes;
3359 this.runtimeAttributes[attr] = {};
3361 var isset = function(prop) {
3362 return (typeof prop !== 'undefined');
3365 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3369 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3372 if (isset(attributes[attr]['to'])) {
3373 end = attributes[attr]['to'];
3374 } else if (isset(attributes[attr]['by'])) {
3375 if (start.constructor == Array) {
3377 for (var i = 0, len = start.length; i < len; ++i) {
3378 end[i] = start[i] + attributes[attr]['by'][i];
3381 end = start + attributes[attr]['by'];
3385 this.runtimeAttributes[attr].start = start;
3386 this.runtimeAttributes[attr].end = end;
3389 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3393 init: function(el, attributes, duration, method) {
3395 var isAnimated = false;
3398 var startTime = null;
3401 var actualFrames = 0;
3404 el = Roo.getDom(el);
3407 this.attributes = attributes || {};
3410 this.duration = duration || 1;
3413 this.method = method || Roo.lib.Easing.easeNone;
3416 this.useSeconds = true;
3419 this.currentFrame = 0;
3422 this.totalFrames = Roo.lib.AnimMgr.fps;
3425 this.getEl = function() {
3430 this.isAnimated = function() {
3435 this.getStartTime = function() {
3439 this.runtimeAttributes = {};
3442 this.animate = function() {
3443 if (this.isAnimated()) {
3447 this.currentFrame = 0;
3449 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3451 Roo.lib.AnimMgr.registerElement(this);
3455 this.stop = function(finish) {
3457 this.currentFrame = this.totalFrames;
3458 this._onTween.fire();
3460 Roo.lib.AnimMgr.stop(this);
3463 var onStart = function() {
3464 this.onStart.fire();
3466 this.runtimeAttributes = {};
3467 for (var attr in this.attributes) {
3468 this.setRuntimeAttribute(attr);
3473 startTime = new Date();
3477 var onTween = function() {
3479 duration: new Date() - this.getStartTime(),
3480 currentFrame: this.currentFrame
3483 data.toString = function() {
3485 'duration: ' + data.duration +
3486 ', currentFrame: ' + data.currentFrame
3490 this.onTween.fire(data);
3492 var runtimeAttributes = this.runtimeAttributes;
3494 for (var attr in runtimeAttributes) {
3495 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3501 var onComplete = function() {
3502 var actual_duration = (new Date() - startTime) / 1000 ;
3505 duration: actual_duration,
3506 frames: actualFrames,
3507 fps: actualFrames / actual_duration
3510 data.toString = function() {
3512 'duration: ' + data.duration +
3513 ', frames: ' + data.frames +
3514 ', fps: ' + data.fps
3520 this.onComplete.fire(data);
3524 this._onStart = new Roo.util.Event(this);
3525 this.onStart = new Roo.util.Event(this);
3526 this.onTween = new Roo.util.Event(this);
3527 this._onTween = new Roo.util.Event(this);
3528 this.onComplete = new Roo.util.Event(this);
3529 this._onComplete = new Roo.util.Event(this);
3530 this._onStart.addListener(onStart);
3531 this._onTween.addListener(onTween);
3532 this._onComplete.addListener(onComplete);
3537 * Portions of this file are based on pieces of Yahoo User Interface Library
3538 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3539 * YUI licensed under the BSD License:
3540 * http://developer.yahoo.net/yui/license.txt
3541 * <script type="text/javascript">
3545 Roo.lib.AnimMgr = new function() {
3562 this.registerElement = function(tween) {
3563 queue[queue.length] = tween;
3565 tween._onStart.fire();
3570 this.unRegister = function(tween, index) {
3571 tween._onComplete.fire();
3572 index = index || getIndex(tween);
3574 queue.splice(index, 1);
3578 if (tweenCount <= 0) {
3584 this.start = function() {
3585 if (thread === null) {
3586 thread = setInterval(this.run, this.delay);
3591 this.stop = function(tween) {
3593 clearInterval(thread);
3595 for (var i = 0, len = queue.length; i < len; ++i) {
3596 if (queue[0].isAnimated()) {
3597 this.unRegister(queue[0], 0);
3606 this.unRegister(tween);
3611 this.run = function() {
3612 for (var i = 0, len = queue.length; i < len; ++i) {
3613 var tween = queue[i];
3614 if (!tween || !tween.isAnimated()) {
3618 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3620 tween.currentFrame += 1;
3622 if (tween.useSeconds) {
3623 correctFrame(tween);
3625 tween._onTween.fire();
3628 Roo.lib.AnimMgr.stop(tween, i);
3633 var getIndex = function(anim) {
3634 for (var i = 0, len = queue.length; i < len; ++i) {
3635 if (queue[i] == anim) {
3643 var correctFrame = function(tween) {
3644 var frames = tween.totalFrames;
3645 var frame = tween.currentFrame;
3646 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3647 var elapsed = (new Date() - tween.getStartTime());
3650 if (elapsed < tween.duration * 1000) {
3651 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3653 tweak = frames - (frame + 1);
3655 if (tweak > 0 && isFinite(tweak)) {
3656 if (tween.currentFrame + tweak >= frames) {
3657 tweak = frames - (frame + 1);
3660 tween.currentFrame += tweak;
3666 * Portions of this file are based on pieces of Yahoo User Interface Library
3667 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3668 * YUI licensed under the BSD License:
3669 * http://developer.yahoo.net/yui/license.txt
3670 * <script type="text/javascript">
3673 Roo.lib.Bezier = new function() {
3675 this.getPosition = function(points, t) {
3676 var n = points.length;
3679 for (var i = 0; i < n; ++i) {
3680 tmp[i] = [points[i][0], points[i][1]];
3683 for (var j = 1; j < n; ++j) {
3684 for (i = 0; i < n - j; ++i) {
3685 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3686 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3690 return [ tmp[0][0], tmp[0][1] ];
3696 * @class Roo.lib.Color
3698 * An abstract Color implementation. Concrete Color implementations should use
3699 * an instance of this function as their prototype, and implement the getRGB and
3700 * getHSL functions. getRGB should return an object representing the RGB
3701 * components of this Color, with the red, green, and blue components in the
3702 * range [0,255] and the alpha component in the range [0,100]. getHSL should
3703 * return an object representing the HSL components of this Color, with the hue
3704 * component in the range [0,360), the saturation and lightness components in
3705 * the range [0,100], and the alpha component in the range [0,1].
3710 * Functions for Color handling and processing.
3712 * http://www.safalra.com/web-design/javascript/Color-handling-and-processing/
3714 * The author of this program, Safalra (Stephen Morley), irrevocably releases all
3715 * rights to this program, with the intention of it becoming part of the public
3716 * domain. Because this program is released into the public domain, it comes with
3717 * no warranty either expressed or implied, to the extent permitted by law.
3719 * For more free and public domain JavaScript code by the same author, visit:
3720 * http://www.safalra.com/web-design/javascript/
3723 Roo.lib.Color = function() { }
3726 Roo.apply(Roo.lib.Color.prototype, {
3734 * @return {Object} an object representing the RGBA components of this Color. The red,
3735 * green, and blue components are converted to integers in the range [0,255].
3736 * The alpha is a value in the range [0,1].
3738 getIntegerRGB : function(){
3740 // get the RGB components of this Color
3741 var rgb = this.getRGB();
3743 // return the integer components
3745 'r' : Math.round(rgb.r),
3746 'g' : Math.round(rgb.g),
3747 'b' : Math.round(rgb.b),
3755 * @return {Object} an object representing the RGBA components of this Color. The red,
3756 * green, and blue components are converted to numbers in the range [0,100].
3757 * The alpha is a value in the range [0,1].
3759 getPercentageRGB : function(){
3761 // get the RGB components of this Color
3762 var rgb = this.getRGB();
3764 // return the percentage components
3766 'r' : 100 * rgb.r / 255,
3767 'g' : 100 * rgb.g / 255,
3768 'b' : 100 * rgb.b / 255,
3775 * getCSSHexadecimalRGB
3776 * @return {String} a string representing this Color as a CSS hexadecimal RGB Color
3777 * value - that is, a string of the form #RRGGBB where each of RR, GG, and BB
3778 * are two-digit hexadecimal numbers.
3780 getCSSHexadecimalRGB : function()
3783 // get the integer RGB components
3784 var rgb = this.getIntegerRGB();
3786 // determine the hexadecimal equivalents
3787 var r16 = rgb.r.toString(16);
3788 var g16 = rgb.g.toString(16);
3789 var b16 = rgb.b.toString(16);
3791 // return the CSS RGB Color value
3793 + (r16.length == 2 ? r16 : '0' + r16)
3794 + (g16.length == 2 ? g16 : '0' + g16)
3795 + (b16.length == 2 ? b16 : '0' + b16);
3801 * @return {String} a string representing this Color as a CSS integer RGB Color
3802 * value - that is, a string of the form rgb(r,g,b) where each of r, g, and b
3803 * are integers in the range [0,255].
3805 getCSSIntegerRGB : function(){
3807 // get the integer RGB components
3808 var rgb = this.getIntegerRGB();
3810 // return the CSS RGB Color value
3811 return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')';
3817 * @return {String} Returns a string representing this Color as a CSS integer RGBA Color
3818 * value - that is, a string of the form rgba(r,g,b,a) where each of r, g, and
3819 * b are integers in the range [0,255] and a is in the range [0,1].
3821 getCSSIntegerRGBA : function(){
3823 // get the integer RGB components
3824 var rgb = this.getIntegerRGB();
3826 // return the CSS integer RGBA Color value
3827 return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + rgb.a + ')';
3832 * getCSSPercentageRGB
3833 * @return {String} a string representing this Color as a CSS percentage RGB Color
3834 * value - that is, a string of the form rgb(r%,g%,b%) where each of r, g, and
3835 * b are in the range [0,100].
3837 getCSSPercentageRGB : function(){
3839 // get the percentage RGB components
3840 var rgb = this.getPercentageRGB();
3842 // return the CSS RGB Color value
3843 return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%)';
3848 * getCSSPercentageRGBA
3849 * @return {String} a string representing this Color as a CSS percentage RGBA Color
3850 * value - that is, a string of the form rgba(r%,g%,b%,a) where each of r, g,
3851 * and b are in the range [0,100] and a is in the range [0,1].
3853 getCSSPercentageRGBA : function(){
3855 // get the percentage RGB components
3856 var rgb = this.getPercentageRGB();
3858 // return the CSS percentage RGBA Color value
3859 return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%,' + rgb.a + ')';
3865 * @return {String} a string representing this Color as a CSS HSL Color value - that
3866 * is, a string of the form hsl(h,s%,l%) where h is in the range [0,100] and
3867 * s and l are in the range [0,100].
3869 getCSSHSL : function(){
3871 // get the HSL components
3872 var hsl = this.getHSL();
3874 // return the CSS HSL Color value
3875 return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%)';
3881 * @return {String} a string representing this Color as a CSS HSLA Color value - that
3882 * is, a string of the form hsla(h,s%,l%,a) where h is in the range [0,100],
3883 * s and l are in the range [0,100], and a is in the range [0,1].
3885 getCSSHSLA : function(){
3887 // get the HSL components
3888 var hsl = this.getHSL();
3890 // return the CSS HSL Color value
3891 return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%,' + hsl.a + ')';
3896 * Sets the Color of the specified node to this Color. This functions sets
3897 * the CSS 'color' property for the node. The parameter is:
3899 * @param {DomElement} node - the node whose Color should be set
3901 setNodeColor : function(node){
3903 // set the Color of the node
3904 node.style.color = this.getCSSHexadecimalRGB();
3909 * Sets the background Color of the specified node to this Color. This
3910 * functions sets the CSS 'background-color' property for the node. The
3913 * @param {DomElement} node - the node whose background Color should be set
3915 setNodeBackgroundColor : function(node){
3917 // set the background Color of the node
3918 node.style.backgroundColor = this.getCSSHexadecimalRGB();
3921 // convert between formats..
3924 var r = this.getIntegerRGB();
3925 return new Roo.lib.RGBColor(r.r,r.g,r.b,r.a);
3930 var hsl = this.getHSL();
3931 // return the CSS HSL Color value
3932 return new Roo.lib.HSLColor(hsl.h, hsl.s, hsl.l , hsl.a );
3938 var rgb = this.toRGB();
3939 var hsv = rgb.getHSV();
3940 // return the CSS HSL Color value
3941 return new Roo.lib.HSVColor(hsv.h, hsv.s, hsv.v , hsv.a );
3945 // modify v = 0 ... 1 (eg. 0.5)
3946 saturate : function(v)
3948 var rgb = this.toRGB();
3949 var hsv = rgb.getHSV();
3950 return new Roo.lib.HSVColor(hsv.h, hsv.s * v, hsv.v , hsv.a );
3958 * @return {Object} the RGB and alpha components of this Color as an object with r,
3959 * g, b, and a properties. r, g, and b are in the range [0,255] and a is in
3964 // return the RGB components
3976 * @return {Object} the HSV and alpha components of this Color as an object with h,
3977 * s, v, and a properties. h is in the range [0,360), s and v are in the range
3978 * [0,100], and a is in the range [0,1].
3983 // calculate the HSV components if necessary
3984 if (this.hsv == null) {
3985 this.calculateHSV();
3988 // return the HSV components
4000 * @return {Object} the HSL and alpha components of this Color as an object with h,
4001 * s, l, and a properties. h is in the range [0,360), s and l are in the range
4002 * [0,100], and a is in the range [0,1].
4004 getHSL : function(){
4007 // calculate the HSV components if necessary
4008 if (this.hsl == null) { this.calculateHSL(); }
4010 // return the HSL components
4025 * @class Roo.lib.RGBColor
4026 * @extends Roo.lib.Color
4027 * Creates a Color specified in the RGB Color space, with an optional alpha
4028 * component. The parameters are:
4032 * @param {Number} r - the red component, clipped to the range [0,255]
4033 * @param {Number} g - the green component, clipped to the range [0,255]
4034 * @param {Number} b - the blue component, clipped to the range [0,255]
4035 * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4036 * optional and defaults to 1
4038 Roo.lib.RGBColor = function (r, g, b, a){
4040 // store the alpha component after clipping it if necessary
4041 this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4043 // store the RGB components after clipping them if necessary
4046 'r' : Math.max(0, Math.min(255, r)),
4047 'g' : Math.max(0, Math.min(255, g)),
4048 'b' : Math.max(0, Math.min(255, b))
4051 // initialise the HSV and HSL components to null
4055 * //private returns the HSV or HSL hue component of this RGBColor. The hue is in the
4056 * range [0,360). The parameters are:
4058 * maximum - the maximum of the RGB component values
4059 * range - the range of the RGB component values
4064 // this does an 'exteds'
4065 Roo.extend(Roo.lib.RGBColor, Roo.lib.Color, {
4068 getHue : function(maximum, range)
4072 // check whether the range is zero
4075 // set the hue to zero (any hue is acceptable as the Color is grey)
4080 // determine which of the components has the highest value and set the hue
4083 // red has the highest value
4085 var hue = (rgb.g - rgb.b) / range * 60;
4086 if (hue < 0) { hue += 360; }
4089 // green has the highest value
4091 var hue = (rgb.b - rgb.r) / range * 60 + 120;
4094 // blue has the highest value
4096 var hue = (rgb.r - rgb.g) / range * 60 + 240;
4108 /* //private Calculates and stores the HSV components of this RGBColor so that they can
4109 * be returned be the getHSV function.
4111 calculateHSV : function(){
4113 // get the maximum and range of the RGB component values
4114 var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4115 var range = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4117 // store the HSV components
4120 'h' : this.getHue(maximum, range),
4121 's' : (maximum == 0 ? 0 : 100 * range / maximum),
4122 'v' : maximum / 2.55
4127 /* //private Calculates and stores the HSL components of this RGBColor so that they can
4128 * be returned be the getHSL function.
4130 calculateHSL : function(){
4132 // get the maximum and range of the RGB component values
4133 var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4134 var range = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4136 // determine the lightness in the range [0,1]
4137 var l = maximum / 255 - range / 510;
4139 // store the HSL components
4142 'h' : this.getHue(maximum, range),
4143 's' : (range == 0 ? 0 : range / 2.55 / (l < 0.5 ? l * 2 : 2 - l * 2)),
4152 * @class Roo.lib.HSVColor
4153 * @extends Roo.lib.Color
4154 * Creates a Color specified in the HSV Color space, with an optional alpha
4155 * component. The parameters are:
4158 * @param {Number} h - the hue component, wrapped to the range [0,360)
4159 * @param {Number} s - the saturation component, clipped to the range [0,100]
4160 * @param {Number} v - the value component, clipped to the range [0,100]
4161 * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4162 * optional and defaults to 1
4164 Roo.lib.HSVColor = function (h, s, v, a){
4166 // store the alpha component after clipping it if necessary
4167 this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4169 // store the HSV components after clipping or wrapping them if necessary
4172 'h' : (h % 360 + 360) % 360,
4173 's' : Math.max(0, Math.min(100, s)),
4174 'v' : Math.max(0, Math.min(100, v))
4177 // initialise the RGB and HSL components to null
4182 Roo.extend(Roo.lib.HSVColor, Roo.lib.Color, {
4183 /* Calculates and stores the RGB components of this HSVColor so that they can
4184 * be returned be the getRGB function.
4186 calculateRGB: function ()
4189 // check whether the saturation is zero
4192 // set the Color to the appropriate shade of grey
4199 // set some temporary values
4200 var f = hsv.h / 60 - Math.floor(hsv.h / 60);
4201 var p = hsv.v * (1 - hsv.s / 100);
4202 var q = hsv.v * (1 - hsv.s / 100 * f);
4203 var t = hsv.v * (1 - hsv.s / 100 * (1 - f));
4205 // set the RGB Color components to their temporary values
4206 switch (Math.floor(hsv.h / 60)){
4207 case 0: var r = hsv.v; var g = t; var b = p; break;
4208 case 1: var r = q; var g = hsv.v; var b = p; break;
4209 case 2: var r = p; var g = hsv.v; var b = t; break;
4210 case 3: var r = p; var g = q; var b = hsv.v; break;
4211 case 4: var r = t; var g = p; var b = hsv.v; break;
4212 case 5: var r = hsv.v; var g = p; var b = q; break;
4217 // store the RGB components
4227 /* Calculates and stores the HSL components of this HSVColor so that they can
4228 * be returned be the getHSL function.
4230 calculateHSL : function (){
4233 // determine the lightness in the range [0,100]
4234 var l = (2 - hsv.s / 100) * hsv.v / 2;
4236 // store the HSL components
4240 's' : hsv.s * hsv.v / (l < 50 ? l * 2 : 200 - l * 2),
4244 // correct a division-by-zero error
4245 if (isNaN(hsl.s)) { hsl.s = 0; }
4254 * @class Roo.lib.HSLColor
4255 * @extends Roo.lib.Color
4258 * Creates a Color specified in the HSL Color space, with an optional alpha
4259 * component. The parameters are:
4261 * @param {Number} h - the hue component, wrapped to the range [0,360)
4262 * @param {Number} s - the saturation component, clipped to the range [0,100]
4263 * @param {Number} l - the lightness component, clipped to the range [0,100]
4264 * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4265 * optional and defaults to 1
4268 Roo.lib.HSLColor = function(h, s, l, a){
4270 // store the alpha component after clipping it if necessary
4271 this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4273 // store the HSL components after clipping or wrapping them if necessary
4276 'h' : (h % 360 + 360) % 360,
4277 's' : Math.max(0, Math.min(100, s)),
4278 'l' : Math.max(0, Math.min(100, l))
4281 // initialise the RGB and HSV components to null
4284 Roo.extend(Roo.lib.HSLColor, Roo.lib.Color, {
4286 /* Calculates and stores the RGB components of this HSLColor so that they can
4287 * be returned be the getRGB function.
4289 calculateRGB: function (){
4291 // check whether the saturation is zero
4292 if (this.hsl.s == 0){
4294 // store the RGB components representing the appropriate shade of grey
4297 'r' : this.hsl.l * 2.55,
4298 'g' : this.hsl.l * 2.55,
4299 'b' : this.hsl.l * 2.55
4304 // set some temporary values
4305 var p = this.hsl.l < 50
4306 ? this.hsl.l * (1 + hsl.s / 100)
4307 : this.hsl.l + hsl.s - hsl.l * hsl.s / 100;
4308 var q = 2 * hsl.l - p;
4310 // initialise the RGB components
4313 'r' : (h + 120) / 60 % 6,
4315 'b' : (h + 240) / 60 % 6
4318 // loop over the RGB components
4319 for (var key in this.rgb){
4321 // ensure that the property is not inherited from the root object
4322 if (this.rgb.hasOwnProperty(key)){
4324 // set the component to its value in the range [0,100]
4325 if (this.rgb[key] < 1){
4326 this.rgb[key] = q + (p - q) * this.rgb[key];
4327 }else if (this.rgb[key] < 3){
4329 }else if (this.rgb[key] < 4){
4330 this.rgb[key] = q + (p - q) * (4 - this.rgb[key]);
4335 // set the component to its value in the range [0,255]
4336 this.rgb[key] *= 2.55;
4346 /* Calculates and stores the HSV components of this HSLColor so that they can
4347 * be returned be the getHSL function.
4349 calculateHSV : function(){
4351 // set a temporary value
4352 var t = this.hsl.s * (this.hsl.l < 50 ? this.hsl.l : 100 - this.hsl.l) / 100;
4354 // store the HSV components
4358 's' : 200 * t / (this.hsl.l + t),
4359 'v' : t + this.hsl.l
4362 // correct a division-by-zero error
4363 if (isNaN(this.hsv.s)) { this.hsv.s = 0; }
4370 * Portions of this file are based on pieces of Yahoo User Interface Library
4371 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4372 * YUI licensed under the BSD License:
4373 * http://developer.yahoo.net/yui/license.txt
4374 * <script type="text/javascript">
4379 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
4380 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
4383 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
4385 var fly = Roo.lib.AnimBase.fly;
4387 var superclass = Y.ColorAnim.superclass;
4388 var proto = Y.ColorAnim.prototype;
4390 proto.toString = function() {
4391 var el = this.getEl();
4392 var id = el.id || el.tagName;
4393 return ("ColorAnim " + id);
4396 proto.patterns.color = /color$/i;
4397 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
4398 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
4399 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
4400 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
4403 proto.parseColor = function(s) {
4404 if (s.length == 3) {
4408 var c = this.patterns.hex.exec(s);
4409 if (c && c.length == 4) {
4410 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
4413 c = this.patterns.rgb.exec(s);
4414 if (c && c.length == 4) {
4415 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
4418 c = this.patterns.hex3.exec(s);
4419 if (c && c.length == 4) {
4420 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
4425 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
4426 proto.getAttribute = function(attr) {
4427 var el = this.getEl();
4428 if (this.patterns.color.test(attr)) {
4429 var val = fly(el).getStyle(attr);
4431 if (this.patterns.transparent.test(val)) {
4432 var parent = el.parentNode;
4433 val = fly(parent).getStyle(attr);
4435 while (parent && this.patterns.transparent.test(val)) {
4436 parent = parent.parentNode;
4437 val = fly(parent).getStyle(attr);
4438 if (parent.tagName.toUpperCase() == 'HTML') {
4444 val = superclass.getAttribute.call(this, attr);
4449 proto.getAttribute = function(attr) {
4450 var el = this.getEl();
4451 if (this.patterns.color.test(attr)) {
4452 var val = fly(el).getStyle(attr);
4454 if (this.patterns.transparent.test(val)) {
4455 var parent = el.parentNode;
4456 val = fly(parent).getStyle(attr);
4458 while (parent && this.patterns.transparent.test(val)) {
4459 parent = parent.parentNode;
4460 val = fly(parent).getStyle(attr);
4461 if (parent.tagName.toUpperCase() == 'HTML') {
4467 val = superclass.getAttribute.call(this, attr);
4473 proto.doMethod = function(attr, start, end) {
4476 if (this.patterns.color.test(attr)) {
4478 for (var i = 0, len = start.length; i < len; ++i) {
4479 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
4482 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
4485 val = superclass.doMethod.call(this, attr, start, end);
4491 proto.setRuntimeAttribute = function(attr) {
4492 superclass.setRuntimeAttribute.call(this, attr);
4494 if (this.patterns.color.test(attr)) {
4495 var attributes = this.attributes;
4496 var start = this.parseColor(this.runtimeAttributes[attr].start);
4497 var end = this.parseColor(this.runtimeAttributes[attr].end);
4499 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
4500 end = this.parseColor(attributes[attr].by);
4502 for (var i = 0, len = start.length; i < len; ++i) {
4503 end[i] = start[i] + end[i];
4507 this.runtimeAttributes[attr].start = start;
4508 this.runtimeAttributes[attr].end = end;
4514 * Portions of this file are based on pieces of Yahoo User Interface Library
4515 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4516 * YUI licensed under the BSD License:
4517 * http://developer.yahoo.net/yui/license.txt
4518 * <script type="text/javascript">
4524 easeNone: function (t, b, c, d) {
4525 return c * t / d + b;
4529 easeIn: function (t, b, c, d) {
4530 return c * (t /= d) * t + b;
4534 easeOut: function (t, b, c, d) {
4535 return -c * (t /= d) * (t - 2) + b;
4539 easeBoth: function (t, b, c, d) {
4540 if ((t /= d / 2) < 1) {
4541 return c / 2 * t * t + b;
4544 return -c / 2 * ((--t) * (t - 2) - 1) + b;
4548 easeInStrong: function (t, b, c, d) {
4549 return c * (t /= d) * t * t * t + b;
4553 easeOutStrong: function (t, b, c, d) {
4554 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
4558 easeBothStrong: function (t, b, c, d) {
4559 if ((t /= d / 2) < 1) {
4560 return c / 2 * t * t * t * t + b;
4563 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
4568 elasticIn: function (t, b, c, d, a, p) {
4572 if ((t /= d) == 1) {
4579 if (!a || a < Math.abs(c)) {
4584 var s = p / (2 * Math.PI) * Math.asin(c / a);
4587 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4591 elasticOut: function (t, b, c, d, a, p) {
4595 if ((t /= d) == 1) {
4602 if (!a || a < Math.abs(c)) {
4607 var s = p / (2 * Math.PI) * Math.asin(c / a);
4610 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
4614 elasticBoth: function (t, b, c, d, a, p) {
4619 if ((t /= d / 2) == 2) {
4627 if (!a || a < Math.abs(c)) {
4632 var s = p / (2 * Math.PI) * Math.asin(c / a);
4636 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
4637 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4639 return a * Math.pow(2, -10 * (t -= 1)) *
4640 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
4645 backIn: function (t, b, c, d, s) {
4646 if (typeof s == 'undefined') {
4649 return c * (t /= d) * t * ((s + 1) * t - s) + b;
4653 backOut: function (t, b, c, d, s) {
4654 if (typeof s == 'undefined') {
4657 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
4661 backBoth: function (t, b, c, d, s) {
4662 if (typeof s == 'undefined') {
4666 if ((t /= d / 2 ) < 1) {
4667 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
4669 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
4673 bounceIn: function (t, b, c, d) {
4674 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
4678 bounceOut: function (t, b, c, d) {
4679 if ((t /= d) < (1 / 2.75)) {
4680 return c * (7.5625 * t * t) + b;
4681 } else if (t < (2 / 2.75)) {
4682 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
4683 } else if (t < (2.5 / 2.75)) {
4684 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
4686 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
4690 bounceBoth: function (t, b, c, d) {
4692 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
4694 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
4697 * Portions of this file are based on pieces of Yahoo User Interface Library
4698 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4699 * YUI licensed under the BSD License:
4700 * http://developer.yahoo.net/yui/license.txt
4701 * <script type="text/javascript">
4705 Roo.lib.Motion = function(el, attributes, duration, method) {
4707 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
4711 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
4715 var superclass = Y.Motion.superclass;
4716 var proto = Y.Motion.prototype;
4718 proto.toString = function() {
4719 var el = this.getEl();
4720 var id = el.id || el.tagName;
4721 return ("Motion " + id);
4724 proto.patterns.points = /^points$/i;
4726 proto.setAttribute = function(attr, val, unit) {
4727 if (this.patterns.points.test(attr)) {
4728 unit = unit || 'px';
4729 superclass.setAttribute.call(this, 'left', val[0], unit);
4730 superclass.setAttribute.call(this, 'top', val[1], unit);
4732 superclass.setAttribute.call(this, attr, val, unit);
4736 proto.getAttribute = function(attr) {
4737 if (this.patterns.points.test(attr)) {
4739 superclass.getAttribute.call(this, 'left'),
4740 superclass.getAttribute.call(this, 'top')
4743 val = superclass.getAttribute.call(this, attr);
4749 proto.doMethod = function(attr, start, end) {
4752 if (this.patterns.points.test(attr)) {
4753 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4754 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4756 val = superclass.doMethod.call(this, attr, start, end);
4761 proto.setRuntimeAttribute = function(attr) {
4762 if (this.patterns.points.test(attr)) {
4763 var el = this.getEl();
4764 var attributes = this.attributes;
4766 var control = attributes['points']['control'] || [];
4770 if (control.length > 0 && !(control[0] instanceof Array)) {
4771 control = [control];
4774 for (i = 0,len = control.length; i < len; ++i) {
4775 tmp[i] = control[i];
4780 Roo.fly(el).position();
4782 if (isset(attributes['points']['from'])) {
4783 Roo.lib.Dom.setXY(el, attributes['points']['from']);
4786 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4789 start = this.getAttribute('points');
4792 if (isset(attributes['points']['to'])) {
4793 end = translateValues.call(this, attributes['points']['to'], start);
4795 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4796 for (i = 0,len = control.length; i < len; ++i) {
4797 control[i] = translateValues.call(this, control[i], start);
4801 } else if (isset(attributes['points']['by'])) {
4802 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4804 for (i = 0,len = control.length; i < len; ++i) {
4805 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4809 this.runtimeAttributes[attr] = [start];
4811 if (control.length > 0) {
4812 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4815 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4818 superclass.setRuntimeAttribute.call(this, attr);
4822 var translateValues = function(val, start) {
4823 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4824 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4829 var isset = function(prop) {
4830 return (typeof prop !== 'undefined');
4834 * Portions of this file are based on pieces of Yahoo User Interface Library
4835 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4836 * YUI licensed under the BSD License:
4837 * http://developer.yahoo.net/yui/license.txt
4838 * <script type="text/javascript">
4842 Roo.lib.Scroll = function(el, attributes, duration, method) {
4844 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4848 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4852 var superclass = Y.Scroll.superclass;
4853 var proto = Y.Scroll.prototype;
4855 proto.toString = function() {
4856 var el = this.getEl();
4857 var id = el.id || el.tagName;
4858 return ("Scroll " + id);
4861 proto.doMethod = function(attr, start, end) {
4864 if (attr == 'scroll') {
4866 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4867 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4871 val = superclass.doMethod.call(this, attr, start, end);
4876 proto.getAttribute = function(attr) {
4878 var el = this.getEl();
4880 if (attr == 'scroll') {
4881 val = [ el.scrollLeft, el.scrollTop ];
4883 val = superclass.getAttribute.call(this, attr);
4889 proto.setAttribute = function(attr, val, unit) {
4890 var el = this.getEl();
4892 if (attr == 'scroll') {
4893 el.scrollLeft = val[0];
4894 el.scrollTop = val[1];
4896 superclass.setAttribute.call(this, attr, val, unit);
4901 * Originally based of this code... - refactored for Roo...
4902 * https://github.com/aaalsaleh/undo-manager
4905 * @author Abdulrahman Alsaleh
4906 * @copyright 2015 Abdulrahman Alsaleh
4907 * @license MIT License (c)
4909 * Hackily modifyed by alan@roojs.com
4914 * TOTALLY UNTESTED...
4916 * Documentation to be done....
4921 * @class Roo.lib.UndoManager
4922 * An undo manager implementation in JavaScript. It follows the W3C UndoManager and DOM Transaction
4923 * Draft and the undocumented and disabled Mozilla Firefox's UndoManager implementation.
4929 editor.undoManager = new Roo.lib.UndoManager(1000, editor);
4933 * For more information see this blog post with examples:
4934 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4935 - Create Elements using DOM, HTML fragments and Templates</a>.
4937 * @param {Number} limit how far back to go ... use 1000?
4938 * @param {Object} scope usually use document..
4941 Roo.lib.UndoManager = function (limit, undoScopeHost)
4945 this.scope = undoScopeHost;
4946 this.fireEvent = typeof CustomEvent != 'undefined' && undoScopeHost && undoScopeHost.dispatchEvent;
4947 if (this.fireEvent) {
4954 Roo.lib.UndoManager.prototype = {
4965 * To push and execute a transaction, the method undoManager.transact
4966 * must be called by passing a transaction object as the first argument, and a merge
4967 * flag as the second argument. A transaction object has the following properties:
4971 undoManager.transact({
4973 execute: function() { ... },
4974 undo: function() { ... },
4975 // redo same as execute
4976 redo: function() { this.execute(); }
4979 // merge transaction
4980 undoManager.transact({
4982 execute: function() { ... }, // this will be run...
4983 undo: function() { ... }, // what to do when undo is run.
4984 // redo same as execute
4985 redo: function() { this.execute(); }
4990 * @param {Object} transaction The transaction to add to the stack.
4991 * @return {String} The HTML fragment
4995 transact : function (transaction, merge)
4997 if (arguments.length < 2) {
4998 throw new TypeError('Not enough arguments to UndoManager.transact.');
5001 transaction.execute();
5003 this.stack.splice(0, this.position);
5004 if (merge && this.length) {
5005 this.stack[0].push(transaction);
5007 this.stack.unshift([transaction]);
5012 if (this.limit && this.stack.length > this.limit) {
5013 this.length = this.stack.length = this.limit;
5015 this.length = this.stack.length;
5018 if (this.fireEvent) {
5019 this.scope.dispatchEvent(
5020 new CustomEvent('DOMTransaction', {
5022 transactions: this.stack[0].slice()
5030 //Roo.log("transaction: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
5037 //Roo.log("undo: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
5039 if (this.position < this.length) {
5040 for (var i = this.stack[this.position].length - 1; i >= 0; i--) {
5041 this.stack[this.position][i].undo();
5045 if (this.fireEvent) {
5046 this.scope.dispatchEvent(
5047 new CustomEvent('undo', {
5049 transactions: this.stack[this.position - 1].slice()
5061 if (this.position > 0) {
5062 for (var i = 0, n = this.stack[this.position - 1].length; i < n; i++) {
5063 this.stack[this.position - 1][i].redo();
5067 if (this.fireEvent) {
5068 this.scope.dispatchEvent(
5069 new CustomEvent('redo', {
5071 transactions: this.stack[this.position].slice()
5081 item : function (index)
5083 if (index >= 0 && index < this.length) {
5084 return this.stack[index].slice();
5089 clearUndo : function () {
5090 this.stack.length = this.length = this.position;
5093 clearRedo : function () {
5094 this.stack.splice(0, this.position);
5096 this.length = this.stack.length;
5099 * Reset the undo - probaly done on load to clear all history.
5106 this.current_html = this.scope.innerHTML;
5107 if (this.timer !== false) {
5108 clearTimeout(this.timer);
5120 // this will handle the undo/redo on the element.?
5121 bindEvents : function()
5123 var el = this.scope;
5124 el.undoManager = this;
5127 this.scope.addEventListener('keydown', function(e) {
5128 if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
5130 el.undoManager.redo(); // Ctrl/Command + Shift + Z
5132 el.undoManager.undo(); // Ctrl/Command + Z
5139 this.scope.addEventListener('keyup', function(e) {
5140 if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
5149 el.addEventListener('input', function(e) {
5150 if(el.innerHTML == t.current_html) {
5153 // only record events every second.
5154 if (t.timer !== false) {
5155 clearTimeout(t.timer);
5158 t.timer = setTimeout(function() { t.merge = false; }, 1000);
5160 t.addEvent(t.merge);
5161 t.merge = true; // ignore changes happening every second..
5165 * Manually add an event.
5166 * Normall called without arguements - and it will just get added to the stack.
5170 addEvent : function(merge)
5172 //Roo.log("undomanager +" + (merge ? 'Y':'n'));
5173 // not sure if this should clear the timer
5174 merge = typeof(merge) == 'undefined' ? false : merge;
5176 this.scope.undoManager.transact({
5178 oldHTML: this.current_html,
5179 newHTML: this.scope.innerHTML,
5180 // nothing to execute (content already changed when input is fired)
5181 execute: function() { },
5183 this.scope.innerHTML = this.current_html = this.oldHTML;
5186 this.scope.innerHTML = this.current_html = this.newHTML;
5188 }, false); //merge);
5192 this.current_html = this.scope.innerHTML;
5203 * Ext JS Library 1.1.1
5204 * Copyright(c) 2006-2007, Ext JS, LLC.
5206 * Originally Released Under LGPL - original licence link has changed is not relivant.
5209 * <script type="text/javascript">
5213 // nasty IE9 hack - what a pile of crap that is..
5215 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
5216 Range.prototype.createContextualFragment = function (html) {
5217 var doc = window.document;
5218 var container = doc.createElement("div");
5219 container.innerHTML = html;
5220 var frag = doc.createDocumentFragment(), n;
5221 while ((n = container.firstChild)) {
5222 frag.appendChild(n);
5229 * @class Roo.DomHelper
5230 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
5231 * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
5234 Roo.DomHelper = function(){
5235 var tempTableEl = null;
5236 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
5237 var tableRe = /^table|tbody|tr|td$/i;
5239 // build as innerHTML where available
5241 var createHtml = function(o){
5242 if(typeof o == 'string'){
5251 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
5252 if(attr == "style"){
5254 if(typeof s == "function"){
5257 if(typeof s == "string"){
5258 b += ' style="' + s + '"';
5259 }else if(typeof s == "object"){
5262 if(typeof s[key] != "function"){
5263 b += key + ":" + s[key] + ";";
5270 b += ' class="' + o["cls"] + '"';
5271 }else if(attr == "htmlFor"){
5272 b += ' for="' + o["htmlFor"] + '"';
5274 b += " " + attr + '="' + o[attr] + '"';
5278 if(emptyTags.test(o.tag)){
5282 var cn = o.children || o.cn;
5284 //http://bugs.kde.org/show_bug.cgi?id=71506
5285 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5286 for(var i = 0, len = cn.length; i < len; i++) {
5287 b += createHtml(cn[i], b);
5290 b += createHtml(cn, b);
5296 b += "</" + o.tag + ">";
5303 var createDom = function(o, parentNode){
5305 // defininition craeted..
5307 if (o.ns && o.ns != 'html') {
5309 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
5310 xmlns[o.ns] = o.xmlns;
5313 if (typeof(xmlns[o.ns]) == 'undefined') {
5314 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
5320 if (typeof(o) == 'string') {
5321 return parentNode.appendChild(document.createTextNode(o));
5323 o.tag = o.tag || div;
5324 if (o.ns && Roo.isIE) {
5326 o.tag = o.ns + ':' + o.tag;
5329 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
5330 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
5333 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
5334 attr == "style" || typeof o[attr] == "function") { continue; }
5336 if(attr=="cls" && Roo.isIE){
5337 el.className = o["cls"];
5339 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
5345 Roo.DomHelper.applyStyles(el, o.style);
5346 var cn = o.children || o.cn;
5348 //http://bugs.kde.org/show_bug.cgi?id=71506
5349 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5350 for(var i = 0, len = cn.length; i < len; i++) {
5351 createDom(cn[i], el);
5358 el.innerHTML = o.html;
5361 parentNode.appendChild(el);
5366 var ieTable = function(depth, s, h, e){
5367 tempTableEl.innerHTML = [s, h, e].join('');
5368 var i = -1, el = tempTableEl;
5369 while(++i < depth && el.firstChild){
5375 // kill repeat to save bytes
5379 tbe = '</tbody>'+te,
5385 * Nasty code for IE's broken table implementation
5387 var insertIntoTable = function(tag, where, el, html){
5389 tempTableEl = document.createElement('div');
5394 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
5397 if(where == 'beforebegin'){
5401 before = el.nextSibling;
5404 node = ieTable(4, trs, html, tre);
5406 else if(tag == 'tr'){
5407 if(where == 'beforebegin'){
5410 node = ieTable(3, tbs, html, tbe);
5411 } else if(where == 'afterend'){
5412 before = el.nextSibling;
5414 node = ieTable(3, tbs, html, tbe);
5415 } else{ // INTO a TR
5416 if(where == 'afterbegin'){
5417 before = el.firstChild;
5419 node = ieTable(4, trs, html, tre);
5421 } else if(tag == 'tbody'){
5422 if(where == 'beforebegin'){
5425 node = ieTable(2, ts, html, te);
5426 } else if(where == 'afterend'){
5427 before = el.nextSibling;
5429 node = ieTable(2, ts, html, te);
5431 if(where == 'afterbegin'){
5432 before = el.firstChild;
5434 node = ieTable(3, tbs, html, tbe);
5437 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
5440 if(where == 'afterbegin'){
5441 before = el.firstChild;
5443 node = ieTable(2, ts, html, te);
5445 el.insertBefore(node, before);
5449 // this is a bit like the react update code...
5452 var updateNode = function(from, to)
5454 // should we handle non-standard elements?
5455 Roo.log(["UpdateNode" , from, to]);
5456 if (from.nodeType != to.nodeType) {
5457 Roo.log(["ReplaceChild - mismatch notType" , to, from ]);
5458 from.parentNode.replaceChild(to, from);
5461 if (from.nodeType == 3) {
5462 // assume it's text?!
5463 if (from.data == to.data) {
5466 from.data = to.data;
5470 // assume 'to' doesnt have '1/3 nodetypes!
5471 if (from.nodeType !=1 || from.tagName != to.tagName) {
5472 Roo.log(["ReplaceChild" , from, to ]);
5473 from.parentNode.replaceChild(to, from);
5476 // compare attributes
5477 var ar = Array.from(from.attributes);
5478 for(var i = 0; i< ar.length;i++) {
5479 if (to.hasAttribute(ar[i].name)) {
5482 if (ar[i].name == 'id') { // always keep ids?
5485 //if (ar[i].name == 'style') {
5486 // throw "style removed?";
5488 Roo.log("removeAttribute" + ar[i].name);
5489 from.removeAttribute(ar[i].name);
5492 for(var i = 0; i< ar.length;i++) {
5493 if (from.getAttribute(ar[i].name) == to.getAttribute(ar[i].name)) {
5494 Roo.log("skipAttribute " + ar[i].name + '=' + to.getAttribute(ar[i].name));
5497 Roo.log("updateAttribute " + ar[i].name + '=>' + to.getAttribute(ar[i].name));
5498 from.setAttribute(ar[i].name, to.getAttribute(ar[i].name));
5501 var far = Array.from(from.childNodes);
5502 var tar = Array.from(to.childNodes);
5503 // if the lengths are different.. then it's probably a editable content change, rather than
5504 // a change of the block definition..
5506 // this did notwork , as our rebuilt nodes did not include ID's so did not match at all.
5507 /*if (from.innerHTML == to.innerHTML) {
5510 if (far.length != tar.length) {
5511 from.innerHTML = to.innerHTML;
5516 for(var i = 0; i < Math.max(tar.length, far.length); i++) {
5517 if (i >= far.length) {
5518 from.appendChild(tar[i]);
5519 Roo.log(["add", tar[i]]);
5521 } else if ( i >= tar.length) {
5522 from.removeChild(far[i]);
5523 Roo.log(["remove", far[i]]);
5526 updateNode(far[i], tar[i]);
5538 /** True to force the use of DOM instead of html fragments @type Boolean */
5542 * Returns the markup for the passed Element(s) config
5543 * @param {Object} o The Dom object spec (and children)
5546 markup : function(o){
5547 return createHtml(o);
5551 * Applies a style specification to an element
5552 * @param {String/HTMLElement} el The element to apply styles to
5553 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
5554 * a function which returns such a specification.
5556 applyStyles : function(el, styles){
5559 if(typeof styles == "string"){
5560 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
5562 while ((matches = re.exec(styles)) != null){
5563 el.setStyle(matches[1], matches[2]);
5565 }else if (typeof styles == "object"){
5566 for (var style in styles){
5567 el.setStyle(style, styles[style]);
5569 }else if (typeof styles == "function"){
5570 Roo.DomHelper.applyStyles(el, styles.call());
5576 * Inserts an HTML fragment into the Dom
5577 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
5578 * @param {HTMLElement} el The context element
5579 * @param {String} html The HTML fragmenet
5580 * @return {HTMLElement} The new node
5582 insertHtml : function(where, el, html){
5583 where = where.toLowerCase();
5584 if(el.insertAdjacentHTML){
5585 if(tableRe.test(el.tagName)){
5587 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
5593 el.insertAdjacentHTML('BeforeBegin', html);
5594 return el.previousSibling;
5596 el.insertAdjacentHTML('AfterBegin', html);
5597 return el.firstChild;
5599 el.insertAdjacentHTML('BeforeEnd', html);
5600 return el.lastChild;
5602 el.insertAdjacentHTML('AfterEnd', html);
5603 return el.nextSibling;
5605 throw 'Illegal insertion point -> "' + where + '"';
5607 var range = el.ownerDocument.createRange();
5611 range.setStartBefore(el);
5612 frag = range.createContextualFragment(html);
5613 el.parentNode.insertBefore(frag, el);
5614 return el.previousSibling;
5617 range.setStartBefore(el.firstChild);
5618 frag = range.createContextualFragment(html);
5619 el.insertBefore(frag, el.firstChild);
5620 return el.firstChild;
5622 el.innerHTML = html;
5623 return el.firstChild;
5627 range.setStartAfter(el.lastChild);
5628 frag = range.createContextualFragment(html);
5629 el.appendChild(frag);
5630 return el.lastChild;
5632 el.innerHTML = html;
5633 return el.lastChild;
5636 range.setStartAfter(el);
5637 frag = range.createContextualFragment(html);
5638 el.parentNode.insertBefore(frag, el.nextSibling);
5639 return el.nextSibling;
5641 throw 'Illegal insertion point -> "' + where + '"';
5645 * Creates new Dom element(s) and inserts them before el
5646 * @param {String/HTMLElement/Element} el The context element
5647 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5648 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5649 * @return {HTMLElement/Roo.Element} The new node
5651 insertBefore : function(el, o, returnElement){
5652 return this.doInsert(el, o, returnElement, "beforeBegin");
5656 * Creates new Dom element(s) and inserts them after el
5657 * @param {String/HTMLElement/Element} el The context element
5658 * @param {Object} o The Dom object spec (and children)
5659 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5660 * @return {HTMLElement/Roo.Element} The new node
5662 insertAfter : function(el, o, returnElement){
5663 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
5667 * Creates new Dom element(s) and inserts them as the first child of el
5668 * @param {String/HTMLElement/Element} el The context element
5669 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5670 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5671 * @return {HTMLElement/Roo.Element} The new node
5673 insertFirst : function(el, o, returnElement){
5674 return this.doInsert(el, o, returnElement, "afterBegin");
5678 doInsert : function(el, o, returnElement, pos, sibling){
5679 el = Roo.getDom(el);
5681 if(this.useDom || o.ns){
5682 newNode = createDom(o, null);
5683 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
5685 var html = createHtml(o);
5686 newNode = this.insertHtml(pos, el, html);
5688 return returnElement ? Roo.get(newNode, true) : newNode;
5692 * Creates new Dom element(s) and appends them to el
5693 * @param {String/HTMLElement/Element} el The context element
5694 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5695 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5696 * @return {HTMLElement/Roo.Element} The new node
5698 append : function(el, o, returnElement){
5699 el = Roo.getDom(el);
5701 if(this.useDom || o.ns){
5702 newNode = createDom(o, null);
5703 el.appendChild(newNode);
5705 var html = createHtml(o);
5706 newNode = this.insertHtml("beforeEnd", el, html);
5708 return returnElement ? Roo.get(newNode, true) : newNode;
5712 * Creates new Dom element(s) and overwrites the contents of el with them
5713 * @param {String/HTMLElement/Element} el The context element
5714 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5715 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5716 * @return {HTMLElement/Roo.Element} The new node
5718 overwrite : function(el, o, returnElement)
5720 el = Roo.getDom(el);
5723 while (el.childNodes.length) {
5724 el.removeChild(el.firstChild);
5728 el.innerHTML = createHtml(o);
5731 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5735 * Creates a new Roo.DomHelper.Template from the Dom object spec
5736 * @param {Object} o The Dom object spec (and children)
5737 * @return {Roo.DomHelper.Template} The new template
5739 createTemplate : function(o){
5740 var html = createHtml(o);
5741 return new Roo.Template(html);
5744 * Updates the first element with the spec from the o (replacing if necessary)
5745 * This iterates through the children, and updates attributes / children etc..
5746 * @param {String/HTMLElement/Element} el The context element
5747 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5750 update : function(el, o)
5752 updateNode(Roo.getDom(el), createDom(o));
5761 * Ext JS Library 1.1.1
5762 * Copyright(c) 2006-2007, Ext JS, LLC.
5764 * Originally Released Under LGPL - original licence link has changed is not relivant.
5767 * <script type="text/javascript">
5771 * @class Roo.Template
5772 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
5773 * For a list of available format functions, see {@link Roo.util.Format}.<br />
5776 var t = new Roo.Template({
5777 html : '<div name="{id}">' +
5778 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
5780 myformat: function (value, allValues) {
5781 return 'XX' + value;
5784 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
5786 * For more information see this blog post with examples:
5787 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
5788 - Create Elements using DOM, HTML fragments and Templates</a>.
5790 * @param {Object} cfg - Configuration object.
5792 Roo.Template = function(cfg){
5794 if(cfg instanceof Array){
5796 }else if(arguments.length > 1){
5797 cfg = Array.prototype.join.call(arguments, "");
5801 if (typeof(cfg) == 'object') {
5812 Roo.Template.prototype = {
5815 * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
5821 * @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..
5822 * it should be fixed so that template is observable...
5826 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
5834 * Returns an HTML fragment of this template with the specified values applied.
5835 * @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'})
5836 * @return {String} The HTML fragment
5841 applyTemplate : function(values){
5842 //Roo.log(["applyTemplate", values]);
5846 return this.compiled(values);
5848 var useF = this.disableFormats !== true;
5849 var fm = Roo.util.Format, tpl = this;
5850 var fn = function(m, name, format, args){
5852 if(format.substr(0, 5) == "this."){
5853 return tpl.call(format.substr(5), values[name], values);
5856 // quoted values are required for strings in compiled templates,
5857 // but for non compiled we need to strip them
5858 // quoted reversed for jsmin
5859 var re = /^\s*['"](.*)["']\s*$/;
5860 args = args.split(',');
5861 for(var i = 0, len = args.length; i < len; i++){
5862 args[i] = args[i].replace(re, "$1");
5864 args = [values[name]].concat(args);
5866 args = [values[name]];
5868 return fm[format].apply(fm, args);
5871 return values[name] !== undefined ? values[name] : "";
5874 return this.html.replace(this.re, fn);
5892 this.loading = true;
5893 this.compiled = false;
5895 var cx = new Roo.data.Connection();
5899 success : function (response) {
5903 _t.set(response.responseText,true);
5909 failure : function(response) {
5910 Roo.log("Template failed to load from " + _t.url);
5917 * Sets the HTML used as the template and optionally compiles it.
5918 * @param {String} html
5919 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
5920 * @return {Roo.Template} this
5922 set : function(html, compile){
5924 this.compiled = false;
5932 * True to disable format functions (defaults to false)
5935 disableFormats : false,
5938 * The regular expression used to match template variables
5942 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
5945 * Compiles the template into an internal function, eliminating the RegEx overhead.
5946 * @return {Roo.Template} this
5948 compile : function(){
5949 var fm = Roo.util.Format;
5950 var useF = this.disableFormats !== true;
5951 var sep = Roo.isGecko ? "+" : ",";
5952 var fn = function(m, name, format, args){
5954 args = args ? ',' + args : "";
5955 if(format.substr(0, 5) != "this."){
5956 format = "fm." + format + '(';
5958 format = 'this.call("'+ format.substr(5) + '", ';
5962 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
5964 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
5967 // branched to use + in gecko and [].join() in others
5969 body = "this.compiled = function(values){ return '" +
5970 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
5973 body = ["this.compiled = function(values){ return ['"];
5974 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
5975 body.push("'].join('');};");
5976 body = body.join('');
5986 // private function used to call members
5987 call : function(fnName, value, allValues){
5988 return this[fnName](value, allValues);
5992 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
5993 * @param {String/HTMLElement/Roo.Element} el The context element
5994 * @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'})
5995 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5996 * @return {HTMLElement/Roo.Element} The new node or Element
5998 insertFirst: function(el, values, returnElement){
5999 return this.doInsert('afterBegin', el, values, returnElement);
6003 * Applies the supplied values to the template and inserts the new node(s) before el.
6004 * @param {String/HTMLElement/Roo.Element} el The context element
6005 * @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'})
6006 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6007 * @return {HTMLElement/Roo.Element} The new node or Element
6009 insertBefore: function(el, values, returnElement){
6010 return this.doInsert('beforeBegin', el, values, returnElement);
6014 * Applies the supplied values to the template and inserts the new node(s) after el.
6015 * @param {String/HTMLElement/Roo.Element} el The context element
6016 * @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'})
6017 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6018 * @return {HTMLElement/Roo.Element} The new node or Element
6020 insertAfter : function(el, values, returnElement){
6021 return this.doInsert('afterEnd', el, values, returnElement);
6025 * Applies the supplied values to the template and appends the new node(s) to el.
6026 * @param {String/HTMLElement/Roo.Element} el The context element
6027 * @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'})
6028 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6029 * @return {HTMLElement/Roo.Element} The new node or Element
6031 append : function(el, values, returnElement){
6032 return this.doInsert('beforeEnd', el, values, returnElement);
6035 doInsert : function(where, el, values, returnEl){
6036 el = Roo.getDom(el);
6037 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
6038 return returnEl ? Roo.get(newNode, true) : newNode;
6042 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
6043 * @param {String/HTMLElement/Roo.Element} el The context element
6044 * @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'})
6045 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6046 * @return {HTMLElement/Roo.Element} The new node or Element
6048 overwrite : function(el, values, returnElement){
6049 el = Roo.getDom(el);
6050 el.innerHTML = this.applyTemplate(values);
6051 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
6055 * Alias for {@link #applyTemplate}
6058 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
6061 Roo.DomHelper.Template = Roo.Template;
6064 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
6065 * @param {String/HTMLElement} el A DOM element or its id
6066 * @returns {Roo.Template} The created template
6069 Roo.Template.from = function(el){
6070 el = Roo.getDom(el);
6071 return new Roo.Template(el.value || el.innerHTML);
6074 * Ext JS Library 1.1.1
6075 * Copyright(c) 2006-2007, Ext JS, LLC.
6077 * Originally Released Under LGPL - original licence link has changed is not relivant.
6080 * <script type="text/javascript">
6085 * This is code is also distributed under MIT license for use
6086 * with jQuery and prototype JavaScript libraries.
6089 * @class Roo.DomQuery
6090 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).
6092 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>
6095 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.
6097 <h4>Element Selectors:</h4>
6099 <li> <b>*</b> any element</li>
6100 <li> <b>E</b> an element with the tag E</li>
6101 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
6102 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
6103 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
6104 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
6106 <h4>Attribute Selectors:</h4>
6107 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
6109 <li> <b>E[foo]</b> has an attribute "foo"</li>
6110 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
6111 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
6112 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
6113 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
6114 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
6115 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
6117 <h4>Pseudo Classes:</h4>
6119 <li> <b>E:first-child</b> E is the first child of its parent</li>
6120 <li> <b>E:last-child</b> E is the last child of its parent</li>
6121 <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>
6122 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
6123 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
6124 <li> <b>E:only-child</b> E is the only child of its parent</li>
6125 <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>
6126 <li> <b>E:first</b> the first E in the resultset</li>
6127 <li> <b>E:last</b> the last E in the resultset</li>
6128 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
6129 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
6130 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
6131 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
6132 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
6133 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
6134 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
6135 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
6136 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
6138 <h4>CSS Value Selectors:</h4>
6140 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
6141 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
6142 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
6143 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
6144 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
6145 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
6149 Roo.DomQuery = function(){
6150 var cache = {}, simpleCache = {}, valueCache = {};
6151 var nonSpace = /\S/;
6152 var trimRe = /^\s+|\s+$/g;
6153 var tplRe = /\{(\d+)\}/g;
6154 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
6155 var tagTokenRe = /^(#)?([\w-\*]+)/;
6156 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
6158 function child(p, index){
6160 var n = p.firstChild;
6162 if(n.nodeType == 1){
6173 while((n = n.nextSibling) && n.nodeType != 1);
6178 while((n = n.previousSibling) && n.nodeType != 1);
6182 function children(d){
6183 var n = d.firstChild, ni = -1;
6185 var nx = n.nextSibling;
6186 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
6196 function byClassName(c, a, v){
6200 var r = [], ri = -1, cn;
6201 for(var i = 0, ci; ci = c[i]; i++){
6205 ( (ci instanceof SVGElement) ? ci.className.baseVal : ci.className)
6206 +' ').indexOf(v) != -1){
6213 function attrValue(n, attr){
6214 if(!n.tagName && typeof n.length != "undefined"){
6223 if(attr == "class" || attr == "className"){
6224 return (n instanceof SVGElement) ? n.className.baseVal : n.className;
6226 return n.getAttribute(attr) || n[attr];
6230 function getNodes(ns, mode, tagName){
6231 var result = [], ri = -1, cs;
6235 tagName = tagName || "*";
6236 if(typeof ns.getElementsByTagName != "undefined"){
6240 for(var i = 0, ni; ni = ns[i]; i++){
6241 cs = ni.getElementsByTagName(tagName);
6242 for(var j = 0, ci; ci = cs[j]; j++){
6246 }else if(mode == "/" || mode == ">"){
6247 var utag = tagName.toUpperCase();
6248 for(var i = 0, ni, cn; ni = ns[i]; i++){
6249 cn = ni.children || ni.childNodes;
6250 for(var j = 0, cj; cj = cn[j]; j++){
6251 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
6256 }else if(mode == "+"){
6257 var utag = tagName.toUpperCase();
6258 for(var i = 0, n; n = ns[i]; i++){
6259 while((n = n.nextSibling) && n.nodeType != 1);
6260 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
6264 }else if(mode == "~"){
6265 for(var i = 0, n; n = ns[i]; i++){
6266 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
6275 function concat(a, b){
6279 for(var i = 0, l = b.length; i < l; i++){
6285 function byTag(cs, tagName){
6286 if(cs.tagName || cs == document){
6292 var r = [], ri = -1;
6293 tagName = tagName.toLowerCase();
6294 for(var i = 0, ci; ci = cs[i]; i++){
6295 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
6302 function byId(cs, attr, id){
6303 if(cs.tagName || cs == document){
6309 var r = [], ri = -1;
6310 for(var i = 0,ci; ci = cs[i]; i++){
6311 if(ci && ci.id == id){
6319 function byAttribute(cs, attr, value, op, custom){
6320 var r = [], ri = -1, st = custom=="{";
6321 var f = Roo.DomQuery.operators[op];
6322 for(var i = 0, ci; ci = cs[i]; i++){
6325 a = Roo.DomQuery.getStyle(ci, attr);
6327 else if(attr == "class" || attr == "className"){
6328 a = (ci instanceof SVGElement) ? ci.className.baseVal : ci.className;
6329 }else if(attr == "for"){
6331 }else if(attr == "href"){
6332 a = ci.getAttribute("href", 2);
6334 a = ci.getAttribute(attr);
6336 if((f && f(a, value)) || (!f && a)){
6343 function byPseudo(cs, name, value){
6344 return Roo.DomQuery.pseudos[name](cs, value);
6347 // This is for IE MSXML which does not support expandos.
6348 // IE runs the same speed using setAttribute, however FF slows way down
6349 // and Safari completely fails so they need to continue to use expandos.
6350 var isIE = window.ActiveXObject ? true : false;
6352 // this eval is stop the compressor from
6353 // renaming the variable to something shorter
6355 /** eval:var:batch */
6360 function nodupIEXml(cs){
6362 cs[0].setAttribute("_nodup", d);
6364 for(var i = 1, len = cs.length; i < len; i++){
6366 if(!c.getAttribute("_nodup") != d){
6367 c.setAttribute("_nodup", d);
6371 for(var i = 0, len = cs.length; i < len; i++){
6372 cs[i].removeAttribute("_nodup");
6381 var len = cs.length, c, i, r = cs, cj, ri = -1;
6382 if(!len || typeof cs.nodeType != "undefined" || len == 1){
6385 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
6386 return nodupIEXml(cs);
6390 for(i = 1; c = cs[i]; i++){
6395 for(var j = 0; j < i; j++){
6398 for(j = i+1; cj = cs[j]; j++){
6410 function quickDiffIEXml(c1, c2){
6412 for(var i = 0, len = c1.length; i < len; i++){
6413 c1[i].setAttribute("_qdiff", d);
6416 for(var i = 0, len = c2.length; i < len; i++){
6417 if(c2[i].getAttribute("_qdiff") != d){
6418 r[r.length] = c2[i];
6421 for(var i = 0, len = c1.length; i < len; i++){
6422 c1[i].removeAttribute("_qdiff");
6427 function quickDiff(c1, c2){
6428 var len1 = c1.length;
6432 if(isIE && c1[0].selectSingleNode){
6433 return quickDiffIEXml(c1, c2);
6436 for(var i = 0; i < len1; i++){
6440 for(var i = 0, len = c2.length; i < len; i++){
6441 if(c2[i]._qdiff != d){
6442 r[r.length] = c2[i];
6448 function quickId(ns, mode, root, id){
6450 var d = root.ownerDocument || root;
6451 return d.getElementById(id);
6453 ns = getNodes(ns, mode, "*");
6454 return byId(ns, null, id);
6458 getStyle : function(el, name){
6459 return Roo.fly(el).getStyle(name);
6462 * Compiles a selector/xpath query into a reusable function. The returned function
6463 * takes one parameter "root" (optional), which is the context node from where the query should start.
6464 * @param {String} selector The selector/xpath query
6465 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
6466 * @return {Function}
6468 compile : function(path, type){
6469 type = type || "select";
6471 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
6472 var q = path, mode, lq;
6473 var tk = Roo.DomQuery.matchers;
6474 var tklen = tk.length;
6477 // accept leading mode switch
6478 var lmode = q.match(modeRe);
6479 if(lmode && lmode[1]){
6480 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
6481 q = q.replace(lmode[1], "");
6483 // strip leading slashes
6484 while(path.substr(0, 1)=="/"){
6485 path = path.substr(1);
6488 while(q && lq != q){
6490 var tm = q.match(tagTokenRe);
6491 if(type == "select"){
6494 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
6496 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
6498 q = q.replace(tm[0], "");
6499 }else if(q.substr(0, 1) != '@'){
6500 fn[fn.length] = 'n = getNodes(n, mode, "*");';
6505 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
6507 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
6509 q = q.replace(tm[0], "");
6512 while(!(mm = q.match(modeRe))){
6513 var matched = false;
6514 for(var j = 0; j < tklen; j++){
6516 var m = q.match(t.re);
6518 fn[fn.length] = t.select.replace(tplRe, function(x, i){
6521 q = q.replace(m[0], "");
6526 // prevent infinite loop on bad selector
6528 throw 'Error parsing selector, parsing failed at "' + q + '"';
6532 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
6533 q = q.replace(mm[1], "");
6536 fn[fn.length] = "return nodup(n);\n}";
6539 * list of variables that need from compression as they are used by eval.
6549 * eval:var:byClassName
6551 * eval:var:byAttribute
6552 * eval:var:attrValue
6560 * Selects a group of elements.
6561 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
6562 * @param {Node} root (optional) The start of the query (defaults to document).
6565 select : function(path, root, type){
6566 if(!root || root == document){
6569 if(typeof root == "string"){
6570 root = document.getElementById(root);
6572 var paths = path.split(",");
6574 for(var i = 0, len = paths.length; i < len; i++){
6575 var p = paths[i].replace(trimRe, "");
6577 cache[p] = Roo.DomQuery.compile(p);
6579 throw p + " is not a valid selector";
6582 var result = cache[p](root);
6583 if(result && result != document){
6584 results = results.concat(result);
6587 if(paths.length > 1){
6588 return nodup(results);
6594 * Selects a single element.
6595 * @param {String} selector The selector/xpath query
6596 * @param {Node} root (optional) The start of the query (defaults to document).
6599 selectNode : function(path, root){
6600 return Roo.DomQuery.select(path, root)[0];
6604 * Selects the value of a node, optionally replacing null with the defaultValue.
6605 * @param {String} selector The selector/xpath query
6606 * @param {Node} root (optional) The start of the query (defaults to document).
6607 * @param {String} defaultValue
6609 selectValue : function(path, root, defaultValue){
6610 path = path.replace(trimRe, "");
6611 if(!valueCache[path]){
6612 valueCache[path] = Roo.DomQuery.compile(path, "select");
6614 var n = valueCache[path](root);
6615 n = n[0] ? n[0] : n;
6616 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
6617 return ((v === null||v === undefined||v==='') ? defaultValue : v);
6621 * Selects the value of a node, parsing integers and floats.
6622 * @param {String} selector The selector/xpath query
6623 * @param {Node} root (optional) The start of the query (defaults to document).
6624 * @param {Number} defaultValue
6627 selectNumber : function(path, root, defaultValue){
6628 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
6629 return parseFloat(v);
6633 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
6634 * @param {String/HTMLElement/Array} el An element id, element or array of elements
6635 * @param {String} selector The simple selector to test
6638 is : function(el, ss){
6639 if(typeof el == "string"){
6640 el = document.getElementById(el);
6642 var isArray = (el instanceof Array);
6643 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
6644 return isArray ? (result.length == el.length) : (result.length > 0);
6648 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
6649 * @param {Array} el An array of elements to filter
6650 * @param {String} selector The simple selector to test
6651 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
6652 * the selector instead of the ones that match
6655 filter : function(els, ss, nonMatches){
6656 ss = ss.replace(trimRe, "");
6657 if(!simpleCache[ss]){
6658 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
6660 var result = simpleCache[ss](els);
6661 return nonMatches ? quickDiff(result, els) : result;
6665 * Collection of matching regular expressions and code snippets.
6669 select: 'n = byClassName(n, null, " {1} ");'
6671 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
6672 select: 'n = byPseudo(n, "{1}", "{2}");'
6674 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
6675 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
6678 select: 'n = byId(n, null, "{1}");'
6681 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
6686 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
6687 * 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, > <.
6690 "=" : function(a, v){
6693 "!=" : function(a, v){
6696 "^=" : function(a, v){
6697 return a && a.substr(0, v.length) == v;
6699 "$=" : function(a, v){
6700 return a && a.substr(a.length-v.length) == v;
6702 "*=" : function(a, v){
6703 return a && a.indexOf(v) !== -1;
6705 "%=" : function(a, v){
6706 return (a % v) == 0;
6708 "|=" : function(a, v){
6709 return a && (a == v || a.substr(0, v.length+1) == v+'-');
6711 "~=" : function(a, v){
6712 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
6717 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
6718 * and the argument (if any) supplied in the selector.
6721 "first-child" : function(c){
6722 var r = [], ri = -1, n;
6723 for(var i = 0, ci; ci = n = c[i]; i++){
6724 while((n = n.previousSibling) && n.nodeType != 1);
6732 "last-child" : function(c){
6733 var r = [], ri = -1, n;
6734 for(var i = 0, ci; ci = n = c[i]; i++){
6735 while((n = n.nextSibling) && n.nodeType != 1);
6743 "nth-child" : function(c, a) {
6744 var r = [], ri = -1;
6745 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
6746 var f = (m[1] || 1) - 0, l = m[2] - 0;
6747 for(var i = 0, n; n = c[i]; i++){
6748 var pn = n.parentNode;
6749 if (batch != pn._batch) {
6751 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
6752 if(cn.nodeType == 1){
6759 if (l == 0 || n.nodeIndex == l){
6762 } else if ((n.nodeIndex + l) % f == 0){
6770 "only-child" : function(c){
6771 var r = [], ri = -1;;
6772 for(var i = 0, ci; ci = c[i]; i++){
6773 if(!prev(ci) && !next(ci)){
6780 "empty" : function(c){
6781 var r = [], ri = -1;
6782 for(var i = 0, ci; ci = c[i]; i++){
6783 var cns = ci.childNodes, j = 0, cn, empty = true;
6786 if(cn.nodeType == 1 || cn.nodeType == 3){
6798 "contains" : function(c, v){
6799 var r = [], ri = -1;
6800 for(var i = 0, ci; ci = c[i]; i++){
6801 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
6808 "nodeValue" : function(c, v){
6809 var r = [], ri = -1;
6810 for(var i = 0, ci; ci = c[i]; i++){
6811 if(ci.firstChild && ci.firstChild.nodeValue == v){
6818 "checked" : function(c){
6819 var r = [], ri = -1;
6820 for(var i = 0, ci; ci = c[i]; i++){
6821 if(ci.checked == true){
6828 "not" : function(c, ss){
6829 return Roo.DomQuery.filter(c, ss, true);
6832 "odd" : function(c){
6833 return this["nth-child"](c, "odd");
6836 "even" : function(c){
6837 return this["nth-child"](c, "even");
6840 "nth" : function(c, a){
6841 return c[a-1] || [];
6844 "first" : function(c){
6848 "last" : function(c){
6849 return c[c.length-1] || [];
6852 "has" : function(c, ss){
6853 var s = Roo.DomQuery.select;
6854 var r = [], ri = -1;
6855 for(var i = 0, ci; ci = c[i]; i++){
6856 if(s(ss, ci).length > 0){
6863 "next" : function(c, ss){
6864 var is = Roo.DomQuery.is;
6865 var r = [], ri = -1;
6866 for(var i = 0, ci; ci = c[i]; i++){
6875 "prev" : function(c, ss){
6876 var is = Roo.DomQuery.is;
6877 var r = [], ri = -1;
6878 for(var i = 0, ci; ci = c[i]; i++){
6891 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
6892 * @param {String} path The selector/xpath query
6893 * @param {Node} root (optional) The start of the query (defaults to document).
6898 Roo.query = Roo.DomQuery.select;
6901 * Ext JS Library 1.1.1
6902 * Copyright(c) 2006-2007, Ext JS, LLC.
6904 * Originally Released Under LGPL - original licence link has changed is not relivant.
6907 * <script type="text/javascript">
6911 * @class Roo.util.Observable
6912 * Base class that provides a common interface for publishing events. Subclasses are expected to
6913 * to have a property "events" with all the events defined.<br>
6916 Employee = function(name){
6923 Roo.extend(Employee, Roo.util.Observable);
6925 * @param {Object} config properties to use (incuding events / listeners)
6928 Roo.util.Observable = function(cfg){
6931 this.addEvents(cfg.events || {});
6933 delete cfg.events; // make sure
6936 Roo.apply(this, cfg);
6939 this.on(this.listeners);
6940 delete this.listeners;
6943 Roo.util.Observable.prototype = {
6945 * @cfg {Object} listeners list of events and functions to call for this object,
6949 'click' : function(e) {
6959 * Fires the specified event with the passed parameters (minus the event name).
6960 * @param {String} eventName
6961 * @param {Object...} args Variable number of parameters are passed to handlers
6962 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
6964 fireEvent : function(){
6965 var ce = this.events[arguments[0].toLowerCase()];
6966 if(typeof ce == "object"){
6967 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
6974 filterOptRe : /^(?:scope|delay|buffer|single)$/,
6977 * Appends an event handler to this component
6978 * @param {String} eventName The type of event to listen for
6979 * @param {Function} handler The method the event invokes
6980 * @param {Object} scope (optional) The scope in which to execute the handler
6981 * function. The handler function's "this" context.
6982 * @param {Object} options (optional) An object containing handler configuration
6983 * properties. This may contain any of the following properties:<ul>
6984 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6985 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6986 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6987 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6988 * by the specified number of milliseconds. If the event fires again within that time, the original
6989 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6992 * <b>Combining Options</b><br>
6993 * Using the options argument, it is possible to combine different types of listeners:<br>
6995 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
6997 el.on('click', this.onClick, this, {
7004 * <b>Attaching multiple handlers in 1 call</b><br>
7005 * The method also allows for a single argument to be passed which is a config object containing properties
7006 * which specify multiple handlers.
7015 fn: this.onMouseOver,
7019 fn: this.onMouseOut,
7025 * Or a shorthand syntax which passes the same scope object to all handlers:
7028 'click': this.onClick,
7029 'mouseover': this.onMouseOver,
7030 'mouseout': this.onMouseOut,
7035 addListener : function(eventName, fn, scope, o){
7036 if(typeof eventName == "object"){
7039 if(this.filterOptRe.test(e)){
7042 if(typeof o[e] == "function"){
7044 this.addListener(e, o[e], o.scope, o);
7046 // individual options
7047 this.addListener(e, o[e].fn, o[e].scope, o[e]);
7052 o = (!o || typeof o == "boolean") ? {} : o;
7053 eventName = eventName.toLowerCase();
7054 var ce = this.events[eventName] || true;
7055 if(typeof ce == "boolean"){
7056 ce = new Roo.util.Event(this, eventName);
7057 this.events[eventName] = ce;
7059 ce.addListener(fn, scope, o);
7063 * Removes a listener
7064 * @param {String} eventName The type of event to listen for
7065 * @param {Function} handler The handler to remove
7066 * @param {Object} scope (optional) The scope (this object) for the handler
7068 removeListener : function(eventName, fn, scope){
7069 var ce = this.events[eventName.toLowerCase()];
7070 if(typeof ce == "object"){
7071 ce.removeListener(fn, scope);
7076 * Removes all listeners for this object
7078 purgeListeners : function(){
7079 for(var evt in this.events){
7080 if(typeof this.events[evt] == "object"){
7081 this.events[evt].clearListeners();
7086 relayEvents : function(o, events){
7087 var createHandler = function(ename){
7090 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
7093 for(var i = 0, len = events.length; i < len; i++){
7094 var ename = events[i];
7095 if(!this.events[ename]){
7096 this.events[ename] = true;
7098 o.on(ename, createHandler(ename), this);
7103 * Used to define events on this Observable
7104 * @param {Object} object The object with the events defined
7106 addEvents : function(o){
7110 Roo.applyIf(this.events, o);
7114 * Checks to see if this object has any listeners for a specified event
7115 * @param {String} eventName The name of the event to check for
7116 * @return {Boolean} True if the event is being listened for, else false
7118 hasListener : function(eventName){
7119 var e = this.events[eventName];
7120 return typeof e == "object" && e.listeners.length > 0;
7124 * Appends an event handler to this element (shorthand for addListener)
7125 * @param {String} eventName The type of event to listen for
7126 * @param {Function} handler The method the event invokes
7127 * @param {Object} scope (optional) The scope in which to execute the handler
7128 * function. The handler function's "this" context.
7129 * @param {Object} options (optional)
7132 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
7134 * Removes a listener (shorthand for removeListener)
7135 * @param {String} eventName The type of event to listen for
7136 * @param {Function} handler The handler to remove
7137 * @param {Object} scope (optional) The scope (this object) for the handler
7140 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
7143 * Starts capture on the specified Observable. All events will be passed
7144 * to the supplied function with the event name + standard signature of the event
7145 * <b>before</b> the event is fired. If the supplied function returns false,
7146 * the event will not fire.
7147 * @param {Observable} o The Observable to capture
7148 * @param {Function} fn The function to call
7149 * @param {Object} scope (optional) The scope (this object) for the fn
7152 Roo.util.Observable.capture = function(o, fn, scope){
7153 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
7157 * Removes <b>all</b> added captures from the Observable.
7158 * @param {Observable} o The Observable to release
7161 Roo.util.Observable.releaseCapture = function(o){
7162 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
7167 var createBuffered = function(h, o, scope){
7168 var task = new Roo.util.DelayedTask();
7170 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
7174 var createSingle = function(h, e, fn, scope){
7176 e.removeListener(fn, scope);
7177 return h.apply(scope, arguments);
7181 var createDelayed = function(h, o, scope){
7183 var args = Array.prototype.slice.call(arguments, 0);
7184 setTimeout(function(){
7185 h.apply(scope, args);
7190 Roo.util.Event = function(obj, name){
7193 this.listeners = [];
7196 Roo.util.Event.prototype = {
7197 addListener : function(fn, scope, options){
7198 var o = options || {};
7199 scope = scope || this.obj;
7200 if(!this.isListening(fn, scope)){
7201 var l = {fn: fn, scope: scope, options: o};
7204 h = createDelayed(h, o, scope);
7207 h = createSingle(h, this, fn, scope);
7210 h = createBuffered(h, o, scope);
7213 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
7214 this.listeners.push(l);
7216 this.listeners = this.listeners.slice(0);
7217 this.listeners.push(l);
7222 findListener : function(fn, scope){
7223 scope = scope || this.obj;
7224 var ls = this.listeners;
7225 for(var i = 0, len = ls.length; i < len; i++){
7227 if(l.fn == fn && l.scope == scope){
7234 isListening : function(fn, scope){
7235 return this.findListener(fn, scope) != -1;
7238 removeListener : function(fn, scope){
7240 if((index = this.findListener(fn, scope)) != -1){
7242 this.listeners.splice(index, 1);
7244 this.listeners = this.listeners.slice(0);
7245 this.listeners.splice(index, 1);
7252 clearListeners : function(){
7253 this.listeners = [];
7257 var ls = this.listeners, scope, len = ls.length;
7260 var args = Array.prototype.slice.call(arguments, 0);
7261 for(var i = 0; i < len; i++){
7263 if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
7264 this.firing = false;
7268 this.firing = false;
7275 * Copyright(c) 2007-2017, Roo J Solutions Ltd
7282 * @class Roo.Document
7283 * @extends Roo.util.Observable
7284 * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
7286 * @param {Object} config the methods and properties of the 'base' class for the application.
7288 * Generic Page handler - implement this to start your app..
7291 * MyProject = new Roo.Document({
7293 'load' : true // your events..
7296 'ready' : function() {
7297 // fired on Roo.onReady()
7302 Roo.Document = function(cfg) {
7307 Roo.util.Observable.call(this,cfg);
7311 Roo.onReady(function() {
7312 _this.fireEvent('ready');
7318 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
7320 * Ext JS Library 1.1.1
7321 * Copyright(c) 2006-2007, Ext JS, LLC.
7323 * Originally Released Under LGPL - original licence link has changed is not relivant.
7326 * <script type="text/javascript">
7330 * @class Roo.EventManager
7331 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
7332 * several useful events directly.
7333 * See {@link Roo.EventObject} for more details on normalized event objects.
7336 Roo.EventManager = function(){
7337 var docReadyEvent, docReadyProcId, docReadyState = false;
7338 var resizeEvent, resizeTask, textEvent, textSize;
7339 var E = Roo.lib.Event;
7340 var D = Roo.lib.Dom;
7345 var fireDocReady = function(){
7347 docReadyState = true;
7350 clearInterval(docReadyProcId);
7352 if(Roo.isGecko || Roo.isOpera) {
7353 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
7356 var defer = document.getElementById("ie-deferred-loader");
7358 defer.onreadystatechange = null;
7359 defer.parentNode.removeChild(defer);
7363 docReadyEvent.fire();
7364 docReadyEvent.clearListeners();
7369 var initDocReady = function(){
7370 docReadyEvent = new Roo.util.Event();
7371 if(Roo.isGecko || Roo.isOpera) {
7372 document.addEventListener("DOMContentLoaded", fireDocReady, false);
7374 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
7375 var defer = document.getElementById("ie-deferred-loader");
7376 defer.onreadystatechange = function(){
7377 if(this.readyState == "complete"){
7381 }else if(Roo.isSafari){
7382 docReadyProcId = setInterval(function(){
7383 var rs = document.readyState;
7384 if(rs == "complete") {
7389 // no matter what, make sure it fires on load
7390 E.on(window, "load", fireDocReady);
7393 var createBuffered = function(h, o){
7394 var task = new Roo.util.DelayedTask(h);
7396 // create new event object impl so new events don't wipe out properties
7397 e = new Roo.EventObjectImpl(e);
7398 task.delay(o.buffer, h, null, [e]);
7402 var createSingle = function(h, el, ename, fn){
7404 Roo.EventManager.removeListener(el, ename, fn);
7409 var createDelayed = function(h, o){
7411 // create new event object impl so new events don't wipe out properties
7412 e = new Roo.EventObjectImpl(e);
7413 setTimeout(function(){
7418 var transitionEndVal = false;
7420 var transitionEnd = function()
7422 if (transitionEndVal) {
7423 return transitionEndVal;
7425 var el = document.createElement('div');
7427 var transEndEventNames = {
7428 WebkitTransition : 'webkitTransitionEnd',
7429 MozTransition : 'transitionend',
7430 OTransition : 'oTransitionEnd otransitionend',
7431 transition : 'transitionend'
7434 for (var name in transEndEventNames) {
7435 if (el.style[name] !== undefined) {
7436 transitionEndVal = transEndEventNames[name];
7437 return transitionEndVal ;
7444 var listen = function(element, ename, opt, fn, scope)
7446 var o = (!opt || typeof opt == "boolean") ? {} : opt;
7447 fn = fn || o.fn; scope = scope || o.scope;
7448 var el = Roo.getDom(element);
7452 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
7455 if (ename == 'transitionend') {
7456 ename = transitionEnd();
7458 var h = function(e){
7459 e = Roo.EventObject.setEvent(e);
7462 t = e.getTarget(o.delegate, el);
7469 if(o.stopEvent === true){
7472 if(o.preventDefault === true){
7475 if(o.stopPropagation === true){
7476 e.stopPropagation();
7479 if(o.normalized === false){
7483 fn.call(scope || el, e, t, o);
7486 h = createDelayed(h, o);
7489 h = createSingle(h, el, ename, fn);
7492 h = createBuffered(h, o);
7495 fn._handlers = fn._handlers || [];
7498 fn._handlers.push([Roo.id(el), ename, h]);
7502 E.on(el, ename, h); // this adds the actuall listener to the object..
7505 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
7506 el.addEventListener("DOMMouseScroll", h, false);
7507 E.on(window, 'unload', function(){
7508 el.removeEventListener("DOMMouseScroll", h, false);
7511 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7512 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
7517 var stopListening = function(el, ename, fn){
7518 var id = Roo.id(el), hds = fn._handlers, hd = fn;
7520 for(var i = 0, len = hds.length; i < len; i++){
7522 if(h[0] == id && h[1] == ename){
7529 E.un(el, ename, hd);
7530 el = Roo.getDom(el);
7531 if(ename == "mousewheel" && el.addEventListener){
7532 el.removeEventListener("DOMMouseScroll", hd, false);
7534 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7535 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
7539 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
7546 * @scope Roo.EventManager
7551 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
7552 * object with a Roo.EventObject
7553 * @param {Function} fn The method the event invokes
7554 * @param {Object} scope An object that becomes the scope of the handler
7555 * @param {boolean} override If true, the obj passed in becomes
7556 * the execution scope of the listener
7557 * @return {Function} The wrapped function
7560 wrap : function(fn, scope, override){
7562 Roo.EventObject.setEvent(e);
7563 fn.call(override ? scope || window : window, Roo.EventObject, scope);
7568 * Appends an event handler to an element (shorthand for addListener)
7569 * @param {String/HTMLElement} element The html element or id to assign the
7570 * @param {String} eventName The type of event to listen for
7571 * @param {Function} handler The method the event invokes
7572 * @param {Object} scope (optional) The scope in which to execute the handler
7573 * function. The handler function's "this" context.
7574 * @param {Object} options (optional) An object containing handler configuration
7575 * properties. This may contain any of the following properties:<ul>
7576 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7577 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7578 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7579 * <li>preventDefault {Boolean} True to prevent the default action</li>
7580 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7581 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7582 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7583 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7584 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7585 * by the specified number of milliseconds. If the event fires again within that time, the original
7586 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7589 * <b>Combining Options</b><br>
7590 * Using the options argument, it is possible to combine different types of listeners:<br>
7592 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7594 el.on('click', this.onClick, this, {
7601 * <b>Attaching multiple handlers in 1 call</b><br>
7602 * The method also allows for a single argument to be passed which is a config object containing properties
7603 * which specify multiple handlers.
7613 fn: this.onMouseOver
7622 * Or a shorthand syntax:<br>
7625 'click' : this.onClick,
7626 'mouseover' : this.onMouseOver,
7627 'mouseout' : this.onMouseOut
7631 addListener : function(element, eventName, fn, scope, options){
7632 if(typeof eventName == "object"){
7638 if(typeof o[e] == "function"){
7640 listen(element, e, o, o[e], o.scope);
7642 // individual options
7643 listen(element, e, o[e]);
7648 return listen(element, eventName, options, fn, scope);
7652 * Removes an event handler
7654 * @param {String/HTMLElement} element The id or html element to remove the
7656 * @param {String} eventName The type of event
7657 * @param {Function} fn
7658 * @return {Boolean} True if a listener was actually removed
7660 removeListener : function(element, eventName, fn){
7661 return stopListening(element, eventName, fn);
7665 * Fires when the document is ready (before onload and before images are loaded). Can be
7666 * accessed shorthanded Roo.onReady().
7667 * @param {Function} fn The method the event invokes
7668 * @param {Object} scope An object that becomes the scope of the handler
7669 * @param {boolean} options
7671 onDocumentReady : function(fn, scope, options){
7672 if(docReadyState){ // if it already fired
7673 docReadyEvent.addListener(fn, scope, options);
7674 docReadyEvent.fire();
7675 docReadyEvent.clearListeners();
7681 docReadyEvent.addListener(fn, scope, options);
7685 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
7686 * @param {Function} fn The method the event invokes
7687 * @param {Object} scope An object that becomes the scope of the handler
7688 * @param {boolean} options
7690 onWindowResize : function(fn, scope, options)
7693 resizeEvent = new Roo.util.Event();
7694 resizeTask = new Roo.util.DelayedTask(function(){
7695 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7697 E.on(window, "resize", function()
7700 resizeTask.delay(50);
7702 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7706 resizeEvent.addListener(fn, scope, options);
7710 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
7711 * @param {Function} fn The method the event invokes
7712 * @param {Object} scope An object that becomes the scope of the handler
7713 * @param {boolean} options
7715 onTextResize : function(fn, scope, options){
7717 textEvent = new Roo.util.Event();
7718 var textEl = new Roo.Element(document.createElement('div'));
7719 textEl.dom.className = 'x-text-resize';
7720 textEl.dom.innerHTML = 'X';
7721 textEl.appendTo(document.body);
7722 textSize = textEl.dom.offsetHeight;
7723 setInterval(function(){
7724 if(textEl.dom.offsetHeight != textSize){
7725 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
7727 }, this.textResizeInterval);
7729 textEvent.addListener(fn, scope, options);
7733 * Removes the passed window resize listener.
7734 * @param {Function} fn The method the event invokes
7735 * @param {Object} scope The scope of handler
7737 removeResizeListener : function(fn, scope){
7739 resizeEvent.removeListener(fn, scope);
7744 fireResize : function(){
7746 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7750 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
7754 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
7756 textResizeInterval : 50
7761 * @scopeAlias pub=Roo.EventManager
7765 * Appends an event handler to an element (shorthand for addListener)
7766 * @param {String/HTMLElement} element The html element or id to assign the
7767 * @param {String} eventName The type of event to listen for
7768 * @param {Function} handler The method the event invokes
7769 * @param {Object} scope (optional) The scope in which to execute the handler
7770 * function. The handler function's "this" context.
7771 * @param {Object} options (optional) An object containing handler configuration
7772 * properties. This may contain any of the following properties:<ul>
7773 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7774 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7775 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7776 * <li>preventDefault {Boolean} True to prevent the default action</li>
7777 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7778 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7779 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7780 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7781 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7782 * by the specified number of milliseconds. If the event fires again within that time, the original
7783 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7786 * <b>Combining Options</b><br>
7787 * Using the options argument, it is possible to combine different types of listeners:<br>
7789 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7791 el.on('click', this.onClick, this, {
7798 * <b>Attaching multiple handlers in 1 call</b><br>
7799 * The method also allows for a single argument to be passed which is a config object containing properties
7800 * which specify multiple handlers.
7810 fn: this.onMouseOver
7819 * Or a shorthand syntax:<br>
7822 'click' : this.onClick,
7823 'mouseover' : this.onMouseOver,
7824 'mouseout' : this.onMouseOut
7828 pub.on = pub.addListener;
7829 pub.un = pub.removeListener;
7831 pub.stoppedMouseDownEvent = new Roo.util.Event();
7835 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
7836 * @param {Function} fn The method the event invokes
7837 * @param {Object} scope An object that becomes the scope of the handler
7838 * @param {boolean} override If true, the obj passed in becomes
7839 * the execution scope of the listener
7843 Roo.onReady = Roo.EventManager.onDocumentReady;
7845 Roo.onReady(function(){
7846 var bd = Roo.get(document.body);
7851 : Roo.isIE11 ? "roo-ie11"
7852 : Roo.isEdge ? "roo-edge"
7853 : Roo.isGecko ? "roo-gecko"
7854 : Roo.isOpera ? "roo-opera"
7855 : Roo.isSafari ? "roo-safari" : ""];
7858 cls.push("roo-mac");
7861 cls.push("roo-linux");
7864 cls.push("roo-ios");
7867 cls.push("roo-touch");
7869 if(Roo.isBorderBox){
7870 cls.push('roo-border-box');
7872 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
7873 var p = bd.dom.parentNode;
7875 p.className += ' roo-strict';
7878 bd.addClass(cls.join(' '));
7882 * @class Roo.EventObject
7883 * EventObject exposes the Yahoo! UI Event functionality directly on the object
7884 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
7887 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
7889 var target = e.getTarget();
7892 var myDiv = Roo.get("myDiv");
7893 myDiv.on("click", handleClick);
7895 Roo.EventManager.on("myDiv", 'click', handleClick);
7896 Roo.EventManager.addListener("myDiv", 'click', handleClick);
7900 Roo.EventObject = function(){
7902 var E = Roo.lib.Event;
7904 // safari keypress events for special keys return bad keycodes
7907 63235 : 39, // right
7910 63276 : 33, // page up
7911 63277 : 34, // page down
7912 63272 : 46, // delete
7917 // normalize button clicks
7918 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
7919 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
7921 Roo.EventObjectImpl = function(e){
7923 this.setEvent(e.browserEvent || e);
7926 Roo.EventObjectImpl.prototype = {
7928 * Used to fix doc tools.
7929 * @scope Roo.EventObject.prototype
7935 /** The normal browser event */
7936 browserEvent : null,
7937 /** The button pressed in a mouse event */
7939 /** True if the shift key was down during the event */
7941 /** True if the control key was down during the event */
7943 /** True if the alt key was down during the event */
8002 setEvent : function(e){
8003 if(e == this || (e && e.browserEvent)){ // already wrapped
8006 this.browserEvent = e;
8008 // normalize buttons
8009 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
8010 if(e.type == 'click' && this.button == -1){
8014 this.shiftKey = e.shiftKey;
8015 // mac metaKey behaves like ctrlKey
8016 this.ctrlKey = e.ctrlKey || e.metaKey;
8017 this.altKey = e.altKey;
8018 // in getKey these will be normalized for the mac
8019 this.keyCode = e.keyCode;
8020 // keyup warnings on firefox.
8021 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
8022 // cache the target for the delayed and or buffered events
8023 this.target = E.getTarget(e);
8025 this.xy = E.getXY(e);
8028 this.shiftKey = false;
8029 this.ctrlKey = false;
8030 this.altKey = false;
8040 * Stop the event (preventDefault and stopPropagation)
8042 stopEvent : function(){
8043 if(this.browserEvent){
8044 if(this.browserEvent.type == 'mousedown'){
8045 Roo.EventManager.stoppedMouseDownEvent.fire(this);
8047 E.stopEvent(this.browserEvent);
8052 * Prevents the browsers default handling of the event.
8054 preventDefault : function(){
8055 if(this.browserEvent){
8056 E.preventDefault(this.browserEvent);
8061 isNavKeyPress : function(){
8062 var k = this.keyCode;
8063 k = Roo.isSafari ? (safariKeys[k] || k) : k;
8064 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
8067 isSpecialKey : function(){
8068 var k = this.keyCode;
8069 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
8070 (k == 16) || (k == 17) ||
8071 (k >= 18 && k <= 20) ||
8072 (k >= 33 && k <= 35) ||
8073 (k >= 36 && k <= 39) ||
8074 (k >= 44 && k <= 45);
8077 * Cancels bubbling of the event.
8079 stopPropagation : function(){
8080 if(this.browserEvent){
8081 if(this.type == 'mousedown'){
8082 Roo.EventManager.stoppedMouseDownEvent.fire(this);
8084 E.stopPropagation(this.browserEvent);
8089 * Gets the key code for the event.
8092 getCharCode : function(){
8093 return this.charCode || this.keyCode;
8097 * Returns a normalized keyCode for the event.
8098 * @return {Number} The key code
8100 getKey : function(){
8101 var k = this.keyCode || this.charCode;
8102 return Roo.isSafari ? (safariKeys[k] || k) : k;
8106 * Gets the x coordinate of the event.
8109 getPageX : function(){
8114 * Gets the y coordinate of the event.
8117 getPageY : function(){
8122 * Gets the time of the event.
8125 getTime : function(){
8126 if(this.browserEvent){
8127 return E.getTime(this.browserEvent);
8133 * Gets the page coordinates of the event.
8134 * @return {Array} The xy values like [x, y]
8141 * Gets the target for the event.
8142 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
8143 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8144 search as a number or element (defaults to 10 || document.body)
8145 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8146 * @return {HTMLelement}
8148 getTarget : function(selector, maxDepth, returnEl){
8149 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
8152 * Gets the related target.
8153 * @return {HTMLElement}
8155 getRelatedTarget : function(){
8156 if(this.browserEvent){
8157 return E.getRelatedTarget(this.browserEvent);
8163 * Normalizes mouse wheel delta across browsers
8164 * @return {Number} The delta
8166 getWheelDelta : function(){
8167 var e = this.browserEvent;
8169 if(e.wheelDelta){ /* IE/Opera. */
8170 delta = e.wheelDelta/120;
8171 }else if(e.detail){ /* Mozilla case. */
8172 delta = -e.detail/3;
8178 * Returns true if the control, meta, shift or alt key was pressed during this event.
8181 hasModifier : function(){
8182 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
8186 * Returns true if the target of this event equals el or is a child of el
8187 * @param {String/HTMLElement/Element} el
8188 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
8191 within : function(el, related){
8192 var t = this[related ? "getRelatedTarget" : "getTarget"]();
8193 return t && Roo.fly(el).contains(t);
8196 getPoint : function(){
8197 return new Roo.lib.Point(this.xy[0], this.xy[1]);
8201 return new Roo.EventObjectImpl();
8206 * Ext JS Library 1.1.1
8207 * Copyright(c) 2006-2007, Ext JS, LLC.
8209 * Originally Released Under LGPL - original licence link has changed is not relivant.
8212 * <script type="text/javascript">
8216 // was in Composite Element!??!?!
8219 var D = Roo.lib.Dom;
8220 var E = Roo.lib.Event;
8221 var A = Roo.lib.Anim;
8223 // local style camelizing for speed
8225 var camelRe = /(-[a-z])/gi;
8226 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
8227 var view = document.defaultView;
8230 * @class Roo.Element
8231 * Represents an Element in the DOM.<br><br>
8234 var el = Roo.get("my-div");
8237 var el = getEl("my-div");
8239 // or with a DOM element
8240 var el = Roo.get(myDivElement);
8242 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
8243 * each call instead of constructing a new one.<br><br>
8244 * <b>Animations</b><br />
8245 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
8246 * should either be a boolean (true) or an object literal with animation options. The animation options are:
8248 Option Default Description
8249 --------- -------- ---------------------------------------------
8250 duration .35 The duration of the animation in seconds
8251 easing easeOut The YUI easing method
8252 callback none A function to execute when the anim completes
8253 scope this The scope (this) of the callback function
8255 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
8256 * manipulate the animation. Here's an example:
8258 var el = Roo.get("my-div");
8263 // default animation
8264 el.setWidth(100, true);
8266 // animation with some options set
8273 // using the "anim" property to get the Anim object
8279 el.setWidth(100, opt);
8281 if(opt.anim.isAnimated()){
8285 * <b> Composite (Collections of) Elements</b><br />
8286 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
8287 * @constructor Create a new Element directly.
8288 * @param {String/HTMLElement} element
8289 * @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).
8291 Roo.Element = function(element, forceNew)
8293 var dom = typeof element == "string" ?
8294 document.getElementById(element) : element;
8296 this.listeners = {};
8298 if(!dom){ // invalid id/element
8302 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
8303 return Roo.Element.cache[id];
8313 * The DOM element ID
8316 this.id = id || Roo.id(dom);
8318 return this; // assumed for cctor?
8321 var El = Roo.Element;
8325 * The element's default display mode (defaults to "")
8328 originalDisplay : "",
8331 // note this is overridden in BS version..
8334 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
8340 * Sets the element's visibility mode. When setVisible() is called it
8341 * will use this to determine whether to set the visibility or the display property.
8342 * @param visMode Element.VISIBILITY or Element.DISPLAY
8343 * @return {Roo.Element} this
8345 setVisibilityMode : function(visMode){
8346 this.visibilityMode = visMode;
8350 * Convenience method for setVisibilityMode(Element.DISPLAY)
8351 * @param {String} display (optional) What to set display to when visible
8352 * @return {Roo.Element} this
8354 enableDisplayMode : function(display){
8355 this.setVisibilityMode(El.DISPLAY);
8356 if(typeof display != "undefined") { this.originalDisplay = display; }
8361 * 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)
8362 * @param {String} selector The simple selector to test
8363 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8364 search as a number or element (defaults to 10 || document.body)
8365 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8366 * @return {HTMLElement} The matching DOM node (or null if no match was found)
8368 findParent : function(simpleSelector, maxDepth, returnEl){
8369 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
8370 maxDepth = maxDepth || 50;
8371 if(typeof maxDepth != "number"){
8372 stopEl = Roo.getDom(maxDepth);
8375 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
8376 if(dq.is(p, simpleSelector)){
8377 return returnEl ? Roo.get(p) : p;
8387 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
8388 * @param {String} selector The simple selector to test
8389 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8390 search as a number or element (defaults to 10 || document.body)
8391 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8392 * @return {HTMLElement} The matching DOM node (or null if no match was found)
8394 findParentNode : function(simpleSelector, maxDepth, returnEl){
8395 var p = Roo.fly(this.dom.parentNode, '_internal');
8396 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
8400 * Looks at the scrollable parent element
8402 findScrollableParent : function()
8404 var overflowRegex = /(auto|scroll)/;
8406 if(this.getStyle('position') === 'fixed'){
8407 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8410 var excludeStaticParent = this.getStyle('position') === "absolute";
8412 for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
8414 if (excludeStaticParent && parent.getStyle('position') === "static") {
8418 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
8422 if(parent.dom.nodeName.toLowerCase() == 'body'){
8423 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8427 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8431 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
8432 * This is a shortcut for findParentNode() that always returns an Roo.Element.
8433 * @param {String} selector The simple selector to test
8434 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8435 search as a number or element (defaults to 10 || document.body)
8436 * @return {Roo.Element} The matching DOM node (or null if no match was found)
8438 up : function(simpleSelector, maxDepth){
8439 return this.findParentNode(simpleSelector, maxDepth, true);
8445 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
8446 * @param {String} selector The simple selector to test
8447 * @return {Boolean} True if this element matches the selector, else false
8449 is : function(simpleSelector){
8450 return Roo.DomQuery.is(this.dom, simpleSelector);
8454 * Perform animation on this element.
8455 * @param {Object} args The YUI animation control args
8456 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
8457 * @param {Function} onComplete (optional) Function to call when animation completes
8458 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
8459 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
8460 * @return {Roo.Element} this
8462 animate : function(args, duration, onComplete, easing, animType){
8463 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
8468 * @private Internal animation call
8470 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
8471 animType = animType || 'run';
8473 var anim = Roo.lib.Anim[animType](
8475 (opt.duration || defaultDur) || .35,
8476 (opt.easing || defaultEase) || 'easeOut',
8478 Roo.callback(cb, this);
8479 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
8487 // private legacy anim prep
8488 preanim : function(a, i){
8489 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
8493 * Removes worthless text nodes
8494 * @param {Boolean} forceReclean (optional) By default the element
8495 * keeps track if it has been cleaned already so
8496 * you can call this over and over. However, if you update the element and
8497 * need to force a reclean, you can pass true.
8499 clean : function(forceReclean){
8500 if(this.isCleaned && forceReclean !== true){
8504 var d = this.dom, n = d.firstChild, ni = -1;
8506 var nx = n.nextSibling;
8507 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
8514 this.isCleaned = true;
8519 calcOffsetsTo : function(el){
8522 var restorePos = false;
8523 if(el.getStyle('position') == 'static'){
8524 el.position('relative');
8529 while(op && op != d && op.tagName != 'HTML'){
8532 op = op.offsetParent;
8535 el.position('static');
8541 * Scrolls this element into view within the passed container.
8542 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
8543 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
8544 * @return {Roo.Element} this
8546 scrollIntoView : function(container, hscroll){
8547 var c = Roo.getDom(container) || document.body;
8550 var o = this.calcOffsetsTo(c),
8553 b = t+el.offsetHeight,
8554 r = l+el.offsetWidth;
8556 var ch = c.clientHeight;
8557 var ct = parseInt(c.scrollTop, 10);
8558 var cl = parseInt(c.scrollLeft, 10);
8560 var cr = cl + c.clientWidth;
8568 if(hscroll !== false){
8572 c.scrollLeft = r-c.clientWidth;
8579 scrollChildIntoView : function(child, hscroll){
8580 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
8584 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
8585 * the new height may not be available immediately.
8586 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
8587 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
8588 * @param {Function} onComplete (optional) Function to call when animation completes
8589 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
8590 * @return {Roo.Element} this
8592 autoHeight : function(animate, duration, onComplete, easing){
8593 var oldHeight = this.getHeight();
8595 this.setHeight(1); // force clipping
8596 setTimeout(function(){
8597 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
8599 this.setHeight(height);
8601 if(typeof onComplete == "function"){
8605 this.setHeight(oldHeight); // restore original height
8606 this.setHeight(height, animate, duration, function(){
8608 if(typeof onComplete == "function") { onComplete(); }
8609 }.createDelegate(this), easing);
8611 }.createDelegate(this), 0);
8616 * Returns true if this element is an ancestor of the passed element
8617 * @param {HTMLElement/String} el The element to check
8618 * @return {Boolean} True if this element is an ancestor of el, else false
8620 contains : function(el){
8621 if(!el){return false;}
8622 return D.isAncestor(this.dom, el.dom ? el.dom : el);
8626 * Checks whether the element is currently visible using both visibility and display properties.
8627 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
8628 * @return {Boolean} True if the element is currently visible, else false
8630 isVisible : function(deep) {
8631 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
8632 if(deep !== true || !vis){
8635 var p = this.dom.parentNode;
8636 while(p && p.tagName.toLowerCase() != "body"){
8637 if(!Roo.fly(p, '_isVisible').isVisible()){
8646 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
8647 * @param {String} selector The CSS selector
8648 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
8649 * @return {CompositeElement/CompositeElementLite} The composite element
8651 select : function(selector, unique){
8652 return El.select(selector, unique, this.dom);
8656 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
8657 * @param {String} selector The CSS selector
8658 * @return {Array} An array of the matched nodes
8660 query : function(selector, unique){
8661 return Roo.DomQuery.select(selector, this.dom);
8665 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
8666 * @param {String} selector The CSS selector
8667 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8668 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8670 child : function(selector, returnDom){
8671 var n = Roo.DomQuery.selectNode(selector, this.dom);
8672 return returnDom ? n : Roo.get(n);
8676 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
8677 * @param {String} selector The CSS selector
8678 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8679 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8681 down : function(selector, returnDom){
8682 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
8683 return returnDom ? n : Roo.get(n);
8687 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
8688 * @param {String} group The group the DD object is member of
8689 * @param {Object} config The DD config object
8690 * @param {Object} overrides An object containing methods to override/implement on the DD object
8691 * @return {Roo.dd.DD} The DD object
8693 initDD : function(group, config, overrides){
8694 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
8695 return Roo.apply(dd, overrides);
8699 * Initializes a {@link Roo.dd.DDProxy} object for this element.
8700 * @param {String} group The group the DDProxy object is member of
8701 * @param {Object} config The DDProxy config object
8702 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
8703 * @return {Roo.dd.DDProxy} The DDProxy object
8705 initDDProxy : function(group, config, overrides){
8706 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
8707 return Roo.apply(dd, overrides);
8711 * Initializes a {@link Roo.dd.DDTarget} object for this element.
8712 * @param {String} group The group the DDTarget object is member of
8713 * @param {Object} config The DDTarget config object
8714 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
8715 * @return {Roo.dd.DDTarget} The DDTarget object
8717 initDDTarget : function(group, config, overrides){
8718 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
8719 return Roo.apply(dd, overrides);
8723 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
8724 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
8725 * @param {Boolean} visible Whether the element is visible
8726 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8727 * @return {Roo.Element} this
8729 setVisible : function(visible, animate){
8731 if(this.visibilityMode == El.DISPLAY){
8732 this.setDisplayed(visible);
8735 this.dom.style.visibility = visible ? "visible" : "hidden";
8738 // closure for composites
8740 var visMode = this.visibilityMode;
8742 this.setOpacity(.01);
8743 this.setVisible(true);
8745 this.anim({opacity: { to: (visible?1:0) }},
8746 this.preanim(arguments, 1),
8747 null, .35, 'easeIn', function(){
8749 if(visMode == El.DISPLAY){
8750 dom.style.display = "none";
8752 dom.style.visibility = "hidden";
8754 Roo.get(dom).setOpacity(1);
8762 * Returns true if display is not "none"
8765 isDisplayed : function() {
8766 return this.getStyle("display") != "none";
8770 * Toggles the element's visibility or display, depending on visibility mode.
8771 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8772 * @return {Roo.Element} this
8774 toggle : function(animate){
8775 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
8780 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
8781 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
8782 * @return {Roo.Element} this
8784 setDisplayed : function(value) {
8785 if(typeof value == "boolean"){
8786 value = value ? this.originalDisplay : "none";
8788 this.setStyle("display", value);
8793 * Tries to focus the element. Any exceptions are caught and ignored.
8794 * @return {Roo.Element} this
8796 focus : function() {
8804 * Tries to blur the element. Any exceptions are caught and ignored.
8805 * @return {Roo.Element} this
8815 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
8816 * @param {String/Array} className The CSS class to add, or an array of classes
8817 * @return {Roo.Element} this
8819 addClass : function(className){
8820 if(className instanceof Array){
8821 for(var i = 0, len = className.length; i < len; i++) {
8822 this.addClass(className[i]);
8825 if(className && !this.hasClass(className)){
8826 if (this.dom instanceof SVGElement) {
8827 this.dom.className.baseVal =this.dom.className.baseVal + " " + className;
8829 this.dom.className = this.dom.className + " " + className;
8837 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
8838 * @param {String/Array} className The CSS class to add, or an array of classes
8839 * @return {Roo.Element} this
8841 radioClass : function(className){
8842 var siblings = this.dom.parentNode.childNodes;
8843 for(var i = 0; i < siblings.length; i++) {
8844 var s = siblings[i];
8845 if(s.nodeType == 1){
8846 Roo.get(s).removeClass(className);
8849 this.addClass(className);
8854 * Removes one or more CSS classes from the element.
8855 * @param {String/Array} className The CSS class to remove, or an array of classes
8856 * @return {Roo.Element} this
8858 removeClass : function(className){
8860 var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
8861 if(!className || !cn){
8864 if(className instanceof Array){
8865 for(var i = 0, len = className.length; i < len; i++) {
8866 this.removeClass(className[i]);
8869 if(this.hasClass(className)){
8870 var re = this.classReCache[className];
8872 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
8873 this.classReCache[className] = re;
8875 if (this.dom instanceof SVGElement) {
8876 this.dom.className.baseVal = cn.replace(re, " ");
8878 this.dom.className = cn.replace(re, " ");
8889 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
8890 * @param {String} className The CSS class to toggle
8891 * @return {Roo.Element} this
8893 toggleClass : function(className){
8894 if(this.hasClass(className)){
8895 this.removeClass(className);
8897 this.addClass(className);
8903 * Checks if the specified CSS class exists on this element's DOM node.
8904 * @param {String} className The CSS class to check for
8905 * @return {Boolean} True if the class exists, else false
8907 hasClass : function(className){
8908 if (this.dom instanceof SVGElement) {
8909 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1;
8911 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
8915 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
8916 * @param {String} oldClassName The CSS class to replace
8917 * @param {String} newClassName The replacement CSS class
8918 * @return {Roo.Element} this
8920 replaceClass : function(oldClassName, newClassName){
8921 this.removeClass(oldClassName);
8922 this.addClass(newClassName);
8927 * Returns an object with properties matching the styles requested.
8928 * For example, el.getStyles('color', 'font-size', 'width') might return
8929 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
8930 * @param {String} style1 A style name
8931 * @param {String} style2 A style name
8932 * @param {String} etc.
8933 * @return {Object} The style object
8935 getStyles : function(){
8936 var a = arguments, len = a.length, r = {};
8937 for(var i = 0; i < len; i++){
8938 r[a[i]] = this.getStyle(a[i]);
8944 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
8945 * @param {String} property The style property whose value is returned.
8946 * @return {String} The current value of the style property for this element.
8948 getStyle : function(){
8949 return view && view.getComputedStyle ?
8951 var el = this.dom, v, cs, camel;
8952 if(prop == 'float'){
8955 if(el.style && (v = el.style[prop])){
8958 if(cs = view.getComputedStyle(el, "")){
8959 if(!(camel = propCache[prop])){
8960 camel = propCache[prop] = prop.replace(camelRe, camelFn);
8967 var el = this.dom, v, cs, camel;
8968 if(prop == 'opacity'){
8969 if(typeof el.style.filter == 'string'){
8970 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
8972 var fv = parseFloat(m[1]);
8974 return fv ? fv / 100 : 0;
8979 }else if(prop == 'float'){
8980 prop = "styleFloat";
8982 if(!(camel = propCache[prop])){
8983 camel = propCache[prop] = prop.replace(camelRe, camelFn);
8985 if(v = el.style[camel]){
8988 if(cs = el.currentStyle){
8996 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
8997 * @param {String/Object} property The style property to be set, or an object of multiple styles.
8998 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
8999 * @return {Roo.Element} this
9001 setStyle : function(prop, value){
9002 if(typeof prop == "string"){
9004 if (prop == 'float') {
9005 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
9010 if(!(camel = propCache[prop])){
9011 camel = propCache[prop] = prop.replace(camelRe, camelFn);
9014 if(camel == 'opacity') {
9015 this.setOpacity(value);
9017 this.dom.style[camel] = value;
9020 for(var style in prop){
9021 if(typeof prop[style] != "function"){
9022 this.setStyle(style, prop[style]);
9030 * More flexible version of {@link #setStyle} for setting style properties.
9031 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
9032 * a function which returns such a specification.
9033 * @return {Roo.Element} this
9035 applyStyles : function(style){
9036 Roo.DomHelper.applyStyles(this.dom, style);
9041 * 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).
9042 * @return {Number} The X position of the element
9045 return D.getX(this.dom);
9049 * 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).
9050 * @return {Number} The Y position of the element
9053 return D.getY(this.dom);
9057 * 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).
9058 * @return {Array} The XY position of the element
9061 return D.getXY(this.dom);
9065 * 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).
9066 * @param {Number} The X position of the element
9067 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9068 * @return {Roo.Element} this
9070 setX : function(x, animate){
9072 D.setX(this.dom, x);
9074 this.setXY([x, this.getY()], this.preanim(arguments, 1));
9080 * 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).
9081 * @param {Number} The Y position of the element
9082 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9083 * @return {Roo.Element} this
9085 setY : function(y, animate){
9087 D.setY(this.dom, y);
9089 this.setXY([this.getX(), y], this.preanim(arguments, 1));
9095 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
9096 * @param {String} left The left CSS property value
9097 * @return {Roo.Element} this
9099 setLeft : function(left){
9100 this.setStyle("left", this.addUnits(left));
9105 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
9106 * @param {String} top The top CSS property value
9107 * @return {Roo.Element} this
9109 setTop : function(top){
9110 this.setStyle("top", this.addUnits(top));
9115 * Sets the element's CSS right style.
9116 * @param {String} right The right CSS property value
9117 * @return {Roo.Element} this
9119 setRight : function(right){
9120 this.setStyle("right", this.addUnits(right));
9125 * Sets the element's CSS bottom style.
9126 * @param {String} bottom The bottom CSS property value
9127 * @return {Roo.Element} this
9129 setBottom : function(bottom){
9130 this.setStyle("bottom", this.addUnits(bottom));
9135 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9136 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9137 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
9138 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9139 * @return {Roo.Element} this
9141 setXY : function(pos, animate){
9143 D.setXY(this.dom, pos);
9145 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
9151 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9152 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9153 * @param {Number} x X value for new position (coordinates are page-based)
9154 * @param {Number} y Y value for new position (coordinates are page-based)
9155 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9156 * @return {Roo.Element} this
9158 setLocation : function(x, y, animate){
9159 this.setXY([x, y], this.preanim(arguments, 2));
9164 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9165 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9166 * @param {Number} x X value for new position (coordinates are page-based)
9167 * @param {Number} y Y value for new position (coordinates are page-based)
9168 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9169 * @return {Roo.Element} this
9171 moveTo : function(x, y, animate){
9172 this.setXY([x, y], this.preanim(arguments, 2));
9177 * Returns the region of the given element.
9178 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
9179 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
9181 getRegion : function(){
9182 return D.getRegion(this.dom);
9186 * Returns the offset height of the element
9187 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
9188 * @return {Number} The element's height
9190 getHeight : function(contentHeight){
9191 var h = this.dom.offsetHeight || 0;
9192 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
9196 * Returns the offset width of the element
9197 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
9198 * @return {Number} The element's width
9200 getWidth : function(contentWidth){
9201 var w = this.dom.offsetWidth || 0;
9202 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
9206 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
9207 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
9208 * if a height has not been set using CSS.
9211 getComputedHeight : function(){
9212 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
9214 h = parseInt(this.getStyle('height'), 10) || 0;
9215 if(!this.isBorderBox()){
9216 h += this.getFrameWidth('tb');
9223 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
9224 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
9225 * if a width has not been set using CSS.
9228 getComputedWidth : function(){
9229 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
9231 w = parseInt(this.getStyle('width'), 10) || 0;
9232 if(!this.isBorderBox()){
9233 w += this.getFrameWidth('lr');
9240 * Returns the size of the element.
9241 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
9242 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
9244 getSize : function(contentSize){
9245 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
9249 * Returns the width and height of the viewport.
9250 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
9252 getViewSize : function(){
9253 var d = this.dom, doc = document, aw = 0, ah = 0;
9254 if(d == doc || d == doc.body){
9255 return {width : D.getViewWidth(), height: D.getViewHeight()};
9258 width : d.clientWidth,
9259 height: d.clientHeight
9265 * Returns the value of the "value" attribute
9266 * @param {Boolean} asNumber true to parse the value as a number
9267 * @return {String/Number}
9269 getValue : function(asNumber){
9270 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
9274 adjustWidth : function(width){
9275 if(typeof width == "number"){
9276 if(this.autoBoxAdjust && !this.isBorderBox()){
9277 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9287 adjustHeight : function(height){
9288 if(typeof height == "number"){
9289 if(this.autoBoxAdjust && !this.isBorderBox()){
9290 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9300 * Set the width of the element
9301 * @param {Number} width The new width
9302 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9303 * @return {Roo.Element} this
9305 setWidth : function(width, animate){
9306 width = this.adjustWidth(width);
9308 this.dom.style.width = this.addUnits(width);
9310 this.anim({width: {to: width}}, this.preanim(arguments, 1));
9316 * Set the height of the element
9317 * @param {Number} height The new height
9318 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9319 * @return {Roo.Element} this
9321 setHeight : function(height, animate){
9322 height = this.adjustHeight(height);
9324 this.dom.style.height = this.addUnits(height);
9326 this.anim({height: {to: height}}, this.preanim(arguments, 1));
9332 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
9333 * @param {Number} width The new width
9334 * @param {Number} height The new height
9335 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9336 * @return {Roo.Element} this
9338 setSize : function(width, height, animate){
9339 if(typeof width == "object"){ // in case of object from getSize()
9340 height = width.height; width = width.width;
9342 width = this.adjustWidth(width); height = this.adjustHeight(height);
9344 this.dom.style.width = this.addUnits(width);
9345 this.dom.style.height = this.addUnits(height);
9347 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
9353 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
9354 * @param {Number} x X value for new position (coordinates are page-based)
9355 * @param {Number} y Y value for new position (coordinates are page-based)
9356 * @param {Number} width The new width
9357 * @param {Number} height The new height
9358 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9359 * @return {Roo.Element} this
9361 setBounds : function(x, y, width, height, animate){
9363 this.setSize(width, height);
9364 this.setLocation(x, y);
9366 width = this.adjustWidth(width); height = this.adjustHeight(height);
9367 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
9368 this.preanim(arguments, 4), 'motion');
9374 * 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.
9375 * @param {Roo.lib.Region} region The region to fill
9376 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9377 * @return {Roo.Element} this
9379 setRegion : function(region, animate){
9380 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
9385 * Appends an event handler
9387 * @param {String} eventName The type of event to append
9388 * @param {Function} fn The method the event invokes
9389 * @param {Object} scope (optional) The scope (this object) of the fn
9390 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9392 addListener : function(eventName, fn, scope, options)
9394 if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
9395 this.addListener('touchstart', this.onTapHandler, this);
9398 // we need to handle a special case where dom element is a svg element.
9399 // in this case we do not actua
9404 if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
9405 if (typeof(this.listeners[eventName]) == 'undefined') {
9406 this.listeners[eventName] = new Roo.util.Event(this, eventName);
9408 this.listeners[eventName].addListener(fn, scope, options);
9413 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
9418 onTapHandler : function(event)
9420 if(!this.tapedTwice) {
9421 this.tapedTwice = true;
9423 setTimeout( function() {
9424 s.tapedTwice = false;
9428 event.preventDefault();
9429 var revent = new MouseEvent('dblclick', {
9435 this.dom.dispatchEvent(revent);
9436 //action on double tap goes below
9441 * Removes an event handler from this element
9442 * @param {String} eventName the type of event to remove
9443 * @param {Function} fn the method the event invokes
9444 * @param {Function} scope (needed for svg fake listeners)
9445 * @return {Roo.Element} this
9447 removeListener : function(eventName, fn, scope){
9448 Roo.EventManager.removeListener(this.dom, eventName, fn);
9449 if (typeof(this.listeners) == 'undefined' || typeof(this.listeners[eventName]) == 'undefined') {
9452 this.listeners[eventName].removeListener(fn, scope);
9457 * Removes all previous added listeners from this element
9458 * @return {Roo.Element} this
9460 removeAllListeners : function(){
9461 E.purgeElement(this.dom);
9462 this.listeners = {};
9466 relayEvent : function(eventName, observable){
9467 this.on(eventName, function(e){
9468 observable.fireEvent(eventName, e);
9474 * Set the opacity of the element
9475 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
9476 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9477 * @return {Roo.Element} this
9479 setOpacity : function(opacity, animate){
9481 var s = this.dom.style;
9484 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
9485 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
9487 s.opacity = opacity;
9490 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
9496 * Gets the left X coordinate
9497 * @param {Boolean} local True to get the local css position instead of page coordinate
9500 getLeft : function(local){
9504 return parseInt(this.getStyle("left"), 10) || 0;
9509 * Gets the right X coordinate of the element (element X position + element width)
9510 * @param {Boolean} local True to get the local css position instead of page coordinate
9513 getRight : function(local){
9515 return this.getX() + this.getWidth();
9517 return (this.getLeft(true) + this.getWidth()) || 0;
9522 * Gets the top Y coordinate
9523 * @param {Boolean} local True to get the local css position instead of page coordinate
9526 getTop : function(local) {
9530 return parseInt(this.getStyle("top"), 10) || 0;
9535 * Gets the bottom Y coordinate of the element (element Y position + element height)
9536 * @param {Boolean} local True to get the local css position instead of page coordinate
9539 getBottom : function(local){
9541 return this.getY() + this.getHeight();
9543 return (this.getTop(true) + this.getHeight()) || 0;
9548 * Initializes positioning on this element. If a desired position is not passed, it will make the
9549 * the element positioned relative IF it is not already positioned.
9550 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
9551 * @param {Number} zIndex (optional) The zIndex to apply
9552 * @param {Number} x (optional) Set the page X position
9553 * @param {Number} y (optional) Set the page Y position
9555 position : function(pos, zIndex, x, y){
9557 if(this.getStyle('position') == 'static'){
9558 this.setStyle('position', 'relative');
9561 this.setStyle("position", pos);
9564 this.setStyle("z-index", zIndex);
9566 if(x !== undefined && y !== undefined){
9568 }else if(x !== undefined){
9570 }else if(y !== undefined){
9576 * Clear positioning back to the default when the document was loaded
9577 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
9578 * @return {Roo.Element} this
9580 clearPositioning : function(value){
9588 "position" : "static"
9594 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
9595 * snapshot before performing an update and then restoring the element.
9598 getPositioning : function(){
9599 var l = this.getStyle("left");
9600 var t = this.getStyle("top");
9602 "position" : this.getStyle("position"),
9604 "right" : l ? "" : this.getStyle("right"),
9606 "bottom" : t ? "" : this.getStyle("bottom"),
9607 "z-index" : this.getStyle("z-index")
9612 * Gets the width of the border(s) for the specified side(s)
9613 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9614 * passing lr would get the border (l)eft width + the border (r)ight width.
9615 * @return {Number} The width of the sides passed added together
9617 getBorderWidth : function(side){
9618 return this.addStyles(side, El.borders);
9622 * Gets the width of the padding(s) for the specified side(s)
9623 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9624 * passing lr would get the padding (l)eft + the padding (r)ight.
9625 * @return {Number} The padding of the sides passed added together
9627 getPadding : function(side){
9628 return this.addStyles(side, El.paddings);
9632 * Set positioning with an object returned by getPositioning().
9633 * @param {Object} posCfg
9634 * @return {Roo.Element} this
9636 setPositioning : function(pc){
9637 this.applyStyles(pc);
9638 if(pc.right == "auto"){
9639 this.dom.style.right = "";
9641 if(pc.bottom == "auto"){
9642 this.dom.style.bottom = "";
9648 fixDisplay : function(){
9649 if(this.getStyle("display") == "none"){
9650 this.setStyle("visibility", "hidden");
9651 this.setStyle("display", this.originalDisplay); // first try reverting to default
9652 if(this.getStyle("display") == "none"){ // if that fails, default to block
9653 this.setStyle("display", "block");
9659 * Quick set left and top adding default units
9660 * @param {String} left The left CSS property value
9661 * @param {String} top The top CSS property value
9662 * @return {Roo.Element} this
9664 setLeftTop : function(left, top){
9665 this.dom.style.left = this.addUnits(left);
9666 this.dom.style.top = this.addUnits(top);
9671 * Move this element relative to its current position.
9672 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9673 * @param {Number} distance How far to move the element in pixels
9674 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9675 * @return {Roo.Element} this
9677 move : function(direction, distance, animate){
9678 var xy = this.getXY();
9679 direction = direction.toLowerCase();
9683 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
9687 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
9692 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
9697 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
9704 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
9705 * @return {Roo.Element} this
9708 if(!this.isClipped){
9709 this.isClipped = true;
9710 this.originalClip = {
9711 "o": this.getStyle("overflow"),
9712 "x": this.getStyle("overflow-x"),
9713 "y": this.getStyle("overflow-y")
9715 this.setStyle("overflow", "hidden");
9716 this.setStyle("overflow-x", "hidden");
9717 this.setStyle("overflow-y", "hidden");
9723 * Return clipping (overflow) to original clipping before clip() was called
9724 * @return {Roo.Element} this
9726 unclip : function(){
9728 this.isClipped = false;
9729 var o = this.originalClip;
9730 if(o.o){this.setStyle("overflow", o.o);}
9731 if(o.x){this.setStyle("overflow-x", o.x);}
9732 if(o.y){this.setStyle("overflow-y", o.y);}
9739 * Gets the x,y coordinates specified by the anchor position on the element.
9740 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
9741 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
9742 * {width: (target width), height: (target height)} (defaults to the element's current size)
9743 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
9744 * @return {Array} [x, y] An array containing the element's x and y coordinates
9746 getAnchorXY : function(anchor, local, s){
9747 //Passing a different size is useful for pre-calculating anchors,
9748 //especially for anchored animations that change the el size.
9750 var w, h, vp = false;
9753 if(d == document.body || d == document){
9755 w = D.getViewWidth(); h = D.getViewHeight();
9757 w = this.getWidth(); h = this.getHeight();
9760 w = s.width; h = s.height;
9762 var x = 0, y = 0, r = Math.round;
9763 switch((anchor || "tl").toLowerCase()){
9805 var sc = this.getScroll();
9806 return [x + sc.left, y + sc.top];
9808 //Add the element's offset xy
9809 var o = this.getXY();
9810 return [x+o[0], y+o[1]];
9814 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
9815 * supported position values.
9816 * @param {String/HTMLElement/Roo.Element} element The element to align to.
9817 * @param {String} position The position to align to.
9818 * @param {Array} offsets (optional) Offset the positioning by [x, y]
9819 * @return {Array} [x, y]
9821 getAlignToXY : function(el, p, o)
9826 throw "Element.alignTo with an element that doesn't exist";
9828 var c = false; //constrain to viewport
9829 var p1 = "", p2 = "";
9836 }else if(p.indexOf("-") == -1){
9839 p = p.toLowerCase();
9840 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
9842 throw "Element.alignTo with an invalid alignment " + p;
9844 p1 = m[1]; p2 = m[2]; c = !!m[3];
9846 //Subtract the aligned el's internal xy from the target's offset xy
9847 //plus custom offset to get the aligned el's new offset xy
9848 var a1 = this.getAnchorXY(p1, true);
9849 var a2 = el.getAnchorXY(p2, false);
9850 var x = a2[0] - a1[0] + o[0];
9851 var y = a2[1] - a1[1] + o[1];
9853 //constrain the aligned el to viewport if necessary
9854 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
9855 // 5px of margin for ie
9856 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
9858 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
9859 //perpendicular to the vp border, allow the aligned el to slide on that border,
9860 //otherwise swap the aligned el to the opposite border of the target.
9861 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
9862 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
9863 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t") );
9864 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
9867 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
9868 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
9870 if((x+w) > dw + scrollX){
9871 x = swapX ? r.left-w : dw+scrollX-w;
9874 x = swapX ? r.right : scrollX;
9876 if((y+h) > dh + scrollY){
9877 y = swapY ? r.top-h : dh+scrollY-h;
9880 y = swapY ? r.bottom : scrollY;
9887 getConstrainToXY : function(){
9888 var os = {top:0, left:0, bottom:0, right: 0};
9890 return function(el, local, offsets, proposedXY){
9892 offsets = offsets ? Roo.applyIf(offsets, os) : os;
9894 var vw, vh, vx = 0, vy = 0;
9895 if(el.dom == document.body || el.dom == document){
9896 vw = Roo.lib.Dom.getViewWidth();
9897 vh = Roo.lib.Dom.getViewHeight();
9899 vw = el.dom.clientWidth;
9900 vh = el.dom.clientHeight;
9902 var vxy = el.getXY();
9908 var s = el.getScroll();
9910 vx += offsets.left + s.left;
9911 vy += offsets.top + s.top;
9913 vw -= offsets.right;
9914 vh -= offsets.bottom;
9919 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
9920 var x = xy[0], y = xy[1];
9921 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
9923 // only move it if it needs it
9926 // first validate right/bottom
9935 // then make sure top/left isn't negative
9944 return moved ? [x, y] : false;
9949 adjustForConstraints : function(xy, parent, offsets){
9950 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
9954 * Aligns this element with another element relative to the specified anchor points. If the other element is the
9955 * document it aligns it to the viewport.
9956 * The position parameter is optional, and can be specified in any one of the following formats:
9958 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
9959 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
9960 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
9961 * deprecated in favor of the newer two anchor syntax below</i>.</li>
9962 * <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
9963 * element's anchor point, and the second value is used as the target's anchor point.</li>
9965 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
9966 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
9967 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
9968 * that specified in order to enforce the viewport constraints.
9969 * Following are all of the supported anchor positions:
9972 ----- -----------------------------
9973 tl The top left corner (default)
9974 t The center of the top edge
9975 tr The top right corner
9976 l The center of the left edge
9977 c In the center of the element
9978 r The center of the right edge
9979 bl The bottom left corner
9980 b The center of the bottom edge
9981 br The bottom right corner
9985 // align el to other-el using the default positioning ("tl-bl", non-constrained)
9986 el.alignTo("other-el");
9988 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
9989 el.alignTo("other-el", "tr?");
9991 // align the bottom right corner of el with the center left edge of other-el
9992 el.alignTo("other-el", "br-l?");
9994 // align the center of el with the bottom left corner of other-el and
9995 // adjust the x position by -6 pixels (and the y position by 0)
9996 el.alignTo("other-el", "c-bl", [-6, 0]);
9998 * @param {String/HTMLElement/Roo.Element} element The element to align to.
9999 * @param {String} position The position to align to.
10000 * @param {Array} offsets (optional) Offset the positioning by [x, y]
10001 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10002 * @return {Roo.Element} this
10004 alignTo : function(element, position, offsets, animate){
10005 var xy = this.getAlignToXY(element, position, offsets);
10006 this.setXY(xy, this.preanim(arguments, 3));
10011 * Anchors an element to another element and realigns it when the window is resized.
10012 * @param {String/HTMLElement/Roo.Element} element The element to align to.
10013 * @param {String} position The position to align to.
10014 * @param {Array} offsets (optional) Offset the positioning by [x, y]
10015 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
10016 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
10017 * is a number, it is used as the buffer delay (defaults to 50ms).
10018 * @param {Function} callback The function to call after the animation finishes
10019 * @return {Roo.Element} this
10021 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
10022 var action = function(){
10023 this.alignTo(el, alignment, offsets, animate);
10024 Roo.callback(callback, this);
10026 Roo.EventManager.onWindowResize(action, this);
10027 var tm = typeof monitorScroll;
10028 if(tm != 'undefined'){
10029 Roo.EventManager.on(window, 'scroll', action, this,
10030 {buffer: tm == 'number' ? monitorScroll : 50});
10032 action.call(this); // align immediately
10036 * Clears any opacity settings from this element. Required in some cases for IE.
10037 * @return {Roo.Element} this
10039 clearOpacity : function(){
10040 if (window.ActiveXObject) {
10041 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
10042 this.dom.style.filter = "";
10045 this.dom.style.opacity = "";
10046 this.dom.style["-moz-opacity"] = "";
10047 this.dom.style["-khtml-opacity"] = "";
10053 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
10054 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10055 * @return {Roo.Element} this
10057 hide : function(animate){
10058 this.setVisible(false, this.preanim(arguments, 0));
10063 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
10064 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10065 * @return {Roo.Element} this
10067 show : function(animate){
10068 this.setVisible(true, this.preanim(arguments, 0));
10073 * @private Test if size has a unit, otherwise appends the default
10075 addUnits : function(size){
10076 return Roo.Element.addUnits(size, this.defaultUnit);
10080 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
10081 * @return {Roo.Element} this
10083 beginMeasure : function(){
10085 if(el.offsetWidth || el.offsetHeight){
10086 return this; // offsets work already
10089 var p = this.dom, b = document.body; // start with this element
10090 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
10091 var pe = Roo.get(p);
10092 if(pe.getStyle('display') == 'none'){
10093 changed.push({el: p, visibility: pe.getStyle("visibility")});
10094 p.style.visibility = "hidden";
10095 p.style.display = "block";
10099 this._measureChanged = changed;
10105 * Restores displays to before beginMeasure was called
10106 * @return {Roo.Element} this
10108 endMeasure : function(){
10109 var changed = this._measureChanged;
10111 for(var i = 0, len = changed.length; i < len; i++) {
10112 var r = changed[i];
10113 r.el.style.visibility = r.visibility;
10114 r.el.style.display = "none";
10116 this._measureChanged = null;
10122 * Update the innerHTML of this element, optionally searching for and processing scripts
10123 * @param {String} html The new HTML
10124 * @param {Boolean} loadScripts (optional) true to look for and process scripts
10125 * @param {Function} callback For async script loading you can be noticed when the update completes
10126 * @return {Roo.Element} this
10128 update : function(html, loadScripts, callback){
10129 if(typeof html == "undefined"){
10132 if(loadScripts !== true){
10133 this.dom.innerHTML = html;
10134 if(typeof callback == "function"){
10140 var dom = this.dom;
10142 html += '<span id="' + id + '"></span>';
10144 E.onAvailable(id, function(){
10145 var hd = document.getElementsByTagName("head")[0];
10146 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
10147 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
10148 var typeRe = /\stype=([\'\"])(.*?)\1/i;
10151 while(match = re.exec(html)){
10152 var attrs = match[1];
10153 var srcMatch = attrs ? attrs.match(srcRe) : false;
10154 if(srcMatch && srcMatch[2]){
10155 var s = document.createElement("script");
10156 s.src = srcMatch[2];
10157 var typeMatch = attrs.match(typeRe);
10158 if(typeMatch && typeMatch[2]){
10159 s.type = typeMatch[2];
10162 }else if(match[2] && match[2].length > 0){
10163 if(window.execScript) {
10164 window.execScript(match[2]);
10172 window.eval(match[2]);
10176 var el = document.getElementById(id);
10177 if(el){el.parentNode.removeChild(el);}
10178 if(typeof callback == "function"){
10182 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
10187 * Direct access to the UpdateManager update() method (takes the same parameters).
10188 * @param {String/Function} url The url for this request or a function to call to get the url
10189 * @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}
10190 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
10191 * @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.
10192 * @return {Roo.Element} this
10195 var um = this.getUpdateManager();
10196 um.update.apply(um, arguments);
10201 * Gets this element's UpdateManager
10202 * @return {Roo.UpdateManager} The UpdateManager
10204 getUpdateManager : function(){
10205 if(!this.updateManager){
10206 this.updateManager = new Roo.UpdateManager(this);
10208 return this.updateManager;
10212 * Disables text selection for this element (normalized across browsers)
10213 * @return {Roo.Element} this
10215 unselectable : function(){
10216 this.dom.unselectable = "on";
10217 this.swallowEvent("selectstart", true);
10218 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
10219 this.addClass("x-unselectable");
10224 * Calculates the x, y to center this element on the screen
10225 * @return {Array} The x, y values [x, y]
10227 getCenterXY : function(){
10228 return this.getAlignToXY(document, 'c-c');
10232 * Centers the Element in either the viewport, or another Element.
10233 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
10235 center : function(centerIn){
10236 this.alignTo(centerIn || document, 'c-c');
10241 * Tests various css rules/browsers to determine if this element uses a border box
10242 * @return {Boolean}
10244 isBorderBox : function(){
10245 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
10249 * Return a box {x, y, width, height} that can be used to set another elements
10250 * size/location to match this element.
10251 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
10252 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
10253 * @return {Object} box An object in the format {x, y, width, height}
10255 getBox : function(contentBox, local){
10260 var left = parseInt(this.getStyle("left"), 10) || 0;
10261 var top = parseInt(this.getStyle("top"), 10) || 0;
10264 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
10266 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
10268 var l = this.getBorderWidth("l")+this.getPadding("l");
10269 var r = this.getBorderWidth("r")+this.getPadding("r");
10270 var t = this.getBorderWidth("t")+this.getPadding("t");
10271 var b = this.getBorderWidth("b")+this.getPadding("b");
10272 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)};
10274 bx.right = bx.x + bx.width;
10275 bx.bottom = bx.y + bx.height;
10280 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
10281 for more information about the sides.
10282 * @param {String} sides
10285 getFrameWidth : function(sides, onlyContentBox){
10286 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
10290 * 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.
10291 * @param {Object} box The box to fill {x, y, width, height}
10292 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
10293 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10294 * @return {Roo.Element} this
10296 setBox : function(box, adjust, animate){
10297 var w = box.width, h = box.height;
10298 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
10299 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
10300 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
10302 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
10307 * Forces the browser to repaint this element
10308 * @return {Roo.Element} this
10310 repaint : function(){
10311 var dom = this.dom;
10312 this.addClass("x-repaint");
10313 setTimeout(function(){
10314 Roo.get(dom).removeClass("x-repaint");
10320 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
10321 * then it returns the calculated width of the sides (see getPadding)
10322 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
10323 * @return {Object/Number}
10325 getMargins : function(side){
10328 top: parseInt(this.getStyle("margin-top"), 10) || 0,
10329 left: parseInt(this.getStyle("margin-left"), 10) || 0,
10330 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
10331 right: parseInt(this.getStyle("margin-right"), 10) || 0
10334 return this.addStyles(side, El.margins);
10339 addStyles : function(sides, styles){
10341 for(var i = 0, len = sides.length; i < len; i++){
10342 v = this.getStyle(styles[sides.charAt(i)]);
10344 w = parseInt(v, 10);
10352 * Creates a proxy element of this element
10353 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
10354 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
10355 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
10356 * @return {Roo.Element} The new proxy element
10358 createProxy : function(config, renderTo, matchBox){
10360 renderTo = Roo.getDom(renderTo);
10362 renderTo = document.body;
10364 config = typeof config == "object" ?
10365 config : {tag : "div", cls: config};
10366 var proxy = Roo.DomHelper.append(renderTo, config, true);
10368 proxy.setBox(this.getBox());
10374 * Puts a mask over this element to disable user interaction. Requires core.css.
10375 * This method can only be applied to elements which accept child nodes.
10376 * @param {String} msg (optional) A message to display in the mask
10377 * @param {String} msgCls (optional) A css class to apply to the msg element - use no-spinner to hide the spinner on bootstrap
10378 * @return {Element} The mask element
10380 mask : function(msg, msgCls)
10382 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
10383 this.setStyle("position", "relative");
10386 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
10389 this.addClass("x-masked");
10390 this._mask.setDisplayed(true);
10394 var dom = this.dom;
10395 while (dom && dom.style) {
10396 if (!isNaN(parseInt(dom.style.zIndex))) {
10397 z = Math.max(z, parseInt(dom.style.zIndex));
10399 dom = dom.parentNode;
10401 // if we are masking the body - then it hides everything..
10402 if (this.dom == document.body) {
10404 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
10405 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
10408 if(typeof msg == 'string'){
10409 if(!this._maskMsg){
10410 this._maskMsg = Roo.DomHelper.append(this.dom, {
10411 cls: "roo-el-mask-msg",
10415 cls: 'fa fa-spinner fa-spin'
10423 var mm = this._maskMsg;
10424 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
10425 if (mm.dom.lastChild) { // weird IE issue?
10426 mm.dom.lastChild.innerHTML = msg;
10428 mm.setDisplayed(true);
10430 mm.setStyle('z-index', z + 102);
10432 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
10433 this._mask.setHeight(this.getHeight());
10435 this._mask.setStyle('z-index', z + 100);
10441 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
10442 * it is cached for reuse.
10444 unmask : function(removeEl){
10446 if(removeEl === true){
10447 this._mask.remove();
10450 this._maskMsg.remove();
10451 delete this._maskMsg;
10454 this._mask.setDisplayed(false);
10456 this._maskMsg.setDisplayed(false);
10460 this.removeClass("x-masked");
10464 * Returns true if this element is masked
10465 * @return {Boolean}
10467 isMasked : function(){
10468 return this._mask && this._mask.isVisible();
10472 * Creates an iframe shim for this element to keep selects and other windowed objects from
10474 * @return {Roo.Element} The new shim element
10476 createShim : function(){
10477 var el = document.createElement('iframe');
10478 el.frameBorder = 'no';
10479 el.className = 'roo-shim';
10480 if(Roo.isIE && Roo.isSecure){
10481 el.src = Roo.SSL_SECURE_URL;
10483 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
10484 shim.autoBoxAdjust = false;
10489 * Removes this element from the DOM and deletes it from the cache
10491 remove : function(){
10492 if(this.dom.parentNode){
10493 this.dom.parentNode.removeChild(this.dom);
10495 delete El.cache[this.dom.id];
10499 * Sets up event handlers to add and remove a css class when the mouse is over this element
10500 * @param {String} className
10501 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
10502 * mouseout events for children elements
10503 * @return {Roo.Element} this
10505 addClassOnOver : function(className, preventFlicker){
10506 this.on("mouseover", function(){
10507 Roo.fly(this, '_internal').addClass(className);
10509 var removeFn = function(e){
10510 if(preventFlicker !== true || !e.within(this, true)){
10511 Roo.fly(this, '_internal').removeClass(className);
10514 this.on("mouseout", removeFn, this.dom);
10519 * Sets up event handlers to add and remove a css class when this element has the focus
10520 * @param {String} className
10521 * @return {Roo.Element} this
10523 addClassOnFocus : function(className){
10524 this.on("focus", function(){
10525 Roo.fly(this, '_internal').addClass(className);
10527 this.on("blur", function(){
10528 Roo.fly(this, '_internal').removeClass(className);
10533 * 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)
10534 * @param {String} className
10535 * @return {Roo.Element} this
10537 addClassOnClick : function(className){
10538 var dom = this.dom;
10539 this.on("mousedown", function(){
10540 Roo.fly(dom, '_internal').addClass(className);
10541 var d = Roo.get(document);
10542 var fn = function(){
10543 Roo.fly(dom, '_internal').removeClass(className);
10544 d.removeListener("mouseup", fn);
10546 d.on("mouseup", fn);
10552 * Stops the specified event from bubbling and optionally prevents the default action
10553 * @param {String} eventName
10554 * @param {Boolean} preventDefault (optional) true to prevent the default action too
10555 * @return {Roo.Element} this
10557 swallowEvent : function(eventName, preventDefault){
10558 var fn = function(e){
10559 e.stopPropagation();
10560 if(preventDefault){
10561 e.preventDefault();
10564 if(eventName instanceof Array){
10565 for(var i = 0, len = eventName.length; i < len; i++){
10566 this.on(eventName[i], fn);
10570 this.on(eventName, fn);
10577 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
10580 * Sizes this element to its parent element's dimensions performing
10581 * neccessary box adjustments.
10582 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
10583 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
10584 * @return {Roo.Element} this
10586 fitToParent : function(monitorResize, targetParent) {
10587 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
10588 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
10589 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
10592 var p = Roo.get(targetParent || this.dom.parentNode);
10593 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
10594 if (monitorResize === true) {
10595 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
10596 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
10602 * Gets the next sibling, skipping text nodes
10603 * @return {HTMLElement} The next sibling or null
10605 getNextSibling : function(){
10606 var n = this.dom.nextSibling;
10607 while(n && n.nodeType != 1){
10614 * Gets the previous sibling, skipping text nodes
10615 * @return {HTMLElement} The previous sibling or null
10617 getPrevSibling : function(){
10618 var n = this.dom.previousSibling;
10619 while(n && n.nodeType != 1){
10620 n = n.previousSibling;
10627 * Appends the passed element(s) to this element
10628 * @param {String/HTMLElement/Array/Element/CompositeElement} el
10629 * @return {Roo.Element} this
10631 appendChild: function(el){
10638 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
10639 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
10640 * automatically generated with the specified attributes.
10641 * @param {HTMLElement} insertBefore (optional) a child element of this element
10642 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
10643 * @return {Roo.Element} The new child element
10645 createChild: function(config, insertBefore, returnDom){
10646 config = config || {tag:'div'};
10648 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
10650 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
10654 * Appends this element to the passed element
10655 * @param {String/HTMLElement/Element} el The new parent element
10656 * @return {Roo.Element} this
10658 appendTo: function(el){
10659 el = Roo.getDom(el);
10660 el.appendChild(this.dom);
10665 * Inserts this element before the passed element in the DOM
10666 * @param {String/HTMLElement/Element} el The element to insert before
10667 * @return {Roo.Element} this
10669 insertBefore: function(el){
10670 el = Roo.getDom(el);
10671 el.parentNode.insertBefore(this.dom, el);
10676 * Inserts this element after the passed element in the DOM
10677 * @param {String/HTMLElement/Element} el The element to insert after
10678 * @return {Roo.Element} this
10680 insertAfter: function(el){
10681 el = Roo.getDom(el);
10682 el.parentNode.insertBefore(this.dom, el.nextSibling);
10687 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
10688 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10689 * @return {Roo.Element} The new child
10691 insertFirst: function(el, returnDom){
10693 if(typeof el == 'object' && !el.nodeType){ // dh config
10694 return this.createChild(el, this.dom.firstChild, returnDom);
10696 el = Roo.getDom(el);
10697 this.dom.insertBefore(el, this.dom.firstChild);
10698 return !returnDom ? Roo.get(el) : el;
10703 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
10704 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10705 * @param {String} where (optional) 'before' or 'after' defaults to before
10706 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10707 * @return {Roo.Element} the inserted Element
10709 insertSibling: function(el, where, returnDom){
10710 where = where ? where.toLowerCase() : 'before';
10712 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
10714 if(typeof el == 'object' && !el.nodeType){ // dh config
10715 if(where == 'after' && !this.dom.nextSibling){
10716 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
10718 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
10722 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
10723 where == 'before' ? this.dom : this.dom.nextSibling);
10732 * Creates and wraps this element with another element
10733 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
10734 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10735 * @return {HTMLElement/Element} The newly created wrapper element
10737 wrap: function(config, returnDom){
10739 config = {tag: "div"};
10741 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
10742 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
10747 * Replaces the passed element with this element
10748 * @param {String/HTMLElement/Element} el The element to replace
10749 * @return {Roo.Element} this
10751 replace: function(el){
10753 this.insertBefore(el);
10759 * Inserts an html fragment into this element
10760 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
10761 * @param {String} html The HTML fragment
10762 * @param {Boolean} returnEl True to return an Roo.Element
10763 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
10765 insertHtml : function(where, html, returnEl){
10766 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
10767 return returnEl ? Roo.get(el) : el;
10771 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
10772 * @param {Object} o The object with the attributes
10773 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
10774 * @return {Roo.Element} this
10776 set : function(o, useSet){
10778 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
10779 for(var attr in o){
10780 if(attr == "style" || typeof o[attr] == "function") { continue; }
10782 el.className = o["cls"];
10785 el.setAttribute(attr, o[attr]);
10787 el[attr] = o[attr];
10792 Roo.DomHelper.applyStyles(el, o.style);
10798 * Convenience method for constructing a KeyMap
10799 * @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:
10800 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
10801 * @param {Function} fn The function to call
10802 * @param {Object} scope (optional) The scope of the function
10803 * @return {Roo.KeyMap} The KeyMap created
10805 addKeyListener : function(key, fn, scope){
10807 if(typeof key != "object" || key instanceof Array){
10823 return new Roo.KeyMap(this, config);
10827 * Creates a KeyMap for this element
10828 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
10829 * @return {Roo.KeyMap} The KeyMap created
10831 addKeyMap : function(config){
10832 return new Roo.KeyMap(this, config);
10836 * Returns true if this element is scrollable.
10837 * @return {Boolean}
10839 isScrollable : function(){
10840 var dom = this.dom;
10841 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
10845 * 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().
10846 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
10847 * @param {Number} value The new scroll value
10848 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10849 * @return {Element} this
10852 scrollTo : function(side, value, animate){
10853 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
10854 if(!animate || !A){
10855 this.dom[prop] = value;
10857 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
10858 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
10864 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
10865 * within this element's scrollable range.
10866 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
10867 * @param {Number} distance How far to scroll the element in pixels
10868 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10869 * @return {Boolean} Returns true if a scroll was triggered or false if the element
10870 * was scrolled as far as it could go.
10872 scroll : function(direction, distance, animate){
10873 if(!this.isScrollable()){
10877 var l = el.scrollLeft, t = el.scrollTop;
10878 var w = el.scrollWidth, h = el.scrollHeight;
10879 var cw = el.clientWidth, ch = el.clientHeight;
10880 direction = direction.toLowerCase();
10881 var scrolled = false;
10882 var a = this.preanim(arguments, 2);
10887 var v = Math.min(l + distance, w-cw);
10888 this.scrollTo("left", v, a);
10895 var v = Math.max(l - distance, 0);
10896 this.scrollTo("left", v, a);
10904 var v = Math.max(t - distance, 0);
10905 this.scrollTo("top", v, a);
10913 var v = Math.min(t + distance, h-ch);
10914 this.scrollTo("top", v, a);
10923 * Translates the passed page coordinates into left/top css values for this element
10924 * @param {Number/Array} x The page x or an array containing [x, y]
10925 * @param {Number} y The page y
10926 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
10928 translatePoints : function(x, y){
10929 if(typeof x == 'object' || x instanceof Array){
10930 y = x[1]; x = x[0];
10932 var p = this.getStyle('position');
10933 var o = this.getXY();
10935 var l = parseInt(this.getStyle('left'), 10);
10936 var t = parseInt(this.getStyle('top'), 10);
10939 l = (p == "relative") ? 0 : this.dom.offsetLeft;
10942 t = (p == "relative") ? 0 : this.dom.offsetTop;
10945 return {left: (x - o[0] + l), top: (y - o[1] + t)};
10949 * Returns the current scroll position of the element.
10950 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
10952 getScroll : function(){
10953 var d = this.dom, doc = document;
10954 if(d == doc || d == doc.body){
10955 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
10956 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
10957 return {left: l, top: t};
10959 return {left: d.scrollLeft, top: d.scrollTop};
10964 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
10965 * are convert to standard 6 digit hex color.
10966 * @param {String} attr The css attribute
10967 * @param {String} defaultValue The default value to use when a valid color isn't found
10968 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
10971 getColor : function(attr, defaultValue, prefix){
10972 var v = this.getStyle(attr);
10973 if(!v || v == "transparent" || v == "inherit") {
10974 return defaultValue;
10976 var color = typeof prefix == "undefined" ? "#" : prefix;
10977 if(v.substr(0, 4) == "rgb("){
10978 var rvs = v.slice(4, v.length -1).split(",");
10979 for(var i = 0; i < 3; i++){
10980 var h = parseInt(rvs[i]).toString(16);
10987 if(v.substr(0, 1) == "#"){
10988 if(v.length == 4) {
10989 for(var i = 1; i < 4; i++){
10990 var c = v.charAt(i);
10993 }else if(v.length == 7){
10994 color += v.substr(1);
10998 return(color.length > 5 ? color.toLowerCase() : defaultValue);
11002 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
11003 * gradient background, rounded corners and a 4-way shadow.
11004 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
11005 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
11006 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
11007 * @return {Roo.Element} this
11009 boxWrap : function(cls){
11010 cls = cls || 'x-box';
11011 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
11012 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
11017 * Returns the value of a namespaced attribute from the element's underlying DOM node.
11018 * @param {String} namespace The namespace in which to look for the attribute
11019 * @param {String} name The attribute name
11020 * @return {String} The attribute value
11022 getAttributeNS : Roo.isIE ? function(ns, name){
11024 var type = typeof d[ns+":"+name];
11025 if(type != 'undefined' && type != 'unknown'){
11026 return d[ns+":"+name];
11029 } : function(ns, name){
11031 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
11036 * Sets or Returns the value the dom attribute value
11037 * @param {String|Object} name The attribute name (or object to set multiple attributes)
11038 * @param {String} value (optional) The value to set the attribute to
11039 * @return {String} The attribute value
11041 attr : function(name){
11042 if (arguments.length > 1) {
11043 this.dom.setAttribute(name, arguments[1]);
11044 return arguments[1];
11046 if (typeof(name) == 'object') {
11047 for(var i in name) {
11048 this.attr(i, name[i]);
11054 if (!this.dom.hasAttribute(name)) {
11057 return this.dom.getAttribute(name);
11064 var ep = El.prototype;
11067 * Appends an event handler (Shorthand for addListener)
11068 * @param {String} eventName The type of event to append
11069 * @param {Function} fn The method the event invokes
11070 * @param {Object} scope (optional) The scope (this object) of the fn
11071 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
11074 ep.on = ep.addListener;
11075 // backwards compat
11076 ep.mon = ep.addListener;
11079 * Removes an event handler from this element (shorthand for removeListener)
11080 * @param {String} eventName the type of event to remove
11081 * @param {Function} fn the method the event invokes
11082 * @return {Roo.Element} this
11085 ep.un = ep.removeListener;
11088 * true to automatically adjust width and height settings for box-model issues (default to true)
11090 ep.autoBoxAdjust = true;
11093 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
11096 El.addUnits = function(v, defaultUnit){
11097 if(v === "" || v == "auto"){
11100 if(v === undefined){
11103 if(typeof v == "number" || !El.unitPattern.test(v)){
11104 return v + (defaultUnit || 'px');
11109 // special markup used throughout Roo when box wrapping elements
11110 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>';
11112 * Visibility mode constant - Use visibility to hide element
11118 * Visibility mode constant - Use display to hide element
11124 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
11125 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
11126 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
11138 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
11139 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
11140 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
11141 * @return {Element} The Element object
11144 El.get = function(el){
11146 if(!el){ return null; }
11147 if(typeof el == "string"){ // element id
11148 if(!(elm = document.getElementById(el))){
11151 if(ex = El.cache[el]){
11154 ex = El.cache[el] = new El(elm);
11157 }else if(el.tagName){ // dom element
11161 if(ex = El.cache[id]){
11164 ex = El.cache[id] = new El(el);
11167 }else if(el instanceof El){
11169 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
11170 // catch case where it hasn't been appended
11171 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
11174 }else if(el.isComposite){
11176 }else if(el instanceof Array){
11177 return El.select(el);
11178 }else if(el == document){
11179 // create a bogus element object representing the document object
11181 var f = function(){};
11182 f.prototype = El.prototype;
11184 docEl.dom = document;
11192 El.uncache = function(el){
11193 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
11195 delete El.cache[a[i].id || a[i]];
11201 // Garbage collection - uncache elements/purge listeners on orphaned elements
11202 // so we don't hold a reference and cause the browser to retain them
11203 El.garbageCollect = function(){
11204 if(!Roo.enableGarbageCollector){
11205 clearInterval(El.collectorThread);
11208 for(var eid in El.cache){
11209 var el = El.cache[eid], d = el.dom;
11210 // -------------------------------------------------------
11211 // Determining what is garbage:
11212 // -------------------------------------------------------
11214 // dom node is null, definitely garbage
11215 // -------------------------------------------------------
11217 // no parentNode == direct orphan, definitely garbage
11218 // -------------------------------------------------------
11219 // !d.offsetParent && !document.getElementById(eid)
11220 // display none elements have no offsetParent so we will
11221 // also try to look it up by it's id. However, check
11222 // offsetParent first so we don't do unneeded lookups.
11223 // This enables collection of elements that are not orphans
11224 // directly, but somewhere up the line they have an orphan
11226 // -------------------------------------------------------
11227 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
11228 delete El.cache[eid];
11229 if(d && Roo.enableListenerCollection){
11235 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
11239 El.Flyweight = function(dom){
11242 El.Flyweight.prototype = El.prototype;
11244 El._flyweights = {};
11246 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
11247 * the dom node can be overwritten by other code.
11248 * @param {String/HTMLElement} el The dom node or id
11249 * @param {String} named (optional) Allows for creation of named reusable flyweights to
11250 * prevent conflicts (e.g. internally Roo uses "_internal")
11252 * @return {Element} The shared Element object
11254 El.fly = function(el, named){
11255 named = named || '_global';
11256 el = Roo.getDom(el);
11260 if(!El._flyweights[named]){
11261 El._flyweights[named] = new El.Flyweight();
11263 El._flyweights[named].dom = el;
11264 return El._flyweights[named];
11268 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
11269 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
11270 * Shorthand of {@link Roo.Element#get}
11271 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
11272 * @return {Element} The Element object
11278 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
11279 * the dom node can be overwritten by other code.
11280 * Shorthand of {@link Roo.Element#fly}
11281 * @param {String/HTMLElement} el The dom node or id
11282 * @param {String} named (optional) Allows for creation of named reusable flyweights to
11283 * prevent conflicts (e.g. internally Roo uses "_internal")
11285 * @return {Element} The shared Element object
11291 // speedy lookup for elements never to box adjust
11292 var noBoxAdjust = Roo.isStrict ? {
11295 input:1, select:1, textarea:1
11297 if(Roo.isIE || Roo.isGecko){
11298 noBoxAdjust['button'] = 1;
11302 Roo.EventManager.on(window, 'unload', function(){
11304 delete El._flyweights;
11312 Roo.Element.selectorFunction = Roo.DomQuery.select;
11315 Roo.Element.select = function(selector, unique, root){
11317 if(typeof selector == "string"){
11318 els = Roo.Element.selectorFunction(selector, root);
11319 }else if(selector.length !== undefined){
11322 throw "Invalid selector";
11324 if(unique === true){
11325 return new Roo.CompositeElement(els);
11327 return new Roo.CompositeElementLite(els);
11331 * Selects elements based on the passed CSS selector to enable working on them as 1.
11332 * @param {String/Array} selector The CSS selector or an array of elements
11333 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
11334 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
11335 * @return {CompositeElementLite/CompositeElement}
11339 Roo.select = Roo.Element.select;
11356 * Ext JS Library 1.1.1
11357 * Copyright(c) 2006-2007, Ext JS, LLC.
11359 * Originally Released Under LGPL - original licence link has changed is not relivant.
11362 * <script type="text/javascript">
11367 //Notifies Element that fx methods are available
11368 Roo.enableFx = true;
11372 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
11373 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
11374 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
11375 * Element effects to work.</p><br/>
11377 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
11378 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
11379 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
11380 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
11381 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
11382 * expected results and should be done with care.</p><br/>
11384 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
11385 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
11388 ----- -----------------------------
11389 tl The top left corner
11390 t The center of the top edge
11391 tr The top right corner
11392 l The center of the left edge
11393 r The center of the right edge
11394 bl The bottom left corner
11395 b The center of the bottom edge
11396 br The bottom right corner
11398 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
11399 * below are common options that can be passed to any Fx method.</b>
11400 * @cfg {Function} callback A function called when the effect is finished
11401 * @cfg {Object} scope The scope of the effect function
11402 * @cfg {String} easing A valid Easing value for the effect
11403 * @cfg {String} afterCls A css class to apply after the effect
11404 * @cfg {Number} duration The length of time (in seconds) that the effect should last
11405 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
11406 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
11407 * effects that end with the element being visually hidden, ignored otherwise)
11408 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
11409 * a function which returns such a specification that will be applied to the Element after the effect finishes
11410 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
11411 * @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
11412 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
11416 * Slides the element into view. An anchor point can be optionally passed to set the point of
11417 * origin for the slide effect. This function automatically handles wrapping the element with
11418 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
11421 // default: slide the element in from the top
11424 // custom: slide the element in from the right with a 2-second duration
11425 el.slideIn('r', { duration: 2 });
11427 // common config options shown with default values
11433 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11434 * @param {Object} options (optional) Object literal with any of the Fx config options
11435 * @return {Roo.Element} The Element
11437 slideIn : function(anchor, o){
11438 var el = this.getFxEl();
11441 el.queueFx(o, function(){
11443 anchor = anchor || "t";
11445 // fix display to visibility
11448 // restore values after effect
11449 var r = this.getFxRestore();
11450 var b = this.getBox();
11451 // fixed size for slide
11455 var wrap = this.fxWrap(r.pos, o, "hidden");
11457 var st = this.dom.style;
11458 st.visibility = "visible";
11459 st.position = "absolute";
11461 // clear out temp styles after slide and unwrap
11462 var after = function(){
11463 el.fxUnwrap(wrap, r.pos, o);
11464 st.width = r.width;
11465 st.height = r.height;
11468 // time to calc the positions
11469 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
11471 switch(anchor.toLowerCase()){
11473 wrap.setSize(b.width, 0);
11474 st.left = st.bottom = "0";
11478 wrap.setSize(0, b.height);
11479 st.right = st.top = "0";
11483 wrap.setSize(0, b.height);
11484 wrap.setX(b.right);
11485 st.left = st.top = "0";
11486 a = {width: bw, points: pt};
11489 wrap.setSize(b.width, 0);
11490 wrap.setY(b.bottom);
11491 st.left = st.top = "0";
11492 a = {height: bh, points: pt};
11495 wrap.setSize(0, 0);
11496 st.right = st.bottom = "0";
11497 a = {width: bw, height: bh};
11500 wrap.setSize(0, 0);
11501 wrap.setY(b.y+b.height);
11502 st.right = st.top = "0";
11503 a = {width: bw, height: bh, points: pt};
11506 wrap.setSize(0, 0);
11507 wrap.setXY([b.right, b.bottom]);
11508 st.left = st.top = "0";
11509 a = {width: bw, height: bh, points: pt};
11512 wrap.setSize(0, 0);
11513 wrap.setX(b.x+b.width);
11514 st.left = st.bottom = "0";
11515 a = {width: bw, height: bh, points: pt};
11518 this.dom.style.visibility = "visible";
11521 arguments.callee.anim = wrap.fxanim(a,
11531 * Slides the element out of view. An anchor point can be optionally passed to set the end point
11532 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
11533 * 'hidden') but block elements will still take up space in the document. The element must be removed
11534 * from the DOM using the 'remove' config option if desired. This function automatically handles
11535 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
11538 // default: slide the element out to the top
11541 // custom: slide the element out to the right with a 2-second duration
11542 el.slideOut('r', { duration: 2 });
11544 // common config options shown with default values
11552 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11553 * @param {Object} options (optional) Object literal with any of the Fx config options
11554 * @return {Roo.Element} The Element
11556 slideOut : function(anchor, o){
11557 var el = this.getFxEl();
11560 el.queueFx(o, function(){
11562 anchor = anchor || "t";
11564 // restore values after effect
11565 var r = this.getFxRestore();
11567 var b = this.getBox();
11568 // fixed size for slide
11572 var wrap = this.fxWrap(r.pos, o, "visible");
11574 var st = this.dom.style;
11575 st.visibility = "visible";
11576 st.position = "absolute";
11580 var after = function(){
11582 el.setDisplayed(false);
11587 el.fxUnwrap(wrap, r.pos, o);
11589 st.width = r.width;
11590 st.height = r.height;
11595 var a, zero = {to: 0};
11596 switch(anchor.toLowerCase()){
11598 st.left = st.bottom = "0";
11599 a = {height: zero};
11602 st.right = st.top = "0";
11606 st.left = st.top = "0";
11607 a = {width: zero, points: {to:[b.right, b.y]}};
11610 st.left = st.top = "0";
11611 a = {height: zero, points: {to:[b.x, b.bottom]}};
11614 st.right = st.bottom = "0";
11615 a = {width: zero, height: zero};
11618 st.right = st.top = "0";
11619 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
11622 st.left = st.top = "0";
11623 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
11626 st.left = st.bottom = "0";
11627 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
11631 arguments.callee.anim = wrap.fxanim(a,
11641 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
11642 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
11643 * The element must be removed from the DOM using the 'remove' config option if desired.
11649 // common config options shown with default values
11657 * @param {Object} options (optional) Object literal with any of the Fx config options
11658 * @return {Roo.Element} The Element
11660 puff : function(o){
11661 var el = this.getFxEl();
11664 el.queueFx(o, function(){
11665 this.clearOpacity();
11668 // restore values after effect
11669 var r = this.getFxRestore();
11670 var st = this.dom.style;
11672 var after = function(){
11674 el.setDisplayed(false);
11681 el.setPositioning(r.pos);
11682 st.width = r.width;
11683 st.height = r.height;
11688 var width = this.getWidth();
11689 var height = this.getHeight();
11691 arguments.callee.anim = this.fxanim({
11692 width : {to: this.adjustWidth(width * 2)},
11693 height : {to: this.adjustHeight(height * 2)},
11694 points : {by: [-(width * .5), -(height * .5)]},
11696 fontSize: {to:200, unit: "%"}
11707 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
11708 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
11709 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
11715 // all config options shown with default values
11723 * @param {Object} options (optional) Object literal with any of the Fx config options
11724 * @return {Roo.Element} The Element
11726 switchOff : function(o){
11727 var el = this.getFxEl();
11730 el.queueFx(o, function(){
11731 this.clearOpacity();
11734 // restore values after effect
11735 var r = this.getFxRestore();
11736 var st = this.dom.style;
11738 var after = function(){
11740 el.setDisplayed(false);
11746 el.setPositioning(r.pos);
11747 st.width = r.width;
11748 st.height = r.height;
11753 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
11754 this.clearOpacity();
11758 points:{by:[0, this.getHeight() * .5]}
11759 }, o, 'motion', 0.3, 'easeIn', after);
11760 }).defer(100, this);
11767 * Highlights the Element by setting a color (applies to the background-color by default, but can be
11768 * changed using the "attr" config option) and then fading back to the original color. If no original
11769 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
11772 // default: highlight background to yellow
11775 // custom: highlight foreground text to blue for 2 seconds
11776 el.highlight("0000ff", { attr: 'color', duration: 2 });
11778 // common config options shown with default values
11779 el.highlight("ffff9c", {
11780 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
11781 endColor: (current color) or "ffffff",
11786 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
11787 * @param {Object} options (optional) Object literal with any of the Fx config options
11788 * @return {Roo.Element} The Element
11790 highlight : function(color, o){
11791 var el = this.getFxEl();
11794 el.queueFx(o, function(){
11795 color = color || "ffff9c";
11796 attr = o.attr || "backgroundColor";
11798 this.clearOpacity();
11801 var origColor = this.getColor(attr);
11802 var restoreColor = this.dom.style[attr];
11803 endColor = (o.endColor || origColor) || "ffffff";
11805 var after = function(){
11806 el.dom.style[attr] = restoreColor;
11811 a[attr] = {from: color, to: endColor};
11812 arguments.callee.anim = this.fxanim(a,
11822 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
11825 // default: a single light blue ripple
11828 // custom: 3 red ripples lasting 3 seconds total
11829 el.frame("ff0000", 3, { duration: 3 });
11831 // common config options shown with default values
11832 el.frame("C3DAF9", 1, {
11833 duration: 1 //duration of entire animation (not each individual ripple)
11834 // Note: Easing is not configurable and will be ignored if included
11837 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
11838 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
11839 * @param {Object} options (optional) Object literal with any of the Fx config options
11840 * @return {Roo.Element} The Element
11842 frame : function(color, count, o){
11843 var el = this.getFxEl();
11846 el.queueFx(o, function(){
11847 color = color || "#C3DAF9";
11848 if(color.length == 6){
11849 color = "#" + color;
11851 count = count || 1;
11852 duration = o.duration || 1;
11855 var b = this.getBox();
11856 var animFn = function(){
11857 var proxy = this.createProxy({
11860 visbility:"hidden",
11861 position:"absolute",
11862 "z-index":"35000", // yee haw
11863 border:"0px solid " + color
11866 var scale = Roo.isBorderBox ? 2 : 1;
11868 top:{from:b.y, to:b.y - 20},
11869 left:{from:b.x, to:b.x - 20},
11870 borderWidth:{from:0, to:10},
11871 opacity:{from:1, to:0},
11872 height:{from:b.height, to:(b.height + (20*scale))},
11873 width:{from:b.width, to:(b.width + (20*scale))}
11874 }, duration, function(){
11878 animFn.defer((duration/2)*1000, this);
11889 * Creates a pause before any subsequent queued effects begin. If there are
11890 * no effects queued after the pause it will have no effect.
11895 * @param {Number} seconds The length of time to pause (in seconds)
11896 * @return {Roo.Element} The Element
11898 pause : function(seconds){
11899 var el = this.getFxEl();
11902 el.queueFx(o, function(){
11903 setTimeout(function(){
11905 }, seconds * 1000);
11911 * Fade an element in (from transparent to opaque). The ending opacity can be specified
11912 * using the "endOpacity" config option.
11915 // default: fade in from opacity 0 to 100%
11918 // custom: fade in from opacity 0 to 75% over 2 seconds
11919 el.fadeIn({ endOpacity: .75, duration: 2});
11921 // common config options shown with default values
11923 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
11928 * @param {Object} options (optional) Object literal with any of the Fx config options
11929 * @return {Roo.Element} The Element
11931 fadeIn : function(o){
11932 var el = this.getFxEl();
11934 el.queueFx(o, function(){
11935 this.setOpacity(0);
11937 this.dom.style.visibility = 'visible';
11938 var to = o.endOpacity || 1;
11939 arguments.callee.anim = this.fxanim({opacity:{to:to}},
11940 o, null, .5, "easeOut", function(){
11942 this.clearOpacity();
11951 * Fade an element out (from opaque to transparent). The ending opacity can be specified
11952 * using the "endOpacity" config option.
11955 // default: fade out from the element's current opacity to 0
11958 // custom: fade out from the element's current opacity to 25% over 2 seconds
11959 el.fadeOut({ endOpacity: .25, duration: 2});
11961 // common config options shown with default values
11963 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
11970 * @param {Object} options (optional) Object literal with any of the Fx config options
11971 * @return {Roo.Element} The Element
11973 fadeOut : function(o){
11974 var el = this.getFxEl();
11976 el.queueFx(o, function(){
11977 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
11978 o, null, .5, "easeOut", function(){
11979 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
11980 this.dom.style.display = "none";
11982 this.dom.style.visibility = "hidden";
11984 this.clearOpacity();
11992 * Animates the transition of an element's dimensions from a starting height/width
11993 * to an ending height/width.
11996 // change height and width to 100x100 pixels
11997 el.scale(100, 100);
11999 // common config options shown with default values. The height and width will default to
12000 // the element's existing values if passed as null.
12003 [element's height], {
12008 * @param {Number} width The new width (pass undefined to keep the original width)
12009 * @param {Number} height The new height (pass undefined to keep the original height)
12010 * @param {Object} options (optional) Object literal with any of the Fx config options
12011 * @return {Roo.Element} The Element
12013 scale : function(w, h, o){
12014 this.shift(Roo.apply({}, o, {
12022 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
12023 * Any of these properties not specified in the config object will not be changed. This effect
12024 * requires that at least one new dimension, position or opacity setting must be passed in on
12025 * the config object in order for the function to have any effect.
12028 // slide the element horizontally to x position 200 while changing the height and opacity
12029 el.shift({ x: 200, height: 50, opacity: .8 });
12031 // common config options shown with default values.
12033 width: [element's width],
12034 height: [element's height],
12035 x: [element's x position],
12036 y: [element's y position],
12037 opacity: [element's opacity],
12042 * @param {Object} options Object literal with any of the Fx config options
12043 * @return {Roo.Element} The Element
12045 shift : function(o){
12046 var el = this.getFxEl();
12048 el.queueFx(o, function(){
12049 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
12050 if(w !== undefined){
12051 a.width = {to: this.adjustWidth(w)};
12053 if(h !== undefined){
12054 a.height = {to: this.adjustHeight(h)};
12056 if(x !== undefined || y !== undefined){
12058 x !== undefined ? x : this.getX(),
12059 y !== undefined ? y : this.getY()
12062 if(op !== undefined){
12063 a.opacity = {to: op};
12065 if(o.xy !== undefined){
12066 a.points = {to: o.xy};
12068 arguments.callee.anim = this.fxanim(a,
12069 o, 'motion', .35, "easeOut", function(){
12077 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
12078 * ending point of the effect.
12081 // default: slide the element downward while fading out
12084 // custom: slide the element out to the right with a 2-second duration
12085 el.ghost('r', { duration: 2 });
12087 // common config options shown with default values
12095 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
12096 * @param {Object} options (optional) Object literal with any of the Fx config options
12097 * @return {Roo.Element} The Element
12099 ghost : function(anchor, o){
12100 var el = this.getFxEl();
12103 el.queueFx(o, function(){
12104 anchor = anchor || "b";
12106 // restore values after effect
12107 var r = this.getFxRestore();
12108 var w = this.getWidth(),
12109 h = this.getHeight();
12111 var st = this.dom.style;
12113 var after = function(){
12115 el.setDisplayed(false);
12121 el.setPositioning(r.pos);
12122 st.width = r.width;
12123 st.height = r.height;
12128 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
12129 switch(anchor.toLowerCase()){
12156 arguments.callee.anim = this.fxanim(a,
12166 * Ensures that all effects queued after syncFx is called on the element are
12167 * run concurrently. This is the opposite of {@link #sequenceFx}.
12168 * @return {Roo.Element} The Element
12170 syncFx : function(){
12171 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
12180 * Ensures that all effects queued after sequenceFx is called on the element are
12181 * run in sequence. This is the opposite of {@link #syncFx}.
12182 * @return {Roo.Element} The Element
12184 sequenceFx : function(){
12185 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
12187 concurrent : false,
12194 nextFx : function(){
12195 var ef = this.fxQueue[0];
12202 * Returns true if the element has any effects actively running or queued, else returns false.
12203 * @return {Boolean} True if element has active effects, else false
12205 hasActiveFx : function(){
12206 return this.fxQueue && this.fxQueue[0];
12210 * Stops any running effects and clears the element's internal effects queue if it contains
12211 * any additional effects that haven't started yet.
12212 * @return {Roo.Element} The Element
12214 stopFx : function(){
12215 if(this.hasActiveFx()){
12216 var cur = this.fxQueue[0];
12217 if(cur && cur.anim && cur.anim.isAnimated()){
12218 this.fxQueue = [cur]; // clear out others
12219 cur.anim.stop(true);
12226 beforeFx : function(o){
12227 if(this.hasActiveFx() && !o.concurrent){
12238 * Returns true if the element is currently blocking so that no other effect can be queued
12239 * until this effect is finished, else returns false if blocking is not set. This is commonly
12240 * used to ensure that an effect initiated by a user action runs to completion prior to the
12241 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
12242 * @return {Boolean} True if blocking, else false
12244 hasFxBlock : function(){
12245 var q = this.fxQueue;
12246 return q && q[0] && q[0].block;
12250 queueFx : function(o, fn){
12254 if(!this.hasFxBlock()){
12255 Roo.applyIf(o, this.fxDefaults);
12257 var run = this.beforeFx(o);
12258 fn.block = o.block;
12259 this.fxQueue.push(fn);
12271 fxWrap : function(pos, o, vis){
12273 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
12276 wrapXY = this.getXY();
12278 var div = document.createElement("div");
12279 div.style.visibility = vis;
12280 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
12281 wrap.setPositioning(pos);
12282 if(wrap.getStyle("position") == "static"){
12283 wrap.position("relative");
12285 this.clearPositioning('auto');
12287 wrap.dom.appendChild(this.dom);
12289 wrap.setXY(wrapXY);
12296 fxUnwrap : function(wrap, pos, o){
12297 this.clearPositioning();
12298 this.setPositioning(pos);
12300 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
12306 getFxRestore : function(){
12307 var st = this.dom.style;
12308 return {pos: this.getPositioning(), width: st.width, height : st.height};
12312 afterFx : function(o){
12314 this.applyStyles(o.afterStyle);
12317 this.addClass(o.afterCls);
12319 if(o.remove === true){
12322 Roo.callback(o.callback, o.scope, [this]);
12324 this.fxQueue.shift();
12330 getFxEl : function(){ // support for composite element fx
12331 return Roo.get(this.dom);
12335 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
12336 animType = animType || 'run';
12338 var anim = Roo.lib.Anim[animType](
12340 (opt.duration || defaultDur) || .35,
12341 (opt.easing || defaultEase) || 'easeOut',
12343 Roo.callback(cb, this);
12352 // backwords compat
12353 Roo.Fx.resize = Roo.Fx.scale;
12355 //When included, Roo.Fx is automatically applied to Element so that all basic
12356 //effects are available directly via the Element API
12357 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
12359 * Ext JS Library 1.1.1
12360 * Copyright(c) 2006-2007, Ext JS, LLC.
12362 * Originally Released Under LGPL - original licence link has changed is not relivant.
12365 * <script type="text/javascript">
12370 * @class Roo.CompositeElement
12371 * Standard composite class. Creates a Roo.Element for every element in the collection.
12373 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12374 * actions will be performed on all the elements in this collection.</b>
12376 * All methods return <i>this</i> and can be chained.
12378 var els = Roo.select("#some-el div.some-class", true);
12379 // or select directly from an existing element
12380 var el = Roo.get('some-el');
12381 el.select('div.some-class', true);
12383 els.setWidth(100); // all elements become 100 width
12384 els.hide(true); // all elements fade out and hide
12386 els.setWidth(100).hide(true);
12389 Roo.CompositeElement = function(els){
12390 this.elements = [];
12391 this.addElements(els);
12393 Roo.CompositeElement.prototype = {
12395 addElements : function(els){
12399 if(typeof els == "string"){
12400 els = Roo.Element.selectorFunction(els);
12402 var yels = this.elements;
12403 var index = yels.length-1;
12404 for(var i = 0, len = els.length; i < len; i++) {
12405 yels[++index] = Roo.get(els[i]);
12411 * Clears this composite and adds the elements returned by the passed selector.
12412 * @param {String/Array} els A string CSS selector, an array of elements or an element
12413 * @return {CompositeElement} this
12415 fill : function(els){
12416 this.elements = [];
12422 * Filters this composite to only elements that match the passed selector.
12423 * @param {String} selector A string CSS selector
12424 * @param {Boolean} inverse return inverse filter (not matches)
12425 * @return {CompositeElement} this
12427 filter : function(selector, inverse){
12429 inverse = inverse || false;
12430 this.each(function(el){
12431 var match = inverse ? !el.is(selector) : el.is(selector);
12433 els[els.length] = el.dom;
12440 invoke : function(fn, args){
12441 var els = this.elements;
12442 for(var i = 0, len = els.length; i < len; i++) {
12443 Roo.Element.prototype[fn].apply(els[i], args);
12448 * Adds elements to this composite.
12449 * @param {String/Array} els A string CSS selector, an array of elements or an element
12450 * @return {CompositeElement} this
12452 add : function(els){
12453 if(typeof els == "string"){
12454 this.addElements(Roo.Element.selectorFunction(els));
12455 }else if(els.length !== undefined){
12456 this.addElements(els);
12458 this.addElements([els]);
12463 * Calls the passed function passing (el, this, index) for each element in this composite.
12464 * @param {Function} fn The function to call
12465 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12466 * @return {CompositeElement} this
12468 each : function(fn, scope){
12469 var els = this.elements;
12470 for(var i = 0, len = els.length; i < len; i++){
12471 if(fn.call(scope || els[i], els[i], this, i) === false) {
12479 * Returns the Element object at the specified index
12480 * @param {Number} index
12481 * @return {Roo.Element}
12483 item : function(index){
12484 return this.elements[index] || null;
12488 * Returns the first Element
12489 * @return {Roo.Element}
12491 first : function(){
12492 return this.item(0);
12496 * Returns the last Element
12497 * @return {Roo.Element}
12500 return this.item(this.elements.length-1);
12504 * Returns the number of elements in this composite
12507 getCount : function(){
12508 return this.elements.length;
12512 * Returns true if this composite contains the passed element
12515 contains : function(el){
12516 return this.indexOf(el) !== -1;
12520 * Returns true if this composite contains the passed element
12523 indexOf : function(el){
12524 return this.elements.indexOf(Roo.get(el));
12529 * Removes the specified element(s).
12530 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
12531 * or an array of any of those.
12532 * @param {Boolean} removeDom (optional) True to also remove the element from the document
12533 * @return {CompositeElement} this
12535 removeElement : function(el, removeDom){
12536 if(el instanceof Array){
12537 for(var i = 0, len = el.length; i < len; i++){
12538 this.removeElement(el[i]);
12542 var index = typeof el == 'number' ? el : this.indexOf(el);
12545 var d = this.elements[index];
12549 d.parentNode.removeChild(d);
12552 this.elements.splice(index, 1);
12558 * Replaces the specified element with the passed element.
12559 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
12561 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
12562 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
12563 * @return {CompositeElement} this
12565 replaceElement : function(el, replacement, domReplace){
12566 var index = typeof el == 'number' ? el : this.indexOf(el);
12569 this.elements[index].replaceWith(replacement);
12571 this.elements.splice(index, 1, Roo.get(replacement))
12578 * Removes all elements.
12580 clear : function(){
12581 this.elements = [];
12585 Roo.CompositeElement.createCall = function(proto, fnName){
12586 if(!proto[fnName]){
12587 proto[fnName] = function(){
12588 return this.invoke(fnName, arguments);
12592 for(var fnName in Roo.Element.prototype){
12593 if(typeof Roo.Element.prototype[fnName] == "function"){
12594 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
12600 * Ext JS Library 1.1.1
12601 * Copyright(c) 2006-2007, Ext JS, LLC.
12603 * Originally Released Under LGPL - original licence link has changed is not relivant.
12606 * <script type="text/javascript">
12610 * @class Roo.CompositeElementLite
12611 * @extends Roo.CompositeElement
12612 * Flyweight composite class. Reuses the same Roo.Element for element operations.
12614 var els = Roo.select("#some-el div.some-class");
12615 // or select directly from an existing element
12616 var el = Roo.get('some-el');
12617 el.select('div.some-class');
12619 els.setWidth(100); // all elements become 100 width
12620 els.hide(true); // all elements fade out and hide
12622 els.setWidth(100).hide(true);
12623 </code></pre><br><br>
12624 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12625 * actions will be performed on all the elements in this collection.</b>
12627 Roo.CompositeElementLite = function(els){
12628 Roo.CompositeElementLite.superclass.constructor.call(this, els);
12629 this.el = new Roo.Element.Flyweight();
12631 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
12632 addElements : function(els){
12634 if(els instanceof Array){
12635 this.elements = this.elements.concat(els);
12637 var yels = this.elements;
12638 var index = yels.length-1;
12639 for(var i = 0, len = els.length; i < len; i++) {
12640 yels[++index] = els[i];
12646 invoke : function(fn, args){
12647 var els = this.elements;
12649 for(var i = 0, len = els.length; i < len; i++) {
12651 Roo.Element.prototype[fn].apply(el, args);
12656 * Returns a flyweight Element of the dom element object at the specified index
12657 * @param {Number} index
12658 * @return {Roo.Element}
12660 item : function(index){
12661 if(!this.elements[index]){
12664 this.el.dom = this.elements[index];
12668 // fixes scope with flyweight
12669 addListener : function(eventName, handler, scope, opt){
12670 var els = this.elements;
12671 for(var i = 0, len = els.length; i < len; i++) {
12672 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
12678 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
12679 * passed is the flyweight (shared) Roo.Element instance, so if you require a
12680 * a reference to the dom node, use el.dom.</b>
12681 * @param {Function} fn The function to call
12682 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12683 * @return {CompositeElement} this
12685 each : function(fn, scope){
12686 var els = this.elements;
12688 for(var i = 0, len = els.length; i < len; i++){
12690 if(fn.call(scope || el, el, this, i) === false){
12697 indexOf : function(el){
12698 return this.elements.indexOf(Roo.getDom(el));
12701 replaceElement : function(el, replacement, domReplace){
12702 var index = typeof el == 'number' ? el : this.indexOf(el);
12704 replacement = Roo.getDom(replacement);
12706 var d = this.elements[index];
12707 d.parentNode.insertBefore(replacement, d);
12708 d.parentNode.removeChild(d);
12710 this.elements.splice(index, 1, replacement);
12715 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
12719 * Ext JS Library 1.1.1
12720 * Copyright(c) 2006-2007, Ext JS, LLC.
12722 * Originally Released Under LGPL - original licence link has changed is not relivant.
12725 * <script type="text/javascript">
12731 * @class Roo.data.Connection
12732 * @extends Roo.util.Observable
12733 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
12734 * either to a configured URL, or to a URL specified at request time.
12736 * Requests made by this class are asynchronous, and will return immediately. No data from
12737 * the server will be available to the statement immediately following the {@link #request} call.
12738 * To process returned data, use a callback in the request options object, or an event listener.
12740 * Note: If you are doing a file upload, you will not get a normal response object sent back to
12741 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
12742 * The response object is created using the innerHTML of the IFRAME's document as the responseText
12743 * property and, if present, the IFRAME's XML document as the responseXML property.
12745 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
12746 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
12747 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
12748 * standard DOM methods.
12750 * @param {Object} config a configuration object.
12752 Roo.data.Connection = function(config){
12753 Roo.apply(this, config);
12756 * @event beforerequest
12757 * Fires before a network request is made to retrieve a data object.
12758 * @param {Connection} conn This Connection object.
12759 * @param {Object} options The options config object passed to the {@link #request} method.
12761 "beforerequest" : true,
12763 * @event requestcomplete
12764 * Fires if the request was successfully completed.
12765 * @param {Connection} conn This Connection object.
12766 * @param {Object} response The XHR object containing the response data.
12767 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12768 * @param {Object} options The options config object passed to the {@link #request} method.
12770 "requestcomplete" : true,
12772 * @event requestexception
12773 * Fires if an error HTTP status was returned from the server.
12774 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
12775 * @param {Connection} conn This Connection object.
12776 * @param {Object} response The XHR object containing the response data.
12777 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12778 * @param {Object} options The options config object passed to the {@link #request} method.
12780 "requestexception" : true
12782 Roo.data.Connection.superclass.constructor.call(this);
12785 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
12787 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12790 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12791 * extra parameters to each request made by this object. (defaults to undefined)
12794 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12795 * to each request made by this object. (defaults to undefined)
12798 * @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)
12801 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12805 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12811 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12814 disableCaching: true,
12817 * Sends an HTTP request to a remote server.
12818 * @param {Object} options An object which may contain the following properties:<ul>
12819 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
12820 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
12821 * request, a url encoded string or a function to call to get either.</li>
12822 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
12823 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
12824 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
12825 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
12826 * <li>options {Object} The parameter to the request call.</li>
12827 * <li>success {Boolean} True if the request succeeded.</li>
12828 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12830 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
12831 * The callback is passed the following parameters:<ul>
12832 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12833 * <li>options {Object} The parameter to the request call.</li>
12835 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
12836 * The callback is passed the following parameters:<ul>
12837 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12838 * <li>options {Object} The parameter to the request call.</li>
12840 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
12841 * for the callback function. Defaults to the browser window.</li>
12842 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
12843 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
12844 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
12845 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
12846 * params for the post data. Any params will be appended to the URL.</li>
12847 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
12849 * @return {Number} transactionId
12851 request : function(o){
12852 if(this.fireEvent("beforerequest", this, o) !== false){
12855 if(typeof p == "function"){
12856 p = p.call(o.scope||window, o);
12858 if(typeof p == "object"){
12859 p = Roo.urlEncode(o.params);
12861 if(this.extraParams){
12862 var extras = Roo.urlEncode(this.extraParams);
12863 p = p ? (p + '&' + extras) : extras;
12866 var url = o.url || this.url;
12867 if(typeof url == 'function'){
12868 url = url.call(o.scope||window, o);
12872 var form = Roo.getDom(o.form);
12873 url = url || form.action;
12875 var enctype = form.getAttribute("enctype");
12878 return this.doFormDataUpload(o, url);
12881 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
12882 return this.doFormUpload(o, p, url);
12884 var f = Roo.lib.Ajax.serializeForm(form);
12885 p = p ? (p + '&' + f) : f;
12888 if (!o.form && o.formData) {
12889 o.formData = o.formData === true ? new FormData() : o.formData;
12890 for (var k in o.params) {
12891 o.formData.append(k,o.params[k]);
12894 return this.doFormDataUpload(o, url);
12898 var hs = o.headers;
12899 if(this.defaultHeaders){
12900 hs = Roo.apply(hs || {}, this.defaultHeaders);
12907 success: this.handleResponse,
12908 failure: this.handleFailure,
12910 argument: {options: o},
12911 timeout : o.timeout || this.timeout
12914 var method = o.method||this.method||(p ? "POST" : "GET");
12916 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
12917 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
12920 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
12924 }else if(this.autoAbort !== false){
12928 if((method == 'GET' && p) || o.xmlData){
12929 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
12932 Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
12933 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
12934 Roo.lib.Ajax.useDefaultHeader == true;
12935 return this.transId;
12937 Roo.callback(o.callback, o.scope, [o, null, null]);
12943 * Determine whether this object has a request outstanding.
12944 * @param {Number} transactionId (Optional) defaults to the last transaction
12945 * @return {Boolean} True if there is an outstanding request.
12947 isLoading : function(transId){
12949 return Roo.lib.Ajax.isCallInProgress(transId);
12951 return this.transId ? true : false;
12956 * Aborts any outstanding request.
12957 * @param {Number} transactionId (Optional) defaults to the last transaction
12959 abort : function(transId){
12960 if(transId || this.isLoading()){
12961 Roo.lib.Ajax.abort(transId || this.transId);
12966 handleResponse : function(response){
12967 this.transId = false;
12968 var options = response.argument.options;
12969 response.argument = options ? options.argument : null;
12970 this.fireEvent("requestcomplete", this, response, options);
12971 Roo.callback(options.success, options.scope, [response, options]);
12972 Roo.callback(options.callback, options.scope, [options, true, response]);
12976 handleFailure : function(response, e){
12977 this.transId = false;
12978 var options = response.argument.options;
12979 response.argument = options ? options.argument : null;
12980 this.fireEvent("requestexception", this, response, options, e);
12981 Roo.callback(options.failure, options.scope, [response, options]);
12982 Roo.callback(options.callback, options.scope, [options, false, response]);
12986 doFormUpload : function(o, ps, url){
12988 var frame = document.createElement('iframe');
12991 frame.className = 'x-hidden';
12993 frame.src = Roo.SSL_SECURE_URL;
12995 document.body.appendChild(frame);
12998 document.frames[id].name = id;
13001 var form = Roo.getDom(o.form);
13003 form.method = 'POST';
13004 form.enctype = form.encoding = 'multipart/form-data';
13010 if(ps){ // add dynamic params
13012 ps = Roo.urlDecode(ps, false);
13014 if(ps.hasOwnProperty(k)){
13015 hd = document.createElement('input');
13016 hd.type = 'hidden';
13019 form.appendChild(hd);
13026 var r = { // bogus response object
13031 r.argument = o ? o.argument : null;
13036 doc = frame.contentWindow.document;
13038 doc = (frame.contentDocument || window.frames[id].document);
13040 if(doc && doc.body){
13041 r.responseText = doc.body.innerHTML;
13043 if(doc && doc.XMLDocument){
13044 r.responseXML = doc.XMLDocument;
13046 r.responseXML = doc;
13053 Roo.EventManager.removeListener(frame, 'load', cb, this);
13055 this.fireEvent("requestcomplete", this, r, o);
13056 Roo.callback(o.success, o.scope, [r, o]);
13057 Roo.callback(o.callback, o.scope, [o, true, r]);
13059 setTimeout(function(){document.body.removeChild(frame);}, 100);
13062 Roo.EventManager.on(frame, 'load', cb, this);
13065 if(hiddens){ // remove dynamic params
13066 for(var i = 0, len = hiddens.length; i < len; i++){
13067 form.removeChild(hiddens[i]);
13071 // this is a 'formdata version???'
13074 doFormDataUpload : function(o, url)
13078 var form = Roo.getDom(o.form);
13079 form.enctype = form.encoding = 'multipart/form-data';
13080 formData = o.formData === true ? new FormData(form) : o.formData;
13082 formData = o.formData === true ? new FormData() : o.formData;
13087 success: this.handleResponse,
13088 failure: this.handleFailure,
13090 argument: {options: o},
13091 timeout : o.timeout || this.timeout
13094 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
13098 }else if(this.autoAbort !== false){
13102 //Roo.lib.Ajax.defaultPostHeader = null;
13103 Roo.lib.Ajax.useDefaultHeader = false;
13104 this.transId = Roo.lib.Ajax.request( "POST", url, cb, formData, o);
13105 Roo.lib.Ajax.useDefaultHeader = true;
13113 * Ext JS Library 1.1.1
13114 * Copyright(c) 2006-2007, Ext JS, LLC.
13116 * Originally Released Under LGPL - original licence link has changed is not relivant.
13119 * <script type="text/javascript">
13123 * Global Ajax request class.
13126 * @extends Roo.data.Connection
13129 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
13130 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
13131 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
13132 * @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)
13133 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
13134 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
13135 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
13137 Roo.Ajax = new Roo.data.Connection({
13146 * Serialize the passed form into a url encoded string
13148 * @param {String/HTMLElement} form
13151 serializeForm : function(form){
13152 return Roo.lib.Ajax.serializeForm(form);
13156 * Ext JS Library 1.1.1
13157 * Copyright(c) 2006-2007, Ext JS, LLC.
13159 * Originally Released Under LGPL - original licence link has changed is not relivant.
13162 * <script type="text/javascript">
13167 * @class Roo.UpdateManager
13168 * @extends Roo.util.Observable
13169 * Provides AJAX-style update for Element object.<br><br>
13172 * // Get it from a Roo.Element object
13173 * var el = Roo.get("foo");
13174 * var mgr = el.getUpdateManager();
13175 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
13177 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
13179 * // or directly (returns the same UpdateManager instance)
13180 * var mgr = new Roo.UpdateManager("myElementId");
13181 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
13182 * mgr.on("update", myFcnNeedsToKnow);
13184 // short handed call directly from the element object
13185 Roo.get("foo").load({
13189 text: "Loading Foo..."
13193 * Create new UpdateManager directly.
13194 * @param {String/HTMLElement/Roo.Element} el The element to update
13195 * @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).
13197 Roo.UpdateManager = function(el, forceNew){
13199 if(!forceNew && el.updateManager){
13200 return el.updateManager;
13203 * The Element object
13204 * @type Roo.Element
13208 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
13211 this.defaultUrl = null;
13215 * @event beforeupdate
13216 * Fired before an update is made, return false from your handler and the update is cancelled.
13217 * @param {Roo.Element} el
13218 * @param {String/Object/Function} url
13219 * @param {String/Object} params
13221 "beforeupdate": true,
13224 * Fired after successful update is made.
13225 * @param {Roo.Element} el
13226 * @param {Object} oResponseObject The response Object
13231 * Fired on update failure.
13232 * @param {Roo.Element} el
13233 * @param {Object} oResponseObject The response Object
13237 var d = Roo.UpdateManager.defaults;
13239 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
13242 this.sslBlankUrl = d.sslBlankUrl;
13244 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
13247 this.disableCaching = d.disableCaching;
13249 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
13252 this.indicatorText = d.indicatorText;
13254 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
13257 this.showLoadIndicator = d.showLoadIndicator;
13259 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
13262 this.timeout = d.timeout;
13265 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
13268 this.loadScripts = d.loadScripts;
13271 * Transaction object of current executing transaction
13273 this.transaction = null;
13278 this.autoRefreshProcId = null;
13280 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
13283 this.refreshDelegate = this.refresh.createDelegate(this);
13285 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
13288 this.updateDelegate = this.update.createDelegate(this);
13290 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
13293 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
13297 this.successDelegate = this.processSuccess.createDelegate(this);
13301 this.failureDelegate = this.processFailure.createDelegate(this);
13303 if(!this.renderer){
13305 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
13307 this.renderer = new Roo.UpdateManager.BasicRenderer();
13310 Roo.UpdateManager.superclass.constructor.call(this);
13313 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
13315 * Get the Element this UpdateManager is bound to
13316 * @return {Roo.Element} The element
13318 getEl : function(){
13322 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
13323 * @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:
13326 url: "your-url.php",<br/>
13327 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
13328 callback: yourFunction,<br/>
13329 scope: yourObject, //(optional scope) <br/>
13330 discardUrl: false, <br/>
13331 nocache: false,<br/>
13332 text: "Loading...",<br/>
13334 scripts: false<br/>
13337 * The only required property is url. The optional properties nocache, text and scripts
13338 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
13339 * @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}
13340 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13341 * @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.
13343 update : function(url, params, callback, discardUrl){
13344 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
13345 var method = this.method,
13347 if(typeof url == "object"){ // must be config object
13350 params = params || cfg.params;
13351 callback = callback || cfg.callback;
13352 discardUrl = discardUrl || cfg.discardUrl;
13353 if(callback && cfg.scope){
13354 callback = callback.createDelegate(cfg.scope);
13356 if(typeof cfg.method != "undefined"){method = cfg.method;};
13357 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
13358 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
13359 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
13360 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
13362 this.showLoading();
13364 this.defaultUrl = url;
13366 if(typeof url == "function"){
13367 url = url.call(this);
13370 method = method || (params ? "POST" : "GET");
13371 if(method == "GET"){
13372 url = this.prepareUrl(url);
13375 var o = Roo.apply(cfg ||{}, {
13378 success: this.successDelegate,
13379 failure: this.failureDelegate,
13380 callback: undefined,
13381 timeout: (this.timeout*1000),
13382 argument: {"url": url, "form": null, "callback": callback, "params": params}
13384 Roo.log("updated manager called with timeout of " + o.timeout);
13385 this.transaction = Roo.Ajax.request(o);
13390 * 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.
13391 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
13392 * @param {String/HTMLElement} form The form Id or form element
13393 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
13394 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
13395 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13397 formUpdate : function(form, url, reset, callback){
13398 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
13399 if(typeof url == "function"){
13400 url = url.call(this);
13402 form = Roo.getDom(form);
13403 this.transaction = Roo.Ajax.request({
13406 success: this.successDelegate,
13407 failure: this.failureDelegate,
13408 timeout: (this.timeout*1000),
13409 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
13411 this.showLoading.defer(1, this);
13416 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
13417 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13419 refresh : function(callback){
13420 if(this.defaultUrl == null){
13423 this.update(this.defaultUrl, null, callback, true);
13427 * Set this element to auto refresh.
13428 * @param {Number} interval How often to update (in seconds).
13429 * @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)
13430 * @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}
13431 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13432 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
13434 startAutoRefresh : function(interval, url, params, callback, refreshNow){
13436 this.update(url || this.defaultUrl, params, callback, true);
13438 if(this.autoRefreshProcId){
13439 clearInterval(this.autoRefreshProcId);
13441 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
13445 * Stop auto refresh on this element.
13447 stopAutoRefresh : function(){
13448 if(this.autoRefreshProcId){
13449 clearInterval(this.autoRefreshProcId);
13450 delete this.autoRefreshProcId;
13454 isAutoRefreshing : function(){
13455 return this.autoRefreshProcId ? true : false;
13458 * Called to update the element to "Loading" state. Override to perform custom action.
13460 showLoading : function(){
13461 if(this.showLoadIndicator){
13462 this.el.update(this.indicatorText);
13467 * Adds unique parameter to query string if disableCaching = true
13470 prepareUrl : function(url){
13471 if(this.disableCaching){
13472 var append = "_dc=" + (new Date().getTime());
13473 if(url.indexOf("?") !== -1){
13474 url += "&" + append;
13476 url += "?" + append;
13485 processSuccess : function(response){
13486 this.transaction = null;
13487 if(response.argument.form && response.argument.reset){
13488 try{ // put in try/catch since some older FF releases had problems with this
13489 response.argument.form.reset();
13492 if(this.loadScripts){
13493 this.renderer.render(this.el, response, this,
13494 this.updateComplete.createDelegate(this, [response]));
13496 this.renderer.render(this.el, response, this);
13497 this.updateComplete(response);
13501 updateComplete : function(response){
13502 this.fireEvent("update", this.el, response);
13503 if(typeof response.argument.callback == "function"){
13504 response.argument.callback(this.el, true, response);
13511 processFailure : function(response){
13512 this.transaction = null;
13513 this.fireEvent("failure", this.el, response);
13514 if(typeof response.argument.callback == "function"){
13515 response.argument.callback(this.el, false, response);
13520 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
13521 * @param {Object} renderer The object implementing the render() method
13523 setRenderer : function(renderer){
13524 this.renderer = renderer;
13527 getRenderer : function(){
13528 return this.renderer;
13532 * Set the defaultUrl used for updates
13533 * @param {String/Function} defaultUrl The url or a function to call to get the url
13535 setDefaultUrl : function(defaultUrl){
13536 this.defaultUrl = defaultUrl;
13540 * Aborts the executing transaction
13542 abort : function(){
13543 if(this.transaction){
13544 Roo.Ajax.abort(this.transaction);
13549 * Returns true if an update is in progress
13550 * @return {Boolean}
13552 isUpdating : function(){
13553 if(this.transaction){
13554 return Roo.Ajax.isLoading(this.transaction);
13561 * @class Roo.UpdateManager.defaults
13562 * @static (not really - but it helps the doc tool)
13563 * The defaults collection enables customizing the default properties of UpdateManager
13565 Roo.UpdateManager.defaults = {
13567 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
13573 * True to process scripts by default (Defaults to false).
13576 loadScripts : false,
13579 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
13582 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
13584 * Whether to append unique parameter on get request to disable caching (Defaults to false).
13587 disableCaching : false,
13589 * Whether to show indicatorText when loading (Defaults to true).
13592 showLoadIndicator : true,
13594 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
13597 indicatorText : '<div class="loading-indicator">Loading...</div>'
13601 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
13603 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
13604 * @param {String/HTMLElement/Roo.Element} el The element to update
13605 * @param {String} url The url
13606 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
13607 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
13610 * @member Roo.UpdateManager
13612 Roo.UpdateManager.updateElement = function(el, url, params, options){
13613 var um = Roo.get(el, true).getUpdateManager();
13614 Roo.apply(um, options);
13615 um.update(url, params, options ? options.callback : null);
13617 // alias for backwards compat
13618 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
13620 * @class Roo.UpdateManager.BasicRenderer
13621 * Default Content renderer. Updates the elements innerHTML with the responseText.
13623 Roo.UpdateManager.BasicRenderer = function(){};
13625 Roo.UpdateManager.BasicRenderer.prototype = {
13627 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
13628 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
13629 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
13630 * @param {Roo.Element} el The element being rendered
13631 * @param {Object} response The YUI Connect response object
13632 * @param {UpdateManager} updateManager The calling update manager
13633 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
13635 render : function(el, response, updateManager, callback){
13636 el.update(response.responseText, updateManager.loadScripts, callback);
13642 * (c)) Alan Knowles
13648 * @class Roo.DomTemplate
13649 * @extends Roo.Template
13650 * An effort at a dom based template engine..
13652 * Similar to XTemplate, except it uses dom parsing to create the template..
13654 * Supported features:
13659 {a_variable} - output encoded.
13660 {a_variable.format:("Y-m-d")} - call a method on the variable
13661 {a_variable:raw} - unencoded output
13662 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
13663 {a_variable:this.method_on_template(...)} - call a method on the template object.
13668 <div roo-for="a_variable or condition.."></div>
13669 <div roo-if="a_variable or condition"></div>
13670 <div roo-exec="some javascript"></div>
13671 <div roo-name="named_template"></div>
13676 Roo.DomTemplate = function()
13678 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
13685 Roo.extend(Roo.DomTemplate, Roo.Template, {
13687 * id counter for sub templates.
13691 * flag to indicate if dom parser is inside a pre,
13692 * it will strip whitespace if not.
13697 * The various sub templates
13705 * basic tag replacing syntax
13708 * // you can fake an object call by doing this
13712 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
13713 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
13715 iterChild : function (node, method) {
13717 var oldPre = this.inPre;
13718 if (node.tagName == 'PRE') {
13721 for( var i = 0; i < node.childNodes.length; i++) {
13722 method.call(this, node.childNodes[i]);
13724 this.inPre = oldPre;
13730 * compile the template
13732 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
13735 compile: function()
13739 // covert the html into DOM...
13743 doc = document.implementation.createHTMLDocument("");
13744 doc.documentElement.innerHTML = this.html ;
13745 div = doc.documentElement;
13747 // old IE... - nasty -- it causes all sorts of issues.. with
13748 // images getting pulled from server..
13749 div = document.createElement('div');
13750 div.innerHTML = this.html;
13752 //doc.documentElement.innerHTML = htmlBody
13758 this.iterChild(div, function(n) {_t.compileNode(n, true); });
13760 var tpls = this.tpls;
13762 // create a top level template from the snippet..
13764 //Roo.log(div.innerHTML);
13771 body : div.innerHTML,
13784 Roo.each(tpls, function(tp){
13785 this.compileTpl(tp);
13786 this.tpls[tp.id] = tp;
13789 this.master = tpls[0];
13795 compileNode : function(node, istop) {
13800 // skip anything not a tag..
13801 if (node.nodeType != 1) {
13802 if (node.nodeType == 3 && !this.inPre) {
13803 // reduce white space..
13804 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
13827 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
13828 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
13829 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
13830 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
13836 // just itterate children..
13837 this.iterChild(node,this.compileNode);
13840 tpl.uid = this.id++;
13841 tpl.value = node.getAttribute('roo-' + tpl.attr);
13842 node.removeAttribute('roo-'+ tpl.attr);
13843 if (tpl.attr != 'name') {
13844 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
13845 node.parentNode.replaceChild(placeholder, node);
13848 var placeholder = document.createElement('span');
13849 placeholder.className = 'roo-tpl-' + tpl.value;
13850 node.parentNode.replaceChild(placeholder, node);
13853 // parent now sees '{domtplXXXX}
13854 this.iterChild(node,this.compileNode);
13856 // we should now have node body...
13857 var div = document.createElement('div');
13858 div.appendChild(node);
13860 // this has the unfortunate side effect of converting tagged attributes
13861 // eg. href="{...}" into %7C...%7D
13862 // this has been fixed by searching for those combo's although it's a bit hacky..
13865 tpl.body = div.innerHTML;
13872 switch (tpl.value) {
13873 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
13874 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
13875 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
13880 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13884 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13888 tpl.id = tpl.value; // replace non characters???
13894 this.tpls.push(tpl);
13904 * Compile a segment of the template into a 'sub-template'
13910 compileTpl : function(tpl)
13912 var fm = Roo.util.Format;
13913 var useF = this.disableFormats !== true;
13915 var sep = Roo.isGecko ? "+\n" : ",\n";
13917 var undef = function(str) {
13918 Roo.debug && Roo.log("Property not found :" + str);
13922 //Roo.log(tpl.body);
13926 var fn = function(m, lbrace, name, format, args)
13929 //Roo.log(arguments);
13930 args = args ? args.replace(/\\'/g,"'") : args;
13931 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
13932 if (typeof(format) == 'undefined') {
13933 format = 'htmlEncode';
13935 if (format == 'raw' ) {
13939 if(name.substr(0, 6) == 'domtpl'){
13940 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
13943 // build an array of options to determine if value is undefined..
13945 // basically get 'xxxx.yyyy' then do
13946 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
13947 // (function () { Roo.log("Property not found"); return ''; })() :
13952 Roo.each(name.split('.'), function(st) {
13953 lookfor += (lookfor.length ? '.': '') + st;
13954 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
13957 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
13960 if(format && useF){
13962 args = args ? ',' + args : "";
13964 if(format.substr(0, 5) != "this."){
13965 format = "fm." + format + '(';
13967 format = 'this.call("'+ format.substr(5) + '", ';
13971 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
13974 if (args && args.length) {
13975 // called with xxyx.yuu:(test,test)
13977 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
13979 // raw.. - :raw modifier..
13980 return "'"+ sep + udef_st + name + ")"+sep+"'";
13984 // branched to use + in gecko and [].join() in others
13986 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
13987 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
13990 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
13991 body.push(tpl.body.replace(/(\r\n|\n)/g,
13992 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
13993 body.push("'].join('');};};");
13994 body = body.join('');
13997 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
13999 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
14006 * same as applyTemplate, except it's done to one of the subTemplates
14007 * when using named templates, you can do:
14009 * var str = pl.applySubTemplate('your-name', values);
14012 * @param {Number} id of the template
14013 * @param {Object} values to apply to template
14014 * @param {Object} parent (normaly the instance of this object)
14016 applySubTemplate : function(id, values, parent)
14020 var t = this.tpls[id];
14024 if(t.ifCall && !t.ifCall.call(this, values, parent)){
14025 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
14029 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
14036 if(t.execCall && t.execCall.call(this, values, parent)){
14040 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
14046 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
14047 parent = t.target ? values : parent;
14048 if(t.forCall && vs instanceof Array){
14050 for(var i = 0, len = vs.length; i < len; i++){
14052 buf[buf.length] = t.compiled.call(this, vs[i], parent);
14054 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
14056 //Roo.log(t.compiled);
14060 return buf.join('');
14063 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
14068 return t.compiled.call(this, vs, parent);
14070 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
14072 //Roo.log(t.compiled);
14080 applyTemplate : function(values){
14081 return this.master.compiled.call(this, values, {});
14082 //var s = this.subs;
14085 apply : function(){
14086 return this.applyTemplate.apply(this, arguments);
14091 Roo.DomTemplate.from = function(el){
14092 el = Roo.getDom(el);
14093 return new Roo.Domtemplate(el.value || el.innerHTML);
14096 * Ext JS Library 1.1.1
14097 * Copyright(c) 2006-2007, Ext JS, LLC.
14099 * Originally Released Under LGPL - original licence link has changed is not relivant.
14102 * <script type="text/javascript">
14106 * @class Roo.util.DelayedTask
14107 * Provides a convenient method of performing setTimeout where a new
14108 * timeout cancels the old timeout. An example would be performing validation on a keypress.
14109 * You can use this class to buffer
14110 * the keypress events for a certain number of milliseconds, and perform only if they stop
14111 * for that amount of time.
14112 * @constructor The parameters to this constructor serve as defaults and are not required.
14113 * @param {Function} fn (optional) The default function to timeout
14114 * @param {Object} scope (optional) The default scope of that timeout
14115 * @param {Array} args (optional) The default Array of arguments
14117 Roo.util.DelayedTask = function(fn, scope, args){
14118 var id = null, d, t;
14120 var call = function(){
14121 var now = new Date().getTime();
14125 fn.apply(scope, args || []);
14129 * Cancels any pending timeout and queues a new one
14130 * @param {Number} delay The milliseconds to delay
14131 * @param {Function} newFn (optional) Overrides function passed to constructor
14132 * @param {Object} newScope (optional) Overrides scope passed to constructor
14133 * @param {Array} newArgs (optional) Overrides args passed to constructor
14135 this.delay = function(delay, newFn, newScope, newArgs){
14136 if(id && delay != d){
14140 t = new Date().getTime();
14142 scope = newScope || scope;
14143 args = newArgs || args;
14145 id = setInterval(call, d);
14150 * Cancel the last queued timeout
14152 this.cancel = function(){
14160 * Ext JS Library 1.1.1
14161 * Copyright(c) 2006-2007, Ext JS, LLC.
14163 * Originally Released Under LGPL - original licence link has changed is not relivant.
14166 * <script type="text/javascript">
14169 * @class Roo.util.TaskRunner
14170 * Manage background tasks - not sure why this is better that setInterval?
14175 Roo.util.TaskRunner = function(interval){
14176 interval = interval || 10;
14177 var tasks = [], removeQueue = [];
14179 var running = false;
14181 var stopThread = function(){
14187 var startThread = function(){
14190 id = setInterval(runTasks, interval);
14194 var removeTask = function(task){
14195 removeQueue.push(task);
14201 var runTasks = function(){
14202 if(removeQueue.length > 0){
14203 for(var i = 0, len = removeQueue.length; i < len; i++){
14204 tasks.remove(removeQueue[i]);
14207 if(tasks.length < 1){
14212 var now = new Date().getTime();
14213 for(var i = 0, len = tasks.length; i < len; ++i){
14215 var itime = now - t.taskRunTime;
14216 if(t.interval <= itime){
14217 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
14218 t.taskRunTime = now;
14219 if(rt === false || t.taskRunCount === t.repeat){
14224 if(t.duration && t.duration <= (now - t.taskStartTime)){
14231 * Queues a new task.
14232 * @param {Object} task
14234 * Task property : interval = how frequent to run.
14235 * Task object should implement
14237 * Task object may implement
14238 * function onStop()
14240 this.start = function(task){
14242 task.taskStartTime = new Date().getTime();
14243 task.taskRunTime = 0;
14244 task.taskRunCount = 0;
14250 * @param {Object} task
14252 this.stop = function(task){
14259 this.stopAll = function(){
14261 for(var i = 0, len = tasks.length; i < len; i++){
14262 if(tasks[i].onStop){
14271 Roo.TaskMgr = new Roo.util.TaskRunner();/*
14273 * Ext JS Library 1.1.1
14274 * Copyright(c) 2006-2007, Ext JS, LLC.
14276 * Originally Released Under LGPL - original licence link has changed is not relivant.
14279 * <script type="text/javascript">
14284 * @class Roo.util.MixedCollection
14285 * @extends Roo.util.Observable
14286 * A Collection class that maintains both numeric indexes and keys and exposes events.
14288 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
14289 * collection (defaults to false)
14290 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
14291 * and return the key value for that item. This is used when available to look up the key on items that
14292 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
14293 * equivalent to providing an implementation for the {@link #getKey} method.
14295 Roo.util.MixedCollection = function(allowFunctions, keyFn){
14303 * Fires when the collection is cleared.
14308 * Fires when an item is added to the collection.
14309 * @param {Number} index The index at which the item was added.
14310 * @param {Object} o The item added.
14311 * @param {String} key The key associated with the added item.
14316 * Fires when an item is replaced in the collection.
14317 * @param {String} key he key associated with the new added.
14318 * @param {Object} old The item being replaced.
14319 * @param {Object} new The new item.
14324 * Fires when an item is removed from the collection.
14325 * @param {Object} o The item being removed.
14326 * @param {String} key (optional) The key associated with the removed item.
14331 this.allowFunctions = allowFunctions === true;
14333 this.getKey = keyFn;
14335 Roo.util.MixedCollection.superclass.constructor.call(this);
14338 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
14339 allowFunctions : false,
14342 * Adds an item to the collection.
14343 * @param {String} key The key to associate with the item
14344 * @param {Object} o The item to add.
14345 * @return {Object} The item added.
14347 add : function(key, o){
14348 if(arguments.length == 1){
14350 key = this.getKey(o);
14352 if(typeof key == "undefined" || key === null){
14354 this.items.push(o);
14355 this.keys.push(null);
14357 var old = this.map[key];
14359 return this.replace(key, o);
14362 this.items.push(o);
14364 this.keys.push(key);
14366 this.fireEvent("add", this.length-1, o, key);
14371 * MixedCollection has a generic way to fetch keys if you implement getKey.
14374 var mc = new Roo.util.MixedCollection();
14375 mc.add(someEl.dom.id, someEl);
14376 mc.add(otherEl.dom.id, otherEl);
14380 var mc = new Roo.util.MixedCollection();
14381 mc.getKey = function(el){
14387 // or via the constructor
14388 var mc = new Roo.util.MixedCollection(false, function(el){
14394 * @param o {Object} The item for which to find the key.
14395 * @return {Object} The key for the passed item.
14397 getKey : function(o){
14402 * Replaces an item in the collection.
14403 * @param {String} key The key associated with the item to replace, or the item to replace.
14404 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
14405 * @return {Object} The new item.
14407 replace : function(key, o){
14408 if(arguments.length == 1){
14410 key = this.getKey(o);
14412 var old = this.item(key);
14413 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
14414 return this.add(key, o);
14416 var index = this.indexOfKey(key);
14417 this.items[index] = o;
14419 this.fireEvent("replace", key, old, o);
14424 * Adds all elements of an Array or an Object to the collection.
14425 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
14426 * an Array of values, each of which are added to the collection.
14428 addAll : function(objs){
14429 if(arguments.length > 1 || objs instanceof Array){
14430 var args = arguments.length > 1 ? arguments : objs;
14431 for(var i = 0, len = args.length; i < len; i++){
14435 for(var key in objs){
14436 if(this.allowFunctions || typeof objs[key] != "function"){
14437 this.add(key, objs[key]);
14444 * Executes the specified function once for every item in the collection, passing each
14445 * item as the first and only parameter. returning false from the function will stop the iteration.
14446 * @param {Function} fn The function to execute for each item.
14447 * @param {Object} scope (optional) The scope in which to execute the function.
14449 each : function(fn, scope){
14450 var items = [].concat(this.items); // each safe for removal
14451 for(var i = 0, len = items.length; i < len; i++){
14452 if(fn.call(scope || items[i], items[i], i, len) === false){
14459 * Executes the specified function once for every key in the collection, passing each
14460 * key, and its associated item as the first two parameters.
14461 * @param {Function} fn The function to execute for each item.
14462 * @param {Object} scope (optional) The scope in which to execute the function.
14464 eachKey : function(fn, scope){
14465 for(var i = 0, len = this.keys.length; i < len; i++){
14466 fn.call(scope || window, this.keys[i], this.items[i], i, len);
14471 * Returns the first item in the collection which elicits a true return value from the
14472 * passed selection function.
14473 * @param {Function} fn The selection function to execute for each item.
14474 * @param {Object} scope (optional) The scope in which to execute the function.
14475 * @return {Object} The first item in the collection which returned true from the selection function.
14477 find : function(fn, scope){
14478 for(var i = 0, len = this.items.length; i < len; i++){
14479 if(fn.call(scope || window, this.items[i], this.keys[i])){
14480 return this.items[i];
14487 * Inserts an item at the specified index in the collection.
14488 * @param {Number} index The index to insert the item at.
14489 * @param {String} key The key to associate with the new item, or the item itself.
14490 * @param {Object} o (optional) If the second parameter was a key, the new item.
14491 * @return {Object} The item inserted.
14493 insert : function(index, key, o){
14494 if(arguments.length == 2){
14496 key = this.getKey(o);
14498 if(index >= this.length){
14499 return this.add(key, o);
14502 this.items.splice(index, 0, o);
14503 if(typeof key != "undefined" && key != null){
14506 this.keys.splice(index, 0, key);
14507 this.fireEvent("add", index, o, key);
14512 * Removed an item from the collection.
14513 * @param {Object} o The item to remove.
14514 * @return {Object} The item removed.
14516 remove : function(o){
14517 return this.removeAt(this.indexOf(o));
14521 * Remove an item from a specified index in the collection.
14522 * @param {Number} index The index within the collection of the item to remove.
14524 removeAt : function(index){
14525 if(index < this.length && index >= 0){
14527 var o = this.items[index];
14528 this.items.splice(index, 1);
14529 var key = this.keys[index];
14530 if(typeof key != "undefined"){
14531 delete this.map[key];
14533 this.keys.splice(index, 1);
14534 this.fireEvent("remove", o, key);
14539 * Removed an item associated with the passed key fom the collection.
14540 * @param {String} key The key of the item to remove.
14542 removeKey : function(key){
14543 return this.removeAt(this.indexOfKey(key));
14547 * Returns the number of items in the collection.
14548 * @return {Number} the number of items in the collection.
14550 getCount : function(){
14551 return this.length;
14555 * Returns index within the collection of the passed Object.
14556 * @param {Object} o The item to find the index of.
14557 * @return {Number} index of the item.
14559 indexOf : function(o){
14560 if(!this.items.indexOf){
14561 for(var i = 0, len = this.items.length; i < len; i++){
14562 if(this.items[i] == o) {
14568 return this.items.indexOf(o);
14573 * Returns index within the collection of the passed key.
14574 * @param {String} key The key to find the index of.
14575 * @return {Number} index of the key.
14577 indexOfKey : function(key){
14578 if(!this.keys.indexOf){
14579 for(var i = 0, len = this.keys.length; i < len; i++){
14580 if(this.keys[i] == key) {
14586 return this.keys.indexOf(key);
14591 * Returns the item associated with the passed key OR index. Key has priority over index.
14592 * @param {String/Number} key The key or index of the item.
14593 * @return {Object} The item associated with the passed key.
14595 item : function(key){
14596 if (key === 'length') {
14599 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
14600 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
14604 * Returns the item at the specified index.
14605 * @param {Number} index The index of the item.
14608 itemAt : function(index){
14609 return this.items[index];
14613 * Returns the item associated with the passed key.
14614 * @param {String/Number} key The key of the item.
14615 * @return {Object} The item associated with the passed key.
14617 key : function(key){
14618 return this.map[key];
14622 * Returns true if the collection contains the passed Object as an item.
14623 * @param {Object} o The Object to look for in the collection.
14624 * @return {Boolean} True if the collection contains the Object as an item.
14626 contains : function(o){
14627 return this.indexOf(o) != -1;
14631 * Returns true if the collection contains the passed Object as a key.
14632 * @param {String} key The key to look for in the collection.
14633 * @return {Boolean} True if the collection contains the Object as a key.
14635 containsKey : function(key){
14636 return typeof this.map[key] != "undefined";
14640 * Removes all items from the collection.
14642 clear : function(){
14647 this.fireEvent("clear");
14651 * Returns the first item in the collection.
14652 * @return {Object} the first item in the collection..
14654 first : function(){
14655 return this.items[0];
14659 * Returns the last item in the collection.
14660 * @return {Object} the last item in the collection..
14663 return this.items[this.length-1];
14666 _sort : function(property, dir, fn){
14667 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
14668 fn = fn || function(a, b){
14671 var c = [], k = this.keys, items = this.items;
14672 for(var i = 0, len = items.length; i < len; i++){
14673 c[c.length] = {key: k[i], value: items[i], index: i};
14675 c.sort(function(a, b){
14676 var v = fn(a[property], b[property]) * dsc;
14678 v = (a.index < b.index ? -1 : 1);
14682 for(var i = 0, len = c.length; i < len; i++){
14683 items[i] = c[i].value;
14686 this.fireEvent("sort", this);
14690 * Sorts this collection with the passed comparison function
14691 * @param {String} direction (optional) "ASC" or "DESC"
14692 * @param {Function} fn (optional) comparison function
14694 sort : function(dir, fn){
14695 this._sort("value", dir, fn);
14699 * Sorts this collection by keys
14700 * @param {String} direction (optional) "ASC" or "DESC"
14701 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
14703 keySort : function(dir, fn){
14704 this._sort("key", dir, fn || function(a, b){
14705 return String(a).toUpperCase()-String(b).toUpperCase();
14710 * Returns a range of items in this collection
14711 * @param {Number} startIndex (optional) defaults to 0
14712 * @param {Number} endIndex (optional) default to the last item
14713 * @return {Array} An array of items
14715 getRange : function(start, end){
14716 var items = this.items;
14717 if(items.length < 1){
14720 start = start || 0;
14721 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
14724 for(var i = start; i <= end; i++) {
14725 r[r.length] = items[i];
14728 for(var i = start; i >= end; i--) {
14729 r[r.length] = items[i];
14736 * Filter the <i>objects</i> in this collection by a specific property.
14737 * Returns a new collection that has been filtered.
14738 * @param {String} property A property on your objects
14739 * @param {String/RegExp} value Either string that the property values
14740 * should start with or a RegExp to test against the property
14741 * @return {MixedCollection} The new filtered collection
14743 filter : function(property, value){
14744 if(!value.exec){ // not a regex
14745 value = String(value);
14746 if(value.length == 0){
14747 return this.clone();
14749 value = new RegExp("^" + Roo.escapeRe(value), "i");
14751 return this.filterBy(function(o){
14752 return o && value.test(o[property]);
14757 * Filter by a function. * Returns a new collection that has been filtered.
14758 * The passed function will be called with each
14759 * object in the collection. If the function returns true, the value is included
14760 * otherwise it is filtered.
14761 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
14762 * @param {Object} scope (optional) The scope of the function (defaults to this)
14763 * @return {MixedCollection} The new filtered collection
14765 filterBy : function(fn, scope){
14766 var r = new Roo.util.MixedCollection();
14767 r.getKey = this.getKey;
14768 var k = this.keys, it = this.items;
14769 for(var i = 0, len = it.length; i < len; i++){
14770 if(fn.call(scope||this, it[i], k[i])){
14771 r.add(k[i], it[i]);
14778 * Creates a duplicate of this collection
14779 * @return {MixedCollection}
14781 clone : function(){
14782 var r = new Roo.util.MixedCollection();
14783 var k = this.keys, it = this.items;
14784 for(var i = 0, len = it.length; i < len; i++){
14785 r.add(k[i], it[i]);
14787 r.getKey = this.getKey;
14792 * Returns the item associated with the passed key or index.
14794 * @param {String/Number} key The key or index of the item.
14795 * @return {Object} The item associated with the passed key.
14797 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
14799 * Ext JS Library 1.1.1
14800 * Copyright(c) 2006-2007, Ext JS, LLC.
14802 * Originally Released Under LGPL - original licence link has changed is not relivant.
14805 * <script type="text/javascript">
14808 * @class Roo.util.JSON
14809 * Modified version of Douglas Crockford"s json.js that doesn"t
14810 * mess with the Object prototype
14811 * http://www.json.org/js.html
14814 Roo.util.JSON = new (function(){
14815 var useHasOwn = {}.hasOwnProperty ? true : false;
14817 // crashes Safari in some instances
14818 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
14820 var pad = function(n) {
14821 return n < 10 ? "0" + n : n;
14834 var encodeString = function(s){
14835 if (/["\\\x00-\x1f]/.test(s)) {
14836 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
14841 c = b.charCodeAt();
14843 Math.floor(c / 16).toString(16) +
14844 (c % 16).toString(16);
14847 return '"' + s + '"';
14850 var encodeArray = function(o){
14851 var a = ["["], b, i, l = o.length, v;
14852 for (i = 0; i < l; i += 1) {
14854 switch (typeof v) {
14863 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
14871 var encodeDate = function(o){
14872 return '"' + o.getFullYear() + "-" +
14873 pad(o.getMonth() + 1) + "-" +
14874 pad(o.getDate()) + "T" +
14875 pad(o.getHours()) + ":" +
14876 pad(o.getMinutes()) + ":" +
14877 pad(o.getSeconds()) + '"';
14881 * Encodes an Object, Array or other value
14882 * @param {Mixed} o The variable to encode
14883 * @return {String} The JSON string
14885 this.encode = function(o)
14887 // should this be extended to fully wrap stringify..
14889 if(typeof o == "undefined" || o === null){
14891 }else if(o instanceof Array){
14892 return encodeArray(o);
14893 }else if(o instanceof Date){
14894 return encodeDate(o);
14895 }else if(typeof o == "string"){
14896 return encodeString(o);
14897 }else if(typeof o == "number"){
14898 return isFinite(o) ? String(o) : "null";
14899 }else if(typeof o == "boolean"){
14902 var a = ["{"], b, i, v;
14904 if(!useHasOwn || o.hasOwnProperty(i)) {
14906 switch (typeof v) {
14915 a.push(this.encode(i), ":",
14916 v === null ? "null" : this.encode(v));
14927 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
14928 * @param {String} json The JSON string
14929 * @return {Object} The resulting object
14931 this.decode = function(json){
14933 return /** eval:var:json */ eval("(" + json + ')');
14937 * Shorthand for {@link Roo.util.JSON#encode}
14938 * @member Roo encode
14940 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
14942 * Shorthand for {@link Roo.util.JSON#decode}
14943 * @member Roo decode
14945 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
14948 * Ext JS Library 1.1.1
14949 * Copyright(c) 2006-2007, Ext JS, LLC.
14951 * Originally Released Under LGPL - original licence link has changed is not relivant.
14954 * <script type="text/javascript">
14958 * @class Roo.util.Format
14959 * Reusable data formatting functions
14962 Roo.util.Format = function(){
14963 var trimRe = /^\s+|\s+$/g;
14966 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
14967 * @param {String} value The string to truncate
14968 * @param {Number} length The maximum length to allow before truncating
14969 * @return {String} The converted text
14971 ellipsis : function(value, len){
14972 if(value && value.length > len){
14973 return value.substr(0, len-3)+"...";
14979 * Checks a reference and converts it to empty string if it is undefined
14980 * @param {Mixed} value Reference to check
14981 * @return {Mixed} Empty string if converted, otherwise the original value
14983 undef : function(value){
14984 return typeof value != "undefined" ? value : "";
14988 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
14989 * @param {String} value The string to encode
14990 * @return {String} The encoded text
14992 htmlEncode : function(value){
14993 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
14997 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
14998 * @param {String} value The string to decode
14999 * @return {String} The decoded text
15001 htmlDecode : function(value){
15002 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
15006 * Trims any whitespace from either side of a string
15007 * @param {String} value The text to trim
15008 * @return {String} The trimmed text
15010 trim : function(value){
15011 return String(value).replace(trimRe, "");
15015 * Returns a substring from within an original string
15016 * @param {String} value The original text
15017 * @param {Number} start The start index of the substring
15018 * @param {Number} length The length of the substring
15019 * @return {String} The substring
15021 substr : function(value, start, length){
15022 return String(value).substr(start, length);
15026 * Converts a string to all lower case letters
15027 * @param {String} value The text to convert
15028 * @return {String} The converted text
15030 lowercase : function(value){
15031 return String(value).toLowerCase();
15035 * Converts a string to all upper case letters
15036 * @param {String} value The text to convert
15037 * @return {String} The converted text
15039 uppercase : function(value){
15040 return String(value).toUpperCase();
15044 * Converts the first character only of a string to upper case
15045 * @param {String} value The text to convert
15046 * @return {String} The converted text
15048 capitalize : function(value){
15049 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
15053 call : function(value, fn){
15054 if(arguments.length > 2){
15055 var args = Array.prototype.slice.call(arguments, 2);
15056 args.unshift(value);
15058 return /** eval:var:value */ eval(fn).apply(window, args);
15060 /** eval:var:value */
15061 return /** eval:var:value */ eval(fn).call(window, value);
15067 * safer version of Math.toFixed..??/
15068 * @param {Number/String} value The numeric value to format
15069 * @param {Number/String} value Decimal places
15070 * @return {String} The formatted currency string
15072 toFixed : function(v, n)
15074 // why not use to fixed - precision is buggered???
15076 return Math.round(v-0);
15078 var fact = Math.pow(10,n+1);
15079 v = (Math.round((v-0)*fact))/fact;
15080 var z = (''+fact).substring(2);
15081 if (v == Math.floor(v)) {
15082 return Math.floor(v) + '.' + z;
15085 // now just padd decimals..
15086 var ps = String(v).split('.');
15087 var fd = (ps[1] + z);
15088 var r = fd.substring(0,n);
15089 var rm = fd.substring(n);
15091 return ps[0] + '.' + r;
15093 r*=1; // turn it into a number;
15095 if (String(r).length != n) {
15098 r = String(r).substring(1); // chop the end off.
15101 return ps[0] + '.' + r;
15106 * Format a number as US currency
15107 * @param {Number/String} value The numeric value to format
15108 * @return {String} The formatted currency string
15110 usMoney : function(v){
15111 return '$' + Roo.util.Format.number(v);
15116 * eventually this should probably emulate php's number_format
15117 * @param {Number/String} value The numeric value to format
15118 * @param {Number} decimals number of decimal places
15119 * @param {String} delimiter for thousands (default comma)
15120 * @return {String} The formatted currency string
15122 number : function(v, decimals, thousandsDelimiter)
15124 // multiply and round.
15125 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
15126 thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
15128 var mul = Math.pow(10, decimals);
15129 var zero = String(mul).substring(1);
15130 v = (Math.round((v-0)*mul))/mul;
15132 // if it's '0' number.. then
15134 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
15136 var ps = v.split('.');
15139 var r = /(\d+)(\d{3})/;
15142 if(thousandsDelimiter.length != 0) {
15143 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
15148 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
15149 // does not have decimals
15150 (decimals ? ('.' + zero) : '');
15153 return whole + sub ;
15157 * Parse a value into a formatted date using the specified format pattern.
15158 * @param {Mixed} value The value to format
15159 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
15160 * @return {String} The formatted date string
15162 date : function(v, format){
15166 if(!(v instanceof Date)){
15167 v = new Date(Date.parse(v));
15169 return v.dateFormat(format || Roo.util.Format.defaults.date);
15173 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
15174 * @param {String} format Any valid date format string
15175 * @return {Function} The date formatting function
15177 dateRenderer : function(format){
15178 return function(v){
15179 return Roo.util.Format.date(v, format);
15184 stripTagsRE : /<\/?[^>]+>/gi,
15187 * Strips all HTML tags
15188 * @param {Mixed} value The text from which to strip tags
15189 * @return {String} The stripped text
15191 stripTags : function(v){
15192 return !v ? v : String(v).replace(this.stripTagsRE, "");
15196 * Size in Mb,Gb etc.
15197 * @param {Number} value The number to be formated
15198 * @param {number} decimals how many decimal places
15199 * @return {String} the formated string
15201 size : function(value, decimals)
15203 var sizes = ['b', 'k', 'M', 'G', 'T'];
15207 var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
15208 return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals) + sizes[i];
15215 Roo.util.Format.defaults = {
15219 * Ext JS Library 1.1.1
15220 * Copyright(c) 2006-2007, Ext JS, LLC.
15222 * Originally Released Under LGPL - original licence link has changed is not relivant.
15225 * <script type="text/javascript">
15232 * @class Roo.MasterTemplate
15233 * @extends Roo.Template
15234 * Provides a template that can have child templates. The syntax is:
15236 var t = new Roo.MasterTemplate(
15237 '<select name="{name}">',
15238 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
15241 t.add('options', {value: 'foo', text: 'bar'});
15242 // or you can add multiple child elements in one shot
15243 t.addAll('options', [
15244 {value: 'foo', text: 'bar'},
15245 {value: 'foo2', text: 'bar2'},
15246 {value: 'foo3', text: 'bar3'}
15248 // then append, applying the master template values
15249 t.append('my-form', {name: 'my-select'});
15251 * A name attribute for the child template is not required if you have only one child
15252 * template or you want to refer to them by index.
15254 Roo.MasterTemplate = function(){
15255 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
15256 this.originalHtml = this.html;
15258 var m, re = this.subTemplateRe;
15261 while(m = re.exec(this.html)){
15262 var name = m[1], content = m[2];
15267 tpl : new Roo.Template(content)
15270 st[name] = st[subIndex];
15272 st[subIndex].tpl.compile();
15273 st[subIndex].tpl.call = this.call.createDelegate(this);
15276 this.subCount = subIndex;
15279 Roo.extend(Roo.MasterTemplate, Roo.Template, {
15281 * The regular expression used to match sub templates
15285 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
15288 * Applies the passed values to a child template.
15289 * @param {String/Number} name (optional) The name or index of the child template
15290 * @param {Array/Object} values The values to be applied to the template
15291 * @return {MasterTemplate} this
15293 add : function(name, values){
15294 if(arguments.length == 1){
15295 values = arguments[0];
15298 var s = this.subs[name];
15299 s.buffer[s.buffer.length] = s.tpl.apply(values);
15304 * Applies all the passed values to a child template.
15305 * @param {String/Number} name (optional) The name or index of the child template
15306 * @param {Array} values The values to be applied to the template, this should be an array of objects.
15307 * @param {Boolean} reset (optional) True to reset the template first
15308 * @return {MasterTemplate} this
15310 fill : function(name, values, reset){
15312 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
15320 for(var i = 0, len = values.length; i < len; i++){
15321 this.add(name, values[i]);
15327 * Resets the template for reuse
15328 * @return {MasterTemplate} this
15330 reset : function(){
15332 for(var i = 0; i < this.subCount; i++){
15338 applyTemplate : function(values){
15340 var replaceIndex = -1;
15341 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
15342 return s[++replaceIndex].buffer.join("");
15344 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
15347 apply : function(){
15348 return this.applyTemplate.apply(this, arguments);
15351 compile : function(){return this;}
15355 * Alias for fill().
15358 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
15360 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
15361 * var tpl = Roo.MasterTemplate.from('element-id');
15362 * @param {String/HTMLElement} el
15363 * @param {Object} config
15366 Roo.MasterTemplate.from = function(el, config){
15367 el = Roo.getDom(el);
15368 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
15371 * Ext JS Library 1.1.1
15372 * Copyright(c) 2006-2007, Ext JS, LLC.
15374 * Originally Released Under LGPL - original licence link has changed is not relivant.
15377 * <script type="text/javascript">
15382 * @class Roo.util.CSS
15383 * Utility class for manipulating CSS rules
15387 Roo.util.CSS = function(){
15389 var doc = document;
15391 var camelRe = /(-[a-z])/gi;
15392 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
15396 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
15397 * tag and appended to the HEAD of the document.
15398 * @param {String|Object} cssText The text containing the css rules
15399 * @param {String} id An id to add to the stylesheet for later removal
15400 * @return {StyleSheet}
15402 createStyleSheet : function(cssText, id){
15404 var head = doc.getElementsByTagName("head")[0];
15405 var nrules = doc.createElement("style");
15406 nrules.setAttribute("type", "text/css");
15408 nrules.setAttribute("id", id);
15410 if (typeof(cssText) != 'string') {
15411 // support object maps..
15412 // not sure if this a good idea..
15413 // perhaps it should be merged with the general css handling
15414 // and handle js style props.
15415 var cssTextNew = [];
15416 for(var n in cssText) {
15418 for(var k in cssText[n]) {
15419 citems.push( k + ' : ' +cssText[n][k] + ';' );
15421 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
15424 cssText = cssTextNew.join("\n");
15430 head.appendChild(nrules);
15431 ss = nrules.styleSheet;
15432 ss.cssText = cssText;
15435 nrules.appendChild(doc.createTextNode(cssText));
15437 nrules.cssText = cssText;
15439 head.appendChild(nrules);
15440 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
15442 this.cacheStyleSheet(ss);
15447 * Removes a style or link tag by id
15448 * @param {String} id The id of the tag
15450 removeStyleSheet : function(id){
15451 var existing = doc.getElementById(id);
15453 existing.parentNode.removeChild(existing);
15458 * Dynamically swaps an existing stylesheet reference for a new one
15459 * @param {String} id The id of an existing link tag to remove
15460 * @param {String} url The href of the new stylesheet to include
15462 swapStyleSheet : function(id, url){
15463 this.removeStyleSheet(id);
15464 var ss = doc.createElement("link");
15465 ss.setAttribute("rel", "stylesheet");
15466 ss.setAttribute("type", "text/css");
15467 ss.setAttribute("id", id);
15468 ss.setAttribute("href", url);
15469 doc.getElementsByTagName("head")[0].appendChild(ss);
15473 * Refresh the rule cache if you have dynamically added stylesheets
15474 * @return {Object} An object (hash) of rules indexed by selector
15476 refreshCache : function(){
15477 return this.getRules(true);
15481 cacheStyleSheet : function(stylesheet){
15485 try{// try catch for cross domain access issue
15486 var ssRules = stylesheet.cssRules || stylesheet.rules;
15487 for(var j = ssRules.length-1; j >= 0; --j){
15488 rules[ssRules[j].selectorText] = ssRules[j];
15494 * Gets all css rules for the document
15495 * @param {Boolean} refreshCache true to refresh the internal cache
15496 * @return {Object} An object (hash) of rules indexed by selector
15498 getRules : function(refreshCache){
15499 if(rules == null || refreshCache){
15501 var ds = doc.styleSheets;
15502 for(var i =0, len = ds.length; i < len; i++){
15504 this.cacheStyleSheet(ds[i]);
15512 * Gets an an individual CSS rule by selector(s)
15513 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
15514 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
15515 * @return {CSSRule} The CSS rule or null if one is not found
15517 getRule : function(selector, refreshCache){
15518 var rs = this.getRules(refreshCache);
15519 if(!(selector instanceof Array)){
15520 return rs[selector];
15522 for(var i = 0; i < selector.length; i++){
15523 if(rs[selector[i]]){
15524 return rs[selector[i]];
15532 * Updates a rule property
15533 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
15534 * @param {String} property The css property
15535 * @param {String} value The new value for the property
15536 * @return {Boolean} true If a rule was found and updated
15538 updateRule : function(selector, property, value){
15539 if(!(selector instanceof Array)){
15540 var rule = this.getRule(selector);
15542 rule.style[property.replace(camelRe, camelFn)] = value;
15546 for(var i = 0; i < selector.length; i++){
15547 if(this.updateRule(selector[i], property, value)){
15557 * Ext JS Library 1.1.1
15558 * Copyright(c) 2006-2007, Ext JS, LLC.
15560 * Originally Released Under LGPL - original licence link has changed is not relivant.
15563 * <script type="text/javascript">
15569 * @class Roo.util.ClickRepeater
15570 * @extends Roo.util.Observable
15572 * A wrapper class which can be applied to any element. Fires a "click" event while the
15573 * mouse is pressed. The interval between firings may be specified in the config but
15574 * defaults to 10 milliseconds.
15576 * Optionally, a CSS class may be applied to the element during the time it is pressed.
15578 * @cfg {String/HTMLElement/Element} el The element to act as a button.
15579 * @cfg {Number} delay The initial delay before the repeating event begins firing.
15580 * Similar to an autorepeat key delay.
15581 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
15582 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
15583 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
15584 * "interval" and "delay" are ignored. "immediate" is honored.
15585 * @cfg {Boolean} preventDefault True to prevent the default click event
15586 * @cfg {Boolean} stopDefault True to stop the default click event
15589 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
15590 * 2007-02-02 jvs Renamed to ClickRepeater
15591 * 2007-02-03 jvs Modifications for FF Mac and Safari
15594 * @param {String/HTMLElement/Element} el The element to listen on
15595 * @param {Object} config
15597 Roo.util.ClickRepeater = function(el, config)
15599 this.el = Roo.get(el);
15600 this.el.unselectable();
15602 Roo.apply(this, config);
15607 * Fires when the mouse button is depressed.
15608 * @param {Roo.util.ClickRepeater} this
15610 "mousedown" : true,
15613 * Fires on a specified interval during the time the element is pressed.
15614 * @param {Roo.util.ClickRepeater} this
15619 * Fires when the mouse key is released.
15620 * @param {Roo.util.ClickRepeater} this
15625 this.el.on("mousedown", this.handleMouseDown, this);
15626 if(this.preventDefault || this.stopDefault){
15627 this.el.on("click", function(e){
15628 if(this.preventDefault){
15629 e.preventDefault();
15631 if(this.stopDefault){
15637 // allow inline handler
15639 this.on("click", this.handler, this.scope || this);
15642 Roo.util.ClickRepeater.superclass.constructor.call(this);
15645 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
15648 preventDefault : true,
15649 stopDefault : false,
15653 handleMouseDown : function(){
15654 clearTimeout(this.timer);
15656 if(this.pressClass){
15657 this.el.addClass(this.pressClass);
15659 this.mousedownTime = new Date();
15661 Roo.get(document).on("mouseup", this.handleMouseUp, this);
15662 this.el.on("mouseout", this.handleMouseOut, this);
15664 this.fireEvent("mousedown", this);
15665 this.fireEvent("click", this);
15667 this.timer = this.click.defer(this.delay || this.interval, this);
15671 click : function(){
15672 this.fireEvent("click", this);
15673 this.timer = this.click.defer(this.getInterval(), this);
15677 getInterval: function(){
15678 if(!this.accelerate){
15679 return this.interval;
15681 var pressTime = this.mousedownTime.getElapsed();
15682 if(pressTime < 500){
15684 }else if(pressTime < 1700){
15686 }else if(pressTime < 2600){
15688 }else if(pressTime < 3500){
15690 }else if(pressTime < 4400){
15692 }else if(pressTime < 5300){
15694 }else if(pressTime < 6200){
15702 handleMouseOut : function(){
15703 clearTimeout(this.timer);
15704 if(this.pressClass){
15705 this.el.removeClass(this.pressClass);
15707 this.el.on("mouseover", this.handleMouseReturn, this);
15711 handleMouseReturn : function(){
15712 this.el.un("mouseover", this.handleMouseReturn);
15713 if(this.pressClass){
15714 this.el.addClass(this.pressClass);
15720 handleMouseUp : function(){
15721 clearTimeout(this.timer);
15722 this.el.un("mouseover", this.handleMouseReturn);
15723 this.el.un("mouseout", this.handleMouseOut);
15724 Roo.get(document).un("mouseup", this.handleMouseUp);
15725 this.el.removeClass(this.pressClass);
15726 this.fireEvent("mouseup", this);
15729 * @class Roo.util.Clipboard
15735 Roo.util.Clipboard = {
15737 * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
15738 * @param {String} text to copy to clipboard
15740 write : function(text) {
15741 // navigator clipboard api needs a secure context (https)
15742 if (navigator.clipboard && window.isSecureContext) {
15743 // navigator clipboard api method'
15744 navigator.clipboard.writeText(text);
15747 // text area method
15748 var ta = document.createElement("textarea");
15750 // make the textarea out of viewport
15751 ta.style.position = "fixed";
15752 ta.style.left = "-999999px";
15753 ta.style.top = "-999999px";
15754 document.body.appendChild(ta);
15757 document.execCommand('copy');
15767 * Ext JS Library 1.1.1
15768 * Copyright(c) 2006-2007, Ext JS, LLC.
15770 * Originally Released Under LGPL - original licence link has changed is not relivant.
15773 * <script type="text/javascript">
15778 * @class Roo.KeyNav
15779 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
15780 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
15781 * way to implement custom navigation schemes for any UI component.</p>
15782 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
15783 * pageUp, pageDown, del, home, end. Usage:</p>
15785 var nav = new Roo.KeyNav("my-element", {
15786 "left" : function(e){
15787 this.moveLeft(e.ctrlKey);
15789 "right" : function(e){
15790 this.moveRight(e.ctrlKey);
15792 "enter" : function(e){
15799 * @param {String/HTMLElement/Roo.Element} el The element to bind to
15800 * @param {Object} config The config
15802 Roo.KeyNav = function(el, config){
15803 this.el = Roo.get(el);
15804 Roo.apply(this, config);
15805 if(!this.disabled){
15806 this.disabled = true;
15811 Roo.KeyNav.prototype = {
15813 * @cfg {Boolean} disabled
15814 * True to disable this KeyNav instance (defaults to false)
15818 * @cfg {String} defaultEventAction
15819 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
15820 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
15821 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
15823 defaultEventAction: "stopEvent",
15825 * @cfg {Boolean} forceKeyDown
15826 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
15827 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
15828 * handle keydown instead of keypress.
15830 forceKeyDown : false,
15833 prepareEvent : function(e){
15834 var k = e.getKey();
15835 var h = this.keyToHandler[k];
15836 //if(h && this[h]){
15837 // e.stopPropagation();
15839 if(Roo.isSafari && h && k >= 37 && k <= 40){
15845 relay : function(e){
15846 var k = e.getKey();
15847 var h = this.keyToHandler[k];
15849 if(this.doRelay(e, this[h], h) !== true){
15850 e[this.defaultEventAction]();
15856 doRelay : function(e, h, hname){
15857 return h.call(this.scope || this, e);
15860 // possible handlers
15874 // quick lookup hash
15891 * Enable this KeyNav
15893 enable: function(){
15895 // ie won't do special keys on keypress, no one else will repeat keys with keydown
15896 // the EventObject will normalize Safari automatically
15897 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15898 this.el.on("keydown", this.relay, this);
15900 this.el.on("keydown", this.prepareEvent, this);
15901 this.el.on("keypress", this.relay, this);
15903 this.disabled = false;
15908 * Disable this KeyNav
15910 disable: function(){
15911 if(!this.disabled){
15912 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15913 this.el.un("keydown", this.relay);
15915 this.el.un("keydown", this.prepareEvent);
15916 this.el.un("keypress", this.relay);
15918 this.disabled = true;
15923 * Ext JS Library 1.1.1
15924 * Copyright(c) 2006-2007, Ext JS, LLC.
15926 * Originally Released Under LGPL - original licence link has changed is not relivant.
15929 * <script type="text/javascript">
15934 * @class Roo.KeyMap
15935 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
15936 * The constructor accepts the same config object as defined by {@link #addBinding}.
15937 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
15938 * combination it will call the function with this signature (if the match is a multi-key
15939 * combination the callback will still be called only once): (String key, Roo.EventObject e)
15940 * A KeyMap can also handle a string representation of keys.<br />
15943 // map one key by key code
15944 var map = new Roo.KeyMap("my-element", {
15945 key: 13, // or Roo.EventObject.ENTER
15950 // map multiple keys to one action by string
15951 var map = new Roo.KeyMap("my-element", {
15957 // map multiple keys to multiple actions by strings and array of codes
15958 var map = new Roo.KeyMap("my-element", [
15961 fn: function(){ alert("Return was pressed"); }
15964 fn: function(){ alert('a, b or c was pressed'); }
15969 fn: function(){ alert('Control + shift + tab was pressed.'); }
15973 * <b>Note: A KeyMap starts enabled</b>
15975 * @param {String/HTMLElement/Roo.Element} el The element to bind to
15976 * @param {Object} config The config (see {@link #addBinding})
15977 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
15979 Roo.KeyMap = function(el, config, eventName){
15980 this.el = Roo.get(el);
15981 this.eventName = eventName || "keydown";
15982 this.bindings = [];
15984 this.addBinding(config);
15989 Roo.KeyMap.prototype = {
15991 * True to stop the event from bubbling and prevent the default browser action if the
15992 * key was handled by the KeyMap (defaults to false)
15998 * Add a new binding to this KeyMap. The following config object properties are supported:
16000 Property Type Description
16001 ---------- --------------- ----------------------------------------------------------------------
16002 key String/Array A single keycode or an array of keycodes to handle
16003 shift Boolean True to handle key only when shift is pressed (defaults to false)
16004 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
16005 alt Boolean True to handle key only when alt is pressed (defaults to false)
16006 fn Function The function to call when KeyMap finds the expected key combination
16007 scope Object The scope of the callback function
16013 var map = new Roo.KeyMap(document, {
16014 key: Roo.EventObject.ENTER,
16019 //Add a new binding to the existing KeyMap later
16027 * @param {Object/Array} config A single KeyMap config or an array of configs
16029 addBinding : function(config){
16030 if(config instanceof Array){
16031 for(var i = 0, len = config.length; i < len; i++){
16032 this.addBinding(config[i]);
16036 var keyCode = config.key,
16037 shift = config.shift,
16038 ctrl = config.ctrl,
16041 scope = config.scope;
16042 if(typeof keyCode == "string"){
16044 var keyString = keyCode.toUpperCase();
16045 for(var j = 0, len = keyString.length; j < len; j++){
16046 ks.push(keyString.charCodeAt(j));
16050 var keyArray = keyCode instanceof Array;
16051 var handler = function(e){
16052 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
16053 var k = e.getKey();
16055 for(var i = 0, len = keyCode.length; i < len; i++){
16056 if(keyCode[i] == k){
16057 if(this.stopEvent){
16060 fn.call(scope || window, k, e);
16066 if(this.stopEvent){
16069 fn.call(scope || window, k, e);
16074 this.bindings.push(handler);
16078 * Shorthand for adding a single key listener
16079 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
16080 * following options:
16081 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
16082 * @param {Function} fn The function to call
16083 * @param {Object} scope (optional) The scope of the function
16085 on : function(key, fn, scope){
16086 var keyCode, shift, ctrl, alt;
16087 if(typeof key == "object" && !(key instanceof Array)){
16106 handleKeyDown : function(e){
16107 if(this.enabled){ //just in case
16108 var b = this.bindings;
16109 for(var i = 0, len = b.length; i < len; i++){
16110 b[i].call(this, e);
16116 * Returns true if this KeyMap is enabled
16117 * @return {Boolean}
16119 isEnabled : function(){
16120 return this.enabled;
16124 * Enables this KeyMap
16126 enable: function(){
16128 this.el.on(this.eventName, this.handleKeyDown, this);
16129 this.enabled = true;
16134 * Disable this KeyMap
16136 disable: function(){
16138 this.el.removeListener(this.eventName, this.handleKeyDown, this);
16139 this.enabled = false;
16144 * Ext JS Library 1.1.1
16145 * Copyright(c) 2006-2007, Ext JS, LLC.
16147 * Originally Released Under LGPL - original licence link has changed is not relivant.
16150 * <script type="text/javascript">
16155 * @class Roo.util.TextMetrics
16156 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
16157 * wide, in pixels, a given block of text will be.
16160 Roo.util.TextMetrics = function(){
16164 * Measures the size of the specified text
16165 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
16166 * that can affect the size of the rendered text
16167 * @param {String} text The text to measure
16168 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
16169 * in order to accurately measure the text height
16170 * @return {Object} An object containing the text's size {width: (width), height: (height)}
16172 measure : function(el, text, fixedWidth){
16174 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
16177 shared.setFixedWidth(fixedWidth || 'auto');
16178 return shared.getSize(text);
16182 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
16183 * the overhead of multiple calls to initialize the style properties on each measurement.
16184 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
16185 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
16186 * in order to accurately measure the text height
16187 * @return {Roo.util.TextMetrics.Instance} instance The new instance
16189 createInstance : function(el, fixedWidth){
16190 return Roo.util.TextMetrics.Instance(el, fixedWidth);
16196 * @class Roo.util.TextMetrics.Instance
16197 * Instance of TextMetrics Calcuation
16199 * Create a new TextMetrics Instance
16200 * @param {Object} bindto
16201 * @param {Boolean} fixedWidth
16204 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth)
16206 var ml = new Roo.Element(document.createElement('div'));
16207 document.body.appendChild(ml.dom);
16208 ml.position('absolute');
16209 ml.setLeftTop(-1000, -1000);
16213 ml.setWidth(fixedWidth);
16218 * Returns the size of the specified text based on the internal element's style and width properties
16219 * @param {String} text The text to measure
16220 * @return {Object} An object containing the text's size {width: (width), height: (height)}
16222 getSize : function(text){
16224 var s = ml.getSize();
16230 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
16231 * that can affect the size of the rendered text
16232 * @param {String/HTMLElement} el The element, dom node or id
16234 bind : function(el){
16236 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
16241 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
16242 * to set a fixed width in order to accurately measure the text height.
16243 * @param {Number} width The width to set on the element
16245 setFixedWidth : function(width){
16246 ml.setWidth(width);
16250 * Returns the measured width of the specified text
16251 * @param {String} text The text to measure
16252 * @return {Number} width The width in pixels
16254 getWidth : function(text){
16255 ml.dom.style.width = 'auto';
16256 return this.getSize(text).width;
16260 * Returns the measured height of the specified text. For multiline text, be sure to call
16261 * {@link #setFixedWidth} if necessary.
16262 * @param {String} text The text to measure
16263 * @return {Number} height The height in pixels
16265 getHeight : function(text){
16266 return this.getSize(text).height;
16270 instance.bind(bindTo);
16275 // backwards compat
16276 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
16278 * Ext JS Library 1.1.1
16279 * Copyright(c) 2006-2007, Ext JS, LLC.
16281 * Originally Released Under LGPL - original licence link has changed is not relivant.
16284 * <script type="text/javascript">
16288 * @class Roo.state.Provider
16289 * Abstract base class for state provider implementations. This class provides methods
16290 * for encoding and decoding <b>typed</b> variables including dates and defines the
16291 * Provider interface.
16293 Roo.state.Provider = function(){
16295 * @event statechange
16296 * Fires when a state change occurs.
16297 * @param {Provider} this This state provider
16298 * @param {String} key The state key which was changed
16299 * @param {String} value The encoded value for the state
16302 "statechange": true
16305 Roo.state.Provider.superclass.constructor.call(this);
16307 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
16309 * Returns the current value for a key
16310 * @param {String} name The key name
16311 * @param {Mixed} defaultValue A default value to return if the key's value is not found
16312 * @return {Mixed} The state data
16314 get : function(name, defaultValue){
16315 return typeof this.state[name] == "undefined" ?
16316 defaultValue : this.state[name];
16320 * Clears a value from the state
16321 * @param {String} name The key name
16323 clear : function(name){
16324 delete this.state[name];
16325 this.fireEvent("statechange", this, name, null);
16329 * Sets the value for a key
16330 * @param {String} name The key name
16331 * @param {Mixed} value The value to set
16333 set : function(name, value){
16334 this.state[name] = value;
16335 this.fireEvent("statechange", this, name, value);
16339 * Decodes a string previously encoded with {@link #encodeValue}.
16340 * @param {String} value The value to decode
16341 * @return {Mixed} The decoded value
16343 decodeValue : function(cookie){
16344 var re = /^(a|n|d|b|s|o)\:(.*)$/;
16345 var matches = re.exec(unescape(cookie));
16346 if(!matches || !matches[1]) {
16347 return; // non state cookie
16349 var type = matches[1];
16350 var v = matches[2];
16353 return parseFloat(v);
16355 return new Date(Date.parse(v));
16360 var values = v.split("^");
16361 for(var i = 0, len = values.length; i < len; i++){
16362 all.push(this.decodeValue(values[i]));
16367 var values = v.split("^");
16368 for(var i = 0, len = values.length; i < len; i++){
16369 var kv = values[i].split("=");
16370 all[kv[0]] = this.decodeValue(kv[1]);
16379 * Encodes a value including type information. Decode with {@link #decodeValue}.
16380 * @param {Mixed} value The value to encode
16381 * @return {String} The encoded value
16383 encodeValue : function(v){
16385 if(typeof v == "number"){
16387 }else if(typeof v == "boolean"){
16388 enc = "b:" + (v ? "1" : "0");
16389 }else if(v instanceof Date){
16390 enc = "d:" + v.toGMTString();
16391 }else if(v instanceof Array){
16393 for(var i = 0, len = v.length; i < len; i++){
16394 flat += this.encodeValue(v[i]);
16400 }else if(typeof v == "object"){
16403 if(typeof v[key] != "function"){
16404 flat += key + "=" + this.encodeValue(v[key]) + "^";
16407 enc = "o:" + flat.substring(0, flat.length-1);
16411 return escape(enc);
16417 * Ext JS Library 1.1.1
16418 * Copyright(c) 2006-2007, Ext JS, LLC.
16420 * Originally Released Under LGPL - original licence link has changed is not relivant.
16423 * <script type="text/javascript">
16426 * @class Roo.state.Manager
16427 * This is the global state manager. By default all components that are "state aware" check this class
16428 * for state information if you don't pass them a custom state provider. In order for this class
16429 * to be useful, it must be initialized with a provider when your application initializes.
16431 // in your initialization function
16433 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
16435 // supposed you have a {@link Roo.BorderLayout}
16436 var layout = new Roo.BorderLayout(...);
16437 layout.restoreState();
16438 // or a {Roo.BasicDialog}
16439 var dialog = new Roo.BasicDialog(...);
16440 dialog.restoreState();
16444 Roo.state.Manager = function(){
16445 var provider = new Roo.state.Provider();
16449 * Configures the default state provider for your application
16450 * @param {Provider} stateProvider The state provider to set
16452 setProvider : function(stateProvider){
16453 provider = stateProvider;
16457 * Returns the current value for a key
16458 * @param {String} name The key name
16459 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
16460 * @return {Mixed} The state data
16462 get : function(key, defaultValue){
16463 return provider.get(key, defaultValue);
16467 * Sets the value for a key
16468 * @param {String} name The key name
16469 * @param {Mixed} value The state data
16471 set : function(key, value){
16472 provider.set(key, value);
16476 * Clears a value from the state
16477 * @param {String} name The key name
16479 clear : function(key){
16480 provider.clear(key);
16484 * Gets the currently configured state provider
16485 * @return {Provider} The state provider
16487 getProvider : function(){
16494 * Ext JS Library 1.1.1
16495 * Copyright(c) 2006-2007, Ext JS, LLC.
16497 * Originally Released Under LGPL - original licence link has changed is not relivant.
16500 * <script type="text/javascript">
16503 * @class Roo.state.CookieProvider
16504 * @extends Roo.state.Provider
16505 * The default Provider implementation which saves state via cookies.
16508 var cp = new Roo.state.CookieProvider({
16510 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
16511 domain: "roojs.com"
16513 Roo.state.Manager.setProvider(cp);
16515 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
16516 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
16517 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
16518 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
16519 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
16520 * domain the page is running on including the 'www' like 'www.roojs.com')
16521 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
16523 * Create a new CookieProvider
16524 * @param {Object} config The configuration object
16526 Roo.state.CookieProvider = function(config){
16527 Roo.state.CookieProvider.superclass.constructor.call(this);
16529 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
16530 this.domain = null;
16531 this.secure = false;
16532 Roo.apply(this, config);
16533 this.state = this.readCookies();
16536 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
16538 set : function(name, value){
16539 if(typeof value == "undefined" || value === null){
16543 this.setCookie(name, value);
16544 Roo.state.CookieProvider.superclass.set.call(this, name, value);
16548 clear : function(name){
16549 this.clearCookie(name);
16550 Roo.state.CookieProvider.superclass.clear.call(this, name);
16554 readCookies : function(){
16556 var c = document.cookie + ";";
16557 var re = /\s?(.*?)=(.*?);/g;
16559 while((matches = re.exec(c)) != null){
16560 var name = matches[1];
16561 var value = matches[2];
16562 if(name && name.substring(0,3) == "ys-"){
16563 cookies[name.substr(3)] = this.decodeValue(value);
16570 setCookie : function(name, value){
16571 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
16572 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
16573 ((this.path == null) ? "" : ("; path=" + this.path)) +
16574 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16575 ((this.secure == true) ? "; secure" : "");
16579 clearCookie : function(name){
16580 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
16581 ((this.path == null) ? "" : ("; path=" + this.path)) +
16582 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16583 ((this.secure == true) ? "; secure" : "");
16587 * Ext JS Library 1.1.1
16588 * Copyright(c) 2006-2007, Ext JS, LLC.
16590 * Originally Released Under LGPL - original licence link has changed is not relivant.
16593 * <script type="text/javascript">
16598 * @class Roo.ComponentMgr
16599 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
16602 Roo.ComponentMgr = function(){
16603 var all = new Roo.util.MixedCollection();
16607 * Registers a component.
16608 * @param {Roo.Component} c The component
16610 register : function(c){
16615 * Unregisters a component.
16616 * @param {Roo.Component} c The component
16618 unregister : function(c){
16623 * Returns a component by id
16624 * @param {String} id The component id
16626 get : function(id){
16627 return all.get(id);
16631 * Registers a function that will be called when a specified component is added to ComponentMgr
16632 * @param {String} id The component id
16633 * @param {Funtction} fn The callback function
16634 * @param {Object} scope The scope of the callback
16636 onAvailable : function(id, fn, scope){
16637 all.on("add", function(index, o){
16639 fn.call(scope || o, o);
16640 all.un("add", fn, scope);
16647 * Ext JS Library 1.1.1
16648 * Copyright(c) 2006-2007, Ext JS, LLC.
16650 * Originally Released Under LGPL - original licence link has changed is not relivant.
16653 * <script type="text/javascript">
16657 * @class Roo.Component
16658 * @extends Roo.util.Observable
16659 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
16660 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
16661 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
16662 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
16663 * All visual components (widgets) that require rendering into a layout should subclass Component.
16665 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
16666 * 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
16667 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
16669 Roo.Component = function(config){
16670 config = config || {};
16671 if(config.tagName || config.dom || typeof config == "string"){ // element object
16672 config = {el: config, id: config.id || config};
16674 this.initialConfig = config;
16676 Roo.apply(this, config);
16680 * Fires after the component is disabled.
16681 * @param {Roo.Component} this
16686 * Fires after the component is enabled.
16687 * @param {Roo.Component} this
16691 * @event beforeshow
16692 * Fires before the component is shown. Return false to stop the show.
16693 * @param {Roo.Component} this
16698 * Fires after the component is shown.
16699 * @param {Roo.Component} this
16703 * @event beforehide
16704 * Fires before the component is hidden. Return false to stop the hide.
16705 * @param {Roo.Component} this
16710 * Fires after the component is hidden.
16711 * @param {Roo.Component} this
16715 * @event beforerender
16716 * Fires before the component is rendered. Return false to stop the render.
16717 * @param {Roo.Component} this
16719 beforerender : true,
16722 * Fires after the component is rendered.
16723 * @param {Roo.Component} this
16727 * @event beforedestroy
16728 * Fires before the component is destroyed. Return false to stop the destroy.
16729 * @param {Roo.Component} this
16731 beforedestroy : true,
16734 * Fires after the component is destroyed.
16735 * @param {Roo.Component} this
16740 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
16742 Roo.ComponentMgr.register(this);
16743 Roo.Component.superclass.constructor.call(this);
16744 this.initComponent();
16745 if(this.renderTo){ // not supported by all components yet. use at your own risk!
16746 this.render(this.renderTo);
16747 delete this.renderTo;
16752 Roo.Component.AUTO_ID = 1000;
16754 Roo.extend(Roo.Component, Roo.util.Observable, {
16756 * @scope Roo.Component.prototype
16758 * true if this component is hidden. Read-only.
16763 * true if this component is disabled. Read-only.
16768 * true if this component has been rendered. Read-only.
16772 /** @cfg {String} disableClass
16773 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
16775 disabledClass : "x-item-disabled",
16776 /** @cfg {Boolean} allowDomMove
16777 * Whether the component can move the Dom node when rendering (defaults to true).
16779 allowDomMove : true,
16780 /** @cfg {String} hideMode (display|visibility)
16781 * How this component should hidden. Supported values are
16782 * "visibility" (css visibility), "offsets" (negative offset position) and
16783 * "display" (css display) - defaults to "display".
16785 hideMode: 'display',
16788 ctype : "Roo.Component",
16791 * @cfg {String} actionMode
16792 * which property holds the element that used for hide() / show() / disable() / enable()
16793 * default is 'el' for forms you probably want to set this to fieldEl
16798 getActionEl : function(){
16799 return this[this.actionMode];
16802 initComponent : Roo.emptyFn,
16804 * If this is a lazy rendering component, render it to its container element.
16805 * @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.
16807 render : function(container, position){
16813 if(this.fireEvent("beforerender", this) === false){
16817 if(!container && this.el){
16818 this.el = Roo.get(this.el);
16819 container = this.el.dom.parentNode;
16820 this.allowDomMove = false;
16822 this.container = Roo.get(container);
16823 this.rendered = true;
16824 if(position !== undefined){
16825 if(typeof position == 'number'){
16826 position = this.container.dom.childNodes[position];
16828 position = Roo.getDom(position);
16831 this.onRender(this.container, position || null);
16833 this.el.addClass(this.cls);
16837 this.el.applyStyles(this.style);
16840 this.fireEvent("render", this);
16841 this.afterRender(this.container);
16854 // default function is not really useful
16855 onRender : function(ct, position){
16857 this.el = Roo.get(this.el);
16858 if(this.allowDomMove !== false){
16859 ct.dom.insertBefore(this.el.dom, position);
16865 getAutoCreate : function(){
16866 var cfg = typeof this.autoCreate == "object" ?
16867 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
16868 if(this.id && !cfg.id){
16875 afterRender : Roo.emptyFn,
16878 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
16879 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
16881 destroy : function(){
16882 if(this.fireEvent("beforedestroy", this) !== false){
16883 this.purgeListeners();
16884 this.beforeDestroy();
16886 this.el.removeAllListeners();
16888 if(this.actionMode == "container"){
16889 this.container.remove();
16893 Roo.ComponentMgr.unregister(this);
16894 this.fireEvent("destroy", this);
16899 beforeDestroy : function(){
16904 onDestroy : function(){
16909 * Returns the underlying {@link Roo.Element}.
16910 * @return {Roo.Element} The element
16912 getEl : function(){
16917 * Returns the id of this component.
16920 getId : function(){
16925 * Try to focus this component.
16926 * @param {Boolean} selectText True to also select the text in this component (if applicable)
16927 * @return {Roo.Component} this
16929 focus : function(selectText){
16932 if(selectText === true){
16933 this.el.dom.select();
16948 * Disable this component.
16949 * @return {Roo.Component} this
16951 disable : function(){
16955 this.disabled = true;
16956 this.fireEvent("disable", this);
16961 onDisable : function(){
16962 this.getActionEl().addClass(this.disabledClass);
16963 this.el.dom.disabled = true;
16967 * Enable this component.
16968 * @return {Roo.Component} this
16970 enable : function(){
16974 this.disabled = false;
16975 this.fireEvent("enable", this);
16980 onEnable : function(){
16981 this.getActionEl().removeClass(this.disabledClass);
16982 this.el.dom.disabled = false;
16986 * Convenience function for setting disabled/enabled by boolean.
16987 * @param {Boolean} disabled
16989 setDisabled : function(disabled){
16990 this[disabled ? "disable" : "enable"]();
16994 * Show this component.
16995 * @return {Roo.Component} this
16998 if(this.fireEvent("beforeshow", this) !== false){
16999 this.hidden = false;
17003 this.fireEvent("show", this);
17009 onShow : function(){
17010 var ae = this.getActionEl();
17011 if(this.hideMode == 'visibility'){
17012 ae.dom.style.visibility = "visible";
17013 }else if(this.hideMode == 'offsets'){
17014 ae.removeClass('x-hidden');
17016 ae.dom.style.display = "";
17021 * Hide this component.
17022 * @return {Roo.Component} this
17025 if(this.fireEvent("beforehide", this) !== false){
17026 this.hidden = true;
17030 this.fireEvent("hide", this);
17036 onHide : function(){
17037 var ae = this.getActionEl();
17038 if(this.hideMode == 'visibility'){
17039 ae.dom.style.visibility = "hidden";
17040 }else if(this.hideMode == 'offsets'){
17041 ae.addClass('x-hidden');
17043 ae.dom.style.display = "none";
17048 * Convenience function to hide or show this component by boolean.
17049 * @param {Boolean} visible True to show, false to hide
17050 * @return {Roo.Component} this
17052 setVisible: function(visible){
17062 * Returns true if this component is visible.
17064 isVisible : function(){
17065 return this.getActionEl().isVisible();
17068 cloneConfig : function(overrides){
17069 overrides = overrides || {};
17070 var id = overrides.id || Roo.id();
17071 var cfg = Roo.applyIf(overrides, this.initialConfig);
17072 cfg.id = id; // prevent dup id
17073 return new this.constructor(cfg);
17077 * Ext JS Library 1.1.1
17078 * Copyright(c) 2006-2007, Ext JS, LLC.
17080 * Originally Released Under LGPL - original licence link has changed is not relivant.
17083 * <script type="text/javascript">
17087 * @class Roo.BoxComponent
17088 * @extends Roo.Component
17089 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
17090 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
17091 * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
17092 * layout containers.
17094 * @param {Roo.Element/String/Object} config The configuration options.
17096 Roo.BoxComponent = function(config){
17097 Roo.Component.call(this, config);
17101 * Fires after the component is resized.
17102 * @param {Roo.Component} this
17103 * @param {Number} adjWidth The box-adjusted width that was set
17104 * @param {Number} adjHeight The box-adjusted height that was set
17105 * @param {Number} rawWidth The width that was originally specified
17106 * @param {Number} rawHeight The height that was originally specified
17111 * Fires after the component is moved.
17112 * @param {Roo.Component} this
17113 * @param {Number} x The new x position
17114 * @param {Number} y The new y position
17120 Roo.extend(Roo.BoxComponent, Roo.Component, {
17121 // private, set in afterRender to signify that the component has been rendered
17123 // private, used to defer height settings to subclasses
17124 deferHeight: false,
17125 /** @cfg {Number} width
17126 * width (optional) size of component
17128 /** @cfg {Number} height
17129 * height (optional) size of component
17133 * Sets the width and height of the component. This method fires the resize event. This method can accept
17134 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
17135 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
17136 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
17137 * @return {Roo.BoxComponent} this
17139 setSize : function(w, h){
17140 // support for standard size objects
17141 if(typeof w == 'object'){
17146 if(!this.boxReady){
17152 // prevent recalcs when not needed
17153 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
17156 this.lastSize = {width: w, height: h};
17158 var adj = this.adjustSize(w, h);
17159 var aw = adj.width, ah = adj.height;
17160 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
17161 var rz = this.getResizeEl();
17162 if(!this.deferHeight && aw !== undefined && ah !== undefined){
17163 rz.setSize(aw, ah);
17164 }else if(!this.deferHeight && ah !== undefined){
17166 }else if(aw !== undefined){
17169 this.onResize(aw, ah, w, h);
17170 this.fireEvent('resize', this, aw, ah, w, h);
17176 * Gets the current size of the component's underlying element.
17177 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
17179 getSize : function(){
17180 return this.el.getSize();
17184 * Gets the current XY position of the component's underlying element.
17185 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
17186 * @return {Array} The XY position of the element (e.g., [100, 200])
17188 getPosition : function(local){
17189 if(local === true){
17190 return [this.el.getLeft(true), this.el.getTop(true)];
17192 return this.xy || this.el.getXY();
17196 * Gets the current box measurements of the component's underlying element.
17197 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
17198 * @returns {Object} box An object in the format {x, y, width, height}
17200 getBox : function(local){
17201 var s = this.el.getSize();
17203 s.x = this.el.getLeft(true);
17204 s.y = this.el.getTop(true);
17206 var xy = this.xy || this.el.getXY();
17214 * Sets the current box measurements of the component's underlying element.
17215 * @param {Object} box An object in the format {x, y, width, height}
17216 * @returns {Roo.BoxComponent} this
17218 updateBox : function(box){
17219 this.setSize(box.width, box.height);
17220 this.setPagePosition(box.x, box.y);
17225 getResizeEl : function(){
17226 return this.resizeEl || this.el;
17230 getPositionEl : function(){
17231 return this.positionEl || this.el;
17235 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
17236 * This method fires the move event.
17237 * @param {Number} left The new left
17238 * @param {Number} top The new top
17239 * @returns {Roo.BoxComponent} this
17241 setPosition : function(x, y){
17244 if(!this.boxReady){
17247 var adj = this.adjustPosition(x, y);
17248 var ax = adj.x, ay = adj.y;
17250 var el = this.getPositionEl();
17251 if(ax !== undefined || ay !== undefined){
17252 if(ax !== undefined && ay !== undefined){
17253 el.setLeftTop(ax, ay);
17254 }else if(ax !== undefined){
17256 }else if(ay !== undefined){
17259 this.onPosition(ax, ay);
17260 this.fireEvent('move', this, ax, ay);
17266 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
17267 * This method fires the move event.
17268 * @param {Number} x The new x position
17269 * @param {Number} y The new y position
17270 * @returns {Roo.BoxComponent} this
17272 setPagePosition : function(x, y){
17275 if(!this.boxReady){
17278 if(x === undefined || y === undefined){ // cannot translate undefined points
17281 var p = this.el.translatePoints(x, y);
17282 this.setPosition(p.left, p.top);
17287 onRender : function(ct, position){
17288 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
17290 this.resizeEl = Roo.get(this.resizeEl);
17292 if(this.positionEl){
17293 this.positionEl = Roo.get(this.positionEl);
17298 afterRender : function(){
17299 Roo.BoxComponent.superclass.afterRender.call(this);
17300 this.boxReady = true;
17301 this.setSize(this.width, this.height);
17302 if(this.x || this.y){
17303 this.setPosition(this.x, this.y);
17305 if(this.pageX || this.pageY){
17306 this.setPagePosition(this.pageX, this.pageY);
17311 * Force the component's size to recalculate based on the underlying element's current height and width.
17312 * @returns {Roo.BoxComponent} this
17314 syncSize : function(){
17315 delete this.lastSize;
17316 this.setSize(this.el.getWidth(), this.el.getHeight());
17321 * Called after the component is resized, this method is empty by default but can be implemented by any
17322 * subclass that needs to perform custom logic after a resize occurs.
17323 * @param {Number} adjWidth The box-adjusted width that was set
17324 * @param {Number} adjHeight The box-adjusted height that was set
17325 * @param {Number} rawWidth The width that was originally specified
17326 * @param {Number} rawHeight The height that was originally specified
17328 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
17333 * Called after the component is moved, this method is empty by default but can be implemented by any
17334 * subclass that needs to perform custom logic after a move occurs.
17335 * @param {Number} x The new x position
17336 * @param {Number} y The new y position
17338 onPosition : function(x, y){
17343 adjustSize : function(w, h){
17344 if(this.autoWidth){
17347 if(this.autoHeight){
17350 return {width : w, height: h};
17354 adjustPosition : function(x, y){
17355 return {x : x, y: y};
17359 * Ext JS Library 1.1.1
17360 * Copyright(c) 2006-2007, Ext JS, LLC.
17362 * Originally Released Under LGPL - original licence link has changed is not relivant.
17365 * <script type="text/javascript">
17370 * @extends Roo.Element
17371 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
17372 * automatic maintaining of shadow/shim positions.
17373 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
17374 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
17375 * you can pass a string with a CSS class name. False turns off the shadow.
17376 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
17377 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
17378 * @cfg {String} cls CSS class to add to the element
17379 * @cfg {Number} zindex Starting z-index (defaults to 11000)
17380 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
17382 * @param {Object} config An object with config options.
17383 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
17386 Roo.Layer = function(config, existingEl){
17387 config = config || {};
17388 var dh = Roo.DomHelper;
17389 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
17391 this.dom = Roo.getDom(existingEl);
17394 var o = config.dh || {tag: "div", cls: "x-layer"};
17395 this.dom = dh.append(pel, o);
17398 this.addClass(config.cls);
17400 this.constrain = config.constrain !== false;
17401 this.visibilityMode = Roo.Element.VISIBILITY;
17403 this.id = this.dom.id = config.id;
17405 this.id = Roo.id(this.dom);
17407 this.zindex = config.zindex || this.getZIndex();
17408 this.position("absolute", this.zindex);
17410 this.shadowOffset = config.shadowOffset || 4;
17411 this.shadow = new Roo.Shadow({
17412 offset : this.shadowOffset,
17413 mode : config.shadow
17416 this.shadowOffset = 0;
17418 this.useShim = config.shim !== false && Roo.useShims;
17419 this.useDisplay = config.useDisplay;
17423 var supr = Roo.Element.prototype;
17425 // shims are shared among layer to keep from having 100 iframes
17428 Roo.extend(Roo.Layer, Roo.Element, {
17430 getZIndex : function(){
17431 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
17434 getShim : function(){
17441 var shim = shims.shift();
17443 shim = this.createShim();
17444 shim.enableDisplayMode('block');
17445 shim.dom.style.display = 'none';
17446 shim.dom.style.visibility = 'visible';
17448 var pn = this.dom.parentNode;
17449 if(shim.dom.parentNode != pn){
17450 pn.insertBefore(shim.dom, this.dom);
17452 shim.setStyle('z-index', this.getZIndex()-2);
17457 hideShim : function(){
17459 this.shim.setDisplayed(false);
17460 shims.push(this.shim);
17465 disableShadow : function(){
17467 this.shadowDisabled = true;
17468 this.shadow.hide();
17469 this.lastShadowOffset = this.shadowOffset;
17470 this.shadowOffset = 0;
17474 enableShadow : function(show){
17476 this.shadowDisabled = false;
17477 this.shadowOffset = this.lastShadowOffset;
17478 delete this.lastShadowOffset;
17486 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
17487 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
17488 sync : function(doShow){
17489 var sw = this.shadow;
17490 if(!this.updating && this.isVisible() && (sw || this.useShim)){
17491 var sh = this.getShim();
17493 var w = this.getWidth(),
17494 h = this.getHeight();
17496 var l = this.getLeft(true),
17497 t = this.getTop(true);
17499 if(sw && !this.shadowDisabled){
17500 if(doShow && !sw.isVisible()){
17503 sw.realign(l, t, w, h);
17509 // fit the shim behind the shadow, so it is shimmed too
17510 var a = sw.adjusts, s = sh.dom.style;
17511 s.left = (Math.min(l, l+a.l))+"px";
17512 s.top = (Math.min(t, t+a.t))+"px";
17513 s.width = (w+a.w)+"px";
17514 s.height = (h+a.h)+"px";
17521 sh.setLeftTop(l, t);
17528 destroy : function(){
17531 this.shadow.hide();
17533 this.removeAllListeners();
17534 var pn = this.dom.parentNode;
17536 pn.removeChild(this.dom);
17538 Roo.Element.uncache(this.id);
17541 remove : function(){
17546 beginUpdate : function(){
17547 this.updating = true;
17551 endUpdate : function(){
17552 this.updating = false;
17557 hideUnders : function(negOffset){
17559 this.shadow.hide();
17565 constrainXY : function(){
17566 if(this.constrain){
17567 var vw = Roo.lib.Dom.getViewWidth(),
17568 vh = Roo.lib.Dom.getViewHeight();
17569 var s = Roo.get(document).getScroll();
17571 var xy = this.getXY();
17572 var x = xy[0], y = xy[1];
17573 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
17574 // only move it if it needs it
17576 // first validate right/bottom
17577 if((x + w) > vw+s.left){
17578 x = vw - w - this.shadowOffset;
17581 if((y + h) > vh+s.top){
17582 y = vh - h - this.shadowOffset;
17585 // then make sure top/left isn't negative
17596 var ay = this.avoidY;
17597 if(y <= ay && (y+h) >= ay){
17603 supr.setXY.call(this, xy);
17609 isVisible : function(){
17610 return this.visible;
17614 showAction : function(){
17615 this.visible = true; // track visibility to prevent getStyle calls
17616 if(this.useDisplay === true){
17617 this.setDisplayed("");
17618 }else if(this.lastXY){
17619 supr.setXY.call(this, this.lastXY);
17620 }else if(this.lastLT){
17621 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
17626 hideAction : function(){
17627 this.visible = false;
17628 if(this.useDisplay === true){
17629 this.setDisplayed(false);
17631 this.setLeftTop(-10000,-10000);
17635 // overridden Element method
17636 setVisible : function(v, a, d, c, e){
17641 var cb = function(){
17646 }.createDelegate(this);
17647 supr.setVisible.call(this, true, true, d, cb, e);
17650 this.hideUnders(true);
17659 }.createDelegate(this);
17661 supr.setVisible.call(this, v, a, d, cb, e);
17670 storeXY : function(xy){
17671 delete this.lastLT;
17675 storeLeftTop : function(left, top){
17676 delete this.lastXY;
17677 this.lastLT = [left, top];
17681 beforeFx : function(){
17682 this.beforeAction();
17683 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
17687 afterFx : function(){
17688 Roo.Layer.superclass.afterFx.apply(this, arguments);
17689 this.sync(this.isVisible());
17693 beforeAction : function(){
17694 if(!this.updating && this.shadow){
17695 this.shadow.hide();
17699 // overridden Element method
17700 setLeft : function(left){
17701 this.storeLeftTop(left, this.getTop(true));
17702 supr.setLeft.apply(this, arguments);
17706 setTop : function(top){
17707 this.storeLeftTop(this.getLeft(true), top);
17708 supr.setTop.apply(this, arguments);
17712 setLeftTop : function(left, top){
17713 this.storeLeftTop(left, top);
17714 supr.setLeftTop.apply(this, arguments);
17718 setXY : function(xy, a, d, c, e){
17720 this.beforeAction();
17722 var cb = this.createCB(c);
17723 supr.setXY.call(this, xy, a, d, cb, e);
17730 createCB : function(c){
17741 // overridden Element method
17742 setX : function(x, a, d, c, e){
17743 this.setXY([x, this.getY()], a, d, c, e);
17746 // overridden Element method
17747 setY : function(y, a, d, c, e){
17748 this.setXY([this.getX(), y], a, d, c, e);
17751 // overridden Element method
17752 setSize : function(w, h, a, d, c, e){
17753 this.beforeAction();
17754 var cb = this.createCB(c);
17755 supr.setSize.call(this, w, h, a, d, cb, e);
17761 // overridden Element method
17762 setWidth : function(w, a, d, c, e){
17763 this.beforeAction();
17764 var cb = this.createCB(c);
17765 supr.setWidth.call(this, w, a, d, cb, e);
17771 // overridden Element method
17772 setHeight : function(h, a, d, c, e){
17773 this.beforeAction();
17774 var cb = this.createCB(c);
17775 supr.setHeight.call(this, h, a, d, cb, e);
17781 // overridden Element method
17782 setBounds : function(x, y, w, h, a, d, c, e){
17783 this.beforeAction();
17784 var cb = this.createCB(c);
17786 this.storeXY([x, y]);
17787 supr.setXY.call(this, [x, y]);
17788 supr.setSize.call(this, w, h, a, d, cb, e);
17791 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
17797 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
17798 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
17799 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
17800 * @param {Number} zindex The new z-index to set
17801 * @return {this} The Layer
17803 setZIndex : function(zindex){
17804 this.zindex = zindex;
17805 this.setStyle("z-index", zindex + 2);
17807 this.shadow.setZIndex(zindex + 1);
17810 this.shim.setStyle("z-index", zindex);
17815 * Original code for Roojs - LGPL
17816 * <script type="text/javascript">
17820 * @class Roo.XComponent
17821 * A delayed Element creator...
17822 * Or a way to group chunks of interface together.
17823 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
17824 * used in conjunction with XComponent.build() it will create an instance of each element,
17825 * then call addxtype() to build the User interface.
17827 * Mypart.xyx = new Roo.XComponent({
17829 parent : 'Mypart.xyz', // empty == document.element.!!
17833 disabled : function() {}
17835 tree : function() { // return an tree of xtype declared components
17839 xtype : 'NestedLayoutPanel',
17846 * It can be used to build a big heiracy, with parent etc.
17847 * or you can just use this to render a single compoent to a dom element
17848 * MYPART.render(Roo.Element | String(id) | dom_element )
17855 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
17856 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
17858 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
17860 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
17861 * - if mulitple topModules exist, the last one is defined as the top module.
17865 * When the top level or multiple modules are to embedded into a existing HTML page,
17866 * the parent element can container '#id' of the element where the module will be drawn.
17870 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
17871 * it relies more on a include mechanism, where sub modules are included into an outer page.
17872 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
17874 * Bootstrap Roo Included elements
17876 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
17877 * hence confusing the component builder as it thinks there are multiple top level elements.
17879 * String Over-ride & Translations
17881 * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
17882 * and also the 'overlaying of string values - needed when different versions of the same application with different text content
17883 * are needed. @see Roo.XComponent.overlayString
17887 * @extends Roo.util.Observable
17889 * @param cfg {Object} configuration of component
17892 Roo.XComponent = function(cfg) {
17893 Roo.apply(this, cfg);
17897 * Fires when this the componnt is built
17898 * @param {Roo.XComponent} c the component
17903 this.region = this.region || 'center'; // default..
17904 Roo.XComponent.register(this);
17905 this.modules = false;
17906 this.el = false; // where the layout goes..
17910 Roo.extend(Roo.XComponent, Roo.util.Observable, {
17913 * The created element (with Roo.factory())
17914 * @type {Roo.Layout}
17920 * for BC - use el in new code
17921 * @type {Roo.Layout}
17927 * for BC - use el in new code
17928 * @type {Roo.Layout}
17933 * @cfg {Function|boolean} disabled
17934 * If this module is disabled by some rule, return true from the funtion
17939 * @cfg {String} parent
17940 * Name of parent element which it get xtype added to..
17945 * @cfg {String} order
17946 * Used to set the order in which elements are created (usefull for multiple tabs)
17951 * @cfg {String} name
17952 * String to display while loading.
17956 * @cfg {String} region
17957 * Region to render component to (defaults to center)
17962 * @cfg {Array} items
17963 * A single item array - the first element is the root of the tree..
17964 * It's done this way to stay compatible with the Xtype system...
17970 * The method that retuns the tree of parts that make up this compoennt
17977 * render element to dom or tree
17978 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
17981 render : function(el)
17985 var hp = this.parent ? 1 : 0;
17986 Roo.debug && Roo.log(this);
17988 var tree = this._tree ? this._tree() : this.tree();
17991 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
17992 // if parent is a '#.....' string, then let's use that..
17993 var ename = this.parent.substr(1);
17994 this.parent = false;
17995 Roo.debug && Roo.log(ename);
17997 case 'bootstrap-body':
17998 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
17999 // this is the BorderLayout standard?
18000 this.parent = { el : true };
18003 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
18004 // need to insert stuff...
18006 el : new Roo.bootstrap.layout.Border({
18007 el : document.body,
18013 tabPosition: 'top',
18014 //resizeTabs: true,
18015 alwaysShowTabs: true,
18025 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
18026 this.parent = { el : new Roo.bootstrap.Body() };
18027 Roo.debug && Roo.log("setting el to doc body");
18030 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
18034 this.parent = { el : true};
18037 el = Roo.get(ename);
18038 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
18039 this.parent = { el : true};
18046 if (!el && !this.parent) {
18047 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
18052 Roo.debug && Roo.log("EL:");
18053 Roo.debug && Roo.log(el);
18054 Roo.debug && Roo.log("this.parent.el:");
18055 Roo.debug && Roo.log(this.parent.el);
18058 // altertive root elements ??? - we need a better way to indicate these.
18059 var is_alt = Roo.XComponent.is_alt ||
18060 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
18061 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
18062 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
18066 if (!this.parent && is_alt) {
18067 //el = Roo.get(document.body);
18068 this.parent = { el : true };
18073 if (!this.parent) {
18075 Roo.debug && Roo.log("no parent - creating one");
18077 el = el ? Roo.get(el) : false;
18079 if (typeof(Roo.BorderLayout) == 'undefined' ) {
18082 el : new Roo.bootstrap.layout.Border({
18083 el: el || document.body,
18089 tabPosition: 'top',
18090 //resizeTabs: true,
18091 alwaysShowTabs: false,
18094 overflow: 'visible'
18100 // it's a top level one..
18102 el : new Roo.BorderLayout(el || document.body, {
18107 tabPosition: 'top',
18108 //resizeTabs: true,
18109 alwaysShowTabs: el && hp? false : true,
18110 hideTabs: el || !hp ? true : false,
18118 if (!this.parent.el) {
18119 // probably an old style ctor, which has been disabled.
18123 // The 'tree' method is '_tree now'
18125 tree.region = tree.region || this.region;
18126 var is_body = false;
18127 if (this.parent.el === true) {
18128 // bootstrap... - body..
18132 this.parent.el = Roo.factory(tree);
18136 this.el = this.parent.el.addxtype(tree, undefined, is_body);
18137 this.fireEvent('built', this);
18139 this.panel = this.el;
18140 this.layout = this.panel.layout;
18141 this.parentLayout = this.parent.layout || false;
18147 Roo.apply(Roo.XComponent, {
18149 * @property hideProgress
18150 * true to disable the building progress bar.. usefull on single page renders.
18153 hideProgress : false,
18155 * @property buildCompleted
18156 * True when the builder has completed building the interface.
18159 buildCompleted : false,
18162 * @property topModule
18163 * the upper most module - uses document.element as it's constructor.
18170 * @property modules
18171 * array of modules to be created by registration system.
18172 * @type {Array} of Roo.XComponent
18177 * @property elmodules
18178 * array of modules to be created by which use #ID
18179 * @type {Array} of Roo.XComponent
18186 * Is an alternative Root - normally used by bootstrap or other systems,
18187 * where the top element in the tree can wrap 'body'
18188 * @type {boolean} (default false)
18193 * @property build_from_html
18194 * Build elements from html - used by bootstrap HTML stuff
18195 * - this is cleared after build is completed
18196 * @type {boolean} (default false)
18199 build_from_html : false,
18201 * Register components to be built later.
18203 * This solves the following issues
18204 * - Building is not done on page load, but after an authentication process has occured.
18205 * - Interface elements are registered on page load
18206 * - Parent Interface elements may not be loaded before child, so this handles that..
18213 module : 'Pman.Tab.projectMgr',
18215 parent : 'Pman.layout',
18216 disabled : false, // or use a function..
18219 * * @param {Object} details about module
18221 register : function(obj) {
18223 Roo.XComponent.event.fireEvent('register', obj);
18224 switch(typeof(obj.disabled) ) {
18230 if ( obj.disabled() ) {
18236 if (obj.disabled || obj.region == '#disabled') {
18242 this.modules.push(obj);
18246 * convert a string to an object..
18247 * eg. 'AAA.BBB' -> finds AAA.BBB
18251 toObject : function(str)
18253 if (!str || typeof(str) == 'object') {
18256 if (str.substring(0,1) == '#') {
18260 var ar = str.split('.');
18265 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
18267 throw "Module not found : " + str;
18271 throw "Module not found : " + str;
18273 Roo.each(ar, function(e) {
18274 if (typeof(o[e]) == 'undefined') {
18275 throw "Module not found : " + str;
18286 * move modules into their correct place in the tree..
18289 preBuild : function ()
18292 Roo.each(this.modules , function (obj)
18294 Roo.XComponent.event.fireEvent('beforebuild', obj);
18296 var opar = obj.parent;
18298 obj.parent = this.toObject(opar);
18300 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
18305 Roo.debug && Roo.log("GOT top level module");
18306 Roo.debug && Roo.log(obj);
18307 obj.modules = new Roo.util.MixedCollection(false,
18308 function(o) { return o.order + '' }
18310 this.topModule = obj;
18313 // parent is a string (usually a dom element name..)
18314 if (typeof(obj.parent) == 'string') {
18315 this.elmodules.push(obj);
18318 if (obj.parent.constructor != Roo.XComponent) {
18319 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
18321 if (!obj.parent.modules) {
18322 obj.parent.modules = new Roo.util.MixedCollection(false,
18323 function(o) { return o.order + '' }
18326 if (obj.parent.disabled) {
18327 obj.disabled = true;
18329 obj.parent.modules.add(obj);
18334 * make a list of modules to build.
18335 * @return {Array} list of modules.
18338 buildOrder : function()
18341 var cmp = function(a,b) {
18342 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
18344 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
18345 throw "No top level modules to build";
18348 // make a flat list in order of modules to build.
18349 var mods = this.topModule ? [ this.topModule ] : [];
18352 // elmodules (is a list of DOM based modules )
18353 Roo.each(this.elmodules, function(e) {
18355 if (!this.topModule &&
18356 typeof(e.parent) == 'string' &&
18357 e.parent.substring(0,1) == '#' &&
18358 Roo.get(e.parent.substr(1))
18361 _this.topModule = e;
18367 // add modules to their parents..
18368 var addMod = function(m) {
18369 Roo.debug && Roo.log("build Order: add: " + m.name);
18372 if (m.modules && !m.disabled) {
18373 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
18374 m.modules.keySort('ASC', cmp );
18375 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
18377 m.modules.each(addMod);
18379 Roo.debug && Roo.log("build Order: no child modules");
18381 // not sure if this is used any more..
18383 m.finalize.name = m.name + " (clean up) ";
18384 mods.push(m.finalize);
18388 if (this.topModule && this.topModule.modules) {
18389 this.topModule.modules.keySort('ASC', cmp );
18390 this.topModule.modules.each(addMod);
18396 * Build the registered modules.
18397 * @param {Object} parent element.
18398 * @param {Function} optional method to call after module has been added.
18402 build : function(opts)
18405 if (typeof(opts) != 'undefined') {
18406 Roo.apply(this,opts);
18410 var mods = this.buildOrder();
18412 //this.allmods = mods;
18413 //Roo.debug && Roo.log(mods);
18415 if (!mods.length) { // should not happen
18416 throw "NO modules!!!";
18420 var msg = "Building Interface...";
18421 // flash it up as modal - so we store the mask!?
18422 if (!this.hideProgress && Roo.MessageBox) {
18423 Roo.MessageBox.show({ title: 'loading' });
18424 Roo.MessageBox.show({
18425 title: "Please wait...",
18435 var total = mods.length;
18438 var progressRun = function() {
18439 if (!mods.length) {
18440 Roo.debug && Roo.log('hide?');
18441 if (!this.hideProgress && Roo.MessageBox) {
18442 Roo.MessageBox.hide();
18444 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
18446 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
18452 var m = mods.shift();
18455 Roo.debug && Roo.log(m);
18456 // not sure if this is supported any more.. - modules that are are just function
18457 if (typeof(m) == 'function') {
18459 return progressRun.defer(10, _this);
18463 msg = "Building Interface " + (total - mods.length) +
18465 (m.name ? (' - ' + m.name) : '');
18466 Roo.debug && Roo.log(msg);
18467 if (!_this.hideProgress && Roo.MessageBox) {
18468 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
18472 // is the module disabled?
18473 var disabled = (typeof(m.disabled) == 'function') ?
18474 m.disabled.call(m.module.disabled) : m.disabled;
18478 return progressRun(); // we do not update the display!
18486 // it's 10 on top level, and 1 on others??? why...
18487 return progressRun.defer(10, _this);
18490 progressRun.defer(1, _this);
18496 * Overlay a set of modified strings onto a component
18497 * This is dependant on our builder exporting the strings and 'named strings' elements.
18499 * @param {Object} element to overlay on - eg. Pman.Dialog.Login
18500 * @param {Object} associative array of 'named' string and it's new value.
18503 overlayStrings : function( component, strings )
18505 if (typeof(component['_named_strings']) == 'undefined') {
18506 throw "ERROR: component does not have _named_strings";
18508 for ( var k in strings ) {
18509 var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
18510 if (md !== false) {
18511 component['_strings'][md] = strings[k];
18513 Roo.log('could not find named string: ' + k + ' in');
18514 Roo.log(component);
18529 * wrapper for event.on - aliased later..
18530 * Typically use to register a event handler for register:
18532 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
18541 Roo.XComponent.event = new Roo.util.Observable({
18545 * Fires when an Component is registered,
18546 * set the disable property on the Component to stop registration.
18547 * @param {Roo.XComponent} c the component being registerd.
18552 * @event beforebuild
18553 * Fires before each Component is built
18554 * can be used to apply permissions.
18555 * @param {Roo.XComponent} c the component being registerd.
18558 'beforebuild' : true,
18560 * @event buildcomplete
18561 * Fires on the top level element when all elements have been built
18562 * @param {Roo.XComponent} the top level component.
18564 'buildcomplete' : true
18569 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
18572 * marked - a markdown parser
18573 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
18574 * https://github.com/chjj/marked
18580 * Roo.Markdown - is a very crude wrapper around marked..
18584 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
18586 * Note: move the sample code to the bottom of this
18587 * file before uncommenting it.
18592 Roo.Markdown.toHtml = function(text) {
18594 var c = new Roo.Markdown.marked.setOptions({
18595 renderer: new Roo.Markdown.marked.Renderer(),
18606 text = text.replace(/\\\n/g,' ');
18607 return Roo.Markdown.marked(text);
18612 // Wraps all "globals" so that the only thing
18613 // exposed is makeHtml().
18619 * eval:var:unescape
18627 var escape = function (html, encode) {
18629 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
18630 .replace(/</g, '<')
18631 .replace(/>/g, '>')
18632 .replace(/"/g, '"')
18633 .replace(/'/g, ''');
18636 var unescape = function (html) {
18637 // explicitly match decimal, hex, and named HTML entities
18638 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
18639 n = n.toLowerCase();
18640 if (n === 'colon') { return ':'; }
18641 if (n.charAt(0) === '#') {
18642 return n.charAt(1) === 'x'
18643 ? String.fromCharCode(parseInt(n.substring(2), 16))
18644 : String.fromCharCode(+n.substring(1));
18650 var replace = function (regex, opt) {
18651 regex = regex.source;
18653 return function self(name, val) {
18654 if (!name) { return new RegExp(regex, opt); }
18655 val = val.source || val;
18656 val = val.replace(/(^|[^\[])\^/g, '$1');
18657 regex = regex.replace(name, val);
18666 var noop = function () {}
18672 var merge = function (obj) {
18677 for (; i < arguments.length; i++) {
18678 target = arguments[i];
18679 for (key in target) {
18680 if (Object.prototype.hasOwnProperty.call(target, key)) {
18681 obj[key] = target[key];
18691 * Block-Level Grammar
18699 code: /^( {4}[^\n]+\n*)+/,
18701 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
18702 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
18704 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
18705 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
18706 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
18707 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
18708 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
18710 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
18714 block.bullet = /(?:[*+-]|\d+\.)/;
18715 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
18716 block.item = replace(block.item, 'gm')
18717 (/bull/g, block.bullet)
18720 block.list = replace(block.list)
18721 (/bull/g, block.bullet)
18722 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
18723 ('def', '\\n+(?=' + block.def.source + ')')
18726 block.blockquote = replace(block.blockquote)
18730 block._tag = '(?!(?:'
18731 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
18732 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
18733 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
18735 block.html = replace(block.html)
18736 ('comment', /<!--[\s\S]*?-->/)
18737 ('closed', /<(tag)[\s\S]+?<\/\1>/)
18738 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
18739 (/tag/g, block._tag)
18742 block.paragraph = replace(block.paragraph)
18744 ('heading', block.heading)
18745 ('lheading', block.lheading)
18746 ('blockquote', block.blockquote)
18747 ('tag', '<' + block._tag)
18752 * Normal Block Grammar
18755 block.normal = merge({}, block);
18758 * GFM Block Grammar
18761 block.gfm = merge({}, block.normal, {
18762 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
18764 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
18767 block.gfm.paragraph = replace(block.paragraph)
18769 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
18770 + block.list.source.replace('\\1', '\\3') + '|')
18774 * GFM + Tables Block Grammar
18777 block.tables = merge({}, block.gfm, {
18778 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
18779 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
18786 var Lexer = function (options) {
18788 this.tokens.links = {};
18789 this.options = options || marked.defaults;
18790 this.rules = block.normal;
18792 if (this.options.gfm) {
18793 if (this.options.tables) {
18794 this.rules = block.tables;
18796 this.rules = block.gfm;
18802 * Expose Block Rules
18805 Lexer.rules = block;
18808 * Static Lex Method
18811 Lexer.lex = function(src, options) {
18812 var lexer = new Lexer(options);
18813 return lexer.lex(src);
18820 Lexer.prototype.lex = function(src) {
18822 .replace(/\r\n|\r/g, '\n')
18823 .replace(/\t/g, ' ')
18824 .replace(/\u00a0/g, ' ')
18825 .replace(/\u2424/g, '\n');
18827 return this.token(src, true);
18834 Lexer.prototype.token = function(src, top, bq) {
18835 var src = src.replace(/^ +$/gm, '')
18848 if (cap = this.rules.newline.exec(src)) {
18849 src = src.substring(cap[0].length);
18850 if (cap[0].length > 1) {
18858 if (cap = this.rules.code.exec(src)) {
18859 src = src.substring(cap[0].length);
18860 cap = cap[0].replace(/^ {4}/gm, '');
18863 text: !this.options.pedantic
18864 ? cap.replace(/\n+$/, '')
18871 if (cap = this.rules.fences.exec(src)) {
18872 src = src.substring(cap[0].length);
18882 if (cap = this.rules.heading.exec(src)) {
18883 src = src.substring(cap[0].length);
18886 depth: cap[1].length,
18892 // table no leading pipe (gfm)
18893 if (top && (cap = this.rules.nptable.exec(src))) {
18894 src = src.substring(cap[0].length);
18898 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18899 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18900 cells: cap[3].replace(/\n$/, '').split('\n')
18903 for (i = 0; i < item.align.length; i++) {
18904 if (/^ *-+: *$/.test(item.align[i])) {
18905 item.align[i] = 'right';
18906 } else if (/^ *:-+: *$/.test(item.align[i])) {
18907 item.align[i] = 'center';
18908 } else if (/^ *:-+ *$/.test(item.align[i])) {
18909 item.align[i] = 'left';
18911 item.align[i] = null;
18915 for (i = 0; i < item.cells.length; i++) {
18916 item.cells[i] = item.cells[i].split(/ *\| */);
18919 this.tokens.push(item);
18925 if (cap = this.rules.lheading.exec(src)) {
18926 src = src.substring(cap[0].length);
18929 depth: cap[2] === '=' ? 1 : 2,
18936 if (cap = this.rules.hr.exec(src)) {
18937 src = src.substring(cap[0].length);
18945 if (cap = this.rules.blockquote.exec(src)) {
18946 src = src.substring(cap[0].length);
18949 type: 'blockquote_start'
18952 cap = cap[0].replace(/^ *> ?/gm, '');
18954 // Pass `top` to keep the current
18955 // "toplevel" state. This is exactly
18956 // how markdown.pl works.
18957 this.token(cap, top, true);
18960 type: 'blockquote_end'
18967 if (cap = this.rules.list.exec(src)) {
18968 src = src.substring(cap[0].length);
18972 type: 'list_start',
18973 ordered: bull.length > 1
18976 // Get each top-level item.
18977 cap = cap[0].match(this.rules.item);
18983 for (; i < l; i++) {
18986 // Remove the list item's bullet
18987 // so it is seen as the next token.
18988 space = item.length;
18989 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
18991 // Outdent whatever the
18992 // list item contains. Hacky.
18993 if (~item.indexOf('\n ')) {
18994 space -= item.length;
18995 item = !this.options.pedantic
18996 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
18997 : item.replace(/^ {1,4}/gm, '');
19000 // Determine whether the next list item belongs here.
19001 // Backpedal if it does not belong in this list.
19002 if (this.options.smartLists && i !== l - 1) {
19003 b = block.bullet.exec(cap[i + 1])[0];
19004 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
19005 src = cap.slice(i + 1).join('\n') + src;
19010 // Determine whether item is loose or not.
19011 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
19012 // for discount behavior.
19013 loose = next || /\n\n(?!\s*$)/.test(item);
19015 next = item.charAt(item.length - 1) === '\n';
19016 if (!loose) { loose = next; }
19021 ? 'loose_item_start'
19022 : 'list_item_start'
19026 this.token(item, false, bq);
19029 type: 'list_item_end'
19041 if (cap = this.rules.html.exec(src)) {
19042 src = src.substring(cap[0].length);
19044 type: this.options.sanitize
19047 pre: !this.options.sanitizer
19048 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
19055 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
19056 src = src.substring(cap[0].length);
19057 this.tokens.links[cap[1].toLowerCase()] = {
19065 if (top && (cap = this.rules.table.exec(src))) {
19066 src = src.substring(cap[0].length);
19070 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
19071 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
19072 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
19075 for (i = 0; i < item.align.length; i++) {
19076 if (/^ *-+: *$/.test(item.align[i])) {
19077 item.align[i] = 'right';
19078 } else if (/^ *:-+: *$/.test(item.align[i])) {
19079 item.align[i] = 'center';
19080 } else if (/^ *:-+ *$/.test(item.align[i])) {
19081 item.align[i] = 'left';
19083 item.align[i] = null;
19087 for (i = 0; i < item.cells.length; i++) {
19088 item.cells[i] = item.cells[i]
19089 .replace(/^ *\| *| *\| *$/g, '')
19093 this.tokens.push(item);
19098 // top-level paragraph
19099 if (top && (cap = this.rules.paragraph.exec(src))) {
19100 src = src.substring(cap[0].length);
19103 text: cap[1].charAt(cap[1].length - 1) === '\n'
19104 ? cap[1].slice(0, -1)
19111 if (cap = this.rules.text.exec(src)) {
19112 // Top-level should never reach here.
19113 src = src.substring(cap[0].length);
19123 Error('Infinite loop on byte: ' + src.charCodeAt(0));
19127 return this.tokens;
19131 * Inline-Level Grammar
19135 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
19136 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
19138 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
19139 link: /^!?\[(inside)\]\(href\)/,
19140 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
19141 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
19142 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
19143 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
19144 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
19145 br: /^ {2,}\n(?!\s*$)/,
19147 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
19150 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
19151 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
19153 inline.link = replace(inline.link)
19154 ('inside', inline._inside)
19155 ('href', inline._href)
19158 inline.reflink = replace(inline.reflink)
19159 ('inside', inline._inside)
19163 * Normal Inline Grammar
19166 inline.normal = merge({}, inline);
19169 * Pedantic Inline Grammar
19172 inline.pedantic = merge({}, inline.normal, {
19173 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
19174 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
19178 * GFM Inline Grammar
19181 inline.gfm = merge({}, inline.normal, {
19182 escape: replace(inline.escape)('])', '~|])')(),
19183 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
19184 del: /^~~(?=\S)([\s\S]*?\S)~~/,
19185 text: replace(inline.text)
19187 ('|', '|https?://|')
19192 * GFM + Line Breaks Inline Grammar
19195 inline.breaks = merge({}, inline.gfm, {
19196 br: replace(inline.br)('{2,}', '*')(),
19197 text: replace(inline.gfm.text)('{2,}', '*')()
19201 * Inline Lexer & Compiler
19204 var InlineLexer = function (links, options) {
19205 this.options = options || marked.defaults;
19206 this.links = links;
19207 this.rules = inline.normal;
19208 this.renderer = this.options.renderer || new Renderer;
19209 this.renderer.options = this.options;
19213 Error('Tokens array requires a `links` property.');
19216 if (this.options.gfm) {
19217 if (this.options.breaks) {
19218 this.rules = inline.breaks;
19220 this.rules = inline.gfm;
19222 } else if (this.options.pedantic) {
19223 this.rules = inline.pedantic;
19228 * Expose Inline Rules
19231 InlineLexer.rules = inline;
19234 * Static Lexing/Compiling Method
19237 InlineLexer.output = function(src, links, options) {
19238 var inline = new InlineLexer(links, options);
19239 return inline.output(src);
19246 InlineLexer.prototype.output = function(src) {
19255 if (cap = this.rules.escape.exec(src)) {
19256 src = src.substring(cap[0].length);
19262 if (cap = this.rules.autolink.exec(src)) {
19263 src = src.substring(cap[0].length);
19264 if (cap[2] === '@') {
19265 text = cap[1].charAt(6) === ':'
19266 ? this.mangle(cap[1].substring(7))
19267 : this.mangle(cap[1]);
19268 href = this.mangle('mailto:') + text;
19270 text = escape(cap[1]);
19273 out += this.renderer.link(href, null, text);
19278 if (!this.inLink && (cap = this.rules.url.exec(src))) {
19279 src = src.substring(cap[0].length);
19280 text = escape(cap[1]);
19282 out += this.renderer.link(href, null, text);
19287 if (cap = this.rules.tag.exec(src)) {
19288 if (!this.inLink && /^<a /i.test(cap[0])) {
19289 this.inLink = true;
19290 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
19291 this.inLink = false;
19293 src = src.substring(cap[0].length);
19294 out += this.options.sanitize
19295 ? this.options.sanitizer
19296 ? this.options.sanitizer(cap[0])
19303 if (cap = this.rules.link.exec(src)) {
19304 src = src.substring(cap[0].length);
19305 this.inLink = true;
19306 out += this.outputLink(cap, {
19310 this.inLink = false;
19315 if ((cap = this.rules.reflink.exec(src))
19316 || (cap = this.rules.nolink.exec(src))) {
19317 src = src.substring(cap[0].length);
19318 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
19319 link = this.links[link.toLowerCase()];
19320 if (!link || !link.href) {
19321 out += cap[0].charAt(0);
19322 src = cap[0].substring(1) + src;
19325 this.inLink = true;
19326 out += this.outputLink(cap, link);
19327 this.inLink = false;
19332 if (cap = this.rules.strong.exec(src)) {
19333 src = src.substring(cap[0].length);
19334 out += this.renderer.strong(this.output(cap[2] || cap[1]));
19339 if (cap = this.rules.em.exec(src)) {
19340 src = src.substring(cap[0].length);
19341 out += this.renderer.em(this.output(cap[2] || cap[1]));
19346 if (cap = this.rules.code.exec(src)) {
19347 src = src.substring(cap[0].length);
19348 out += this.renderer.codespan(escape(cap[2], true));
19353 if (cap = this.rules.br.exec(src)) {
19354 src = src.substring(cap[0].length);
19355 out += this.renderer.br();
19360 if (cap = this.rules.del.exec(src)) {
19361 src = src.substring(cap[0].length);
19362 out += this.renderer.del(this.output(cap[1]));
19367 if (cap = this.rules.text.exec(src)) {
19368 src = src.substring(cap[0].length);
19369 out += this.renderer.text(escape(this.smartypants(cap[0])));
19375 Error('Infinite loop on byte: ' + src.charCodeAt(0));
19386 InlineLexer.prototype.outputLink = function(cap, link) {
19387 var href = escape(link.href)
19388 , title = link.title ? escape(link.title) : null;
19390 return cap[0].charAt(0) !== '!'
19391 ? this.renderer.link(href, title, this.output(cap[1]))
19392 : this.renderer.image(href, title, escape(cap[1]));
19396 * Smartypants Transformations
19399 InlineLexer.prototype.smartypants = function(text) {
19400 if (!this.options.smartypants) { return text; }
19403 .replace(/---/g, '\u2014')
19405 .replace(/--/g, '\u2013')
19407 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
19408 // closing singles & apostrophes
19409 .replace(/'/g, '\u2019')
19411 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
19413 .replace(/"/g, '\u201d')
19415 .replace(/\.{3}/g, '\u2026');
19422 InlineLexer.prototype.mangle = function(text) {
19423 if (!this.options.mangle) { return text; }
19429 for (; i < l; i++) {
19430 ch = text.charCodeAt(i);
19431 if (Math.random() > 0.5) {
19432 ch = 'x' + ch.toString(16);
19434 out += '&#' + ch + ';';
19445 * eval:var:Renderer
19448 var Renderer = function (options) {
19449 this.options = options || {};
19452 Renderer.prototype.code = function(code, lang, escaped) {
19453 if (this.options.highlight) {
19454 var out = this.options.highlight(code, lang);
19455 if (out != null && out !== code) {
19460 // hack!!! - it's already escapeD?
19465 return '<pre><code>'
19466 + (escaped ? code : escape(code, true))
19467 + '\n</code></pre>';
19470 return '<pre><code class="'
19471 + this.options.langPrefix
19472 + escape(lang, true)
19474 + (escaped ? code : escape(code, true))
19475 + '\n</code></pre>\n';
19478 Renderer.prototype.blockquote = function(quote) {
19479 return '<blockquote>\n' + quote + '</blockquote>\n';
19482 Renderer.prototype.html = function(html) {
19486 Renderer.prototype.heading = function(text, level, raw) {
19490 + this.options.headerPrefix
19491 + raw.toLowerCase().replace(/[^\w]+/g, '-')
19499 Renderer.prototype.hr = function() {
19500 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
19503 Renderer.prototype.list = function(body, ordered) {
19504 var type = ordered ? 'ol' : 'ul';
19505 return '<' + type + '>\n' + body + '</' + type + '>\n';
19508 Renderer.prototype.listitem = function(text) {
19509 return '<li>' + text + '</li>\n';
19512 Renderer.prototype.paragraph = function(text) {
19513 return '<p>' + text + '</p>\n';
19516 Renderer.prototype.table = function(header, body) {
19517 return '<table class="table table-striped">\n'
19527 Renderer.prototype.tablerow = function(content) {
19528 return '<tr>\n' + content + '</tr>\n';
19531 Renderer.prototype.tablecell = function(content, flags) {
19532 var type = flags.header ? 'th' : 'td';
19533 var tag = flags.align
19534 ? '<' + type + ' style="text-align:' + flags.align + '">'
19535 : '<' + type + '>';
19536 return tag + content + '</' + type + '>\n';
19539 // span level renderer
19540 Renderer.prototype.strong = function(text) {
19541 return '<strong>' + text + '</strong>';
19544 Renderer.prototype.em = function(text) {
19545 return '<em>' + text + '</em>';
19548 Renderer.prototype.codespan = function(text) {
19549 return '<code>' + text + '</code>';
19552 Renderer.prototype.br = function() {
19553 return this.options.xhtml ? '<br/>' : '<br>';
19556 Renderer.prototype.del = function(text) {
19557 return '<del>' + text + '</del>';
19560 Renderer.prototype.link = function(href, title, text) {
19561 if (this.options.sanitize) {
19563 var prot = decodeURIComponent(unescape(href))
19564 .replace(/[^\w:]/g, '')
19569 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
19573 var out = '<a href="' + href + '"';
19575 out += ' title="' + title + '"';
19577 out += '>' + text + '</a>';
19581 Renderer.prototype.image = function(href, title, text) {
19582 var out = '<img src="' + href + '" alt="' + text + '"';
19584 out += ' title="' + title + '"';
19586 out += this.options.xhtml ? '/>' : '>';
19590 Renderer.prototype.text = function(text) {
19595 * Parsing & Compiling
19601 var Parser= function (options) {
19604 this.options = options || marked.defaults;
19605 this.options.renderer = this.options.renderer || new Renderer;
19606 this.renderer = this.options.renderer;
19607 this.renderer.options = this.options;
19611 * Static Parse Method
19614 Parser.parse = function(src, options, renderer) {
19615 var parser = new Parser(options, renderer);
19616 return parser.parse(src);
19623 Parser.prototype.parse = function(src) {
19624 this.inline = new InlineLexer(src.links, this.options, this.renderer);
19625 this.tokens = src.reverse();
19628 while (this.next()) {
19639 Parser.prototype.next = function() {
19640 return this.token = this.tokens.pop();
19644 * Preview Next Token
19647 Parser.prototype.peek = function() {
19648 return this.tokens[this.tokens.length - 1] || 0;
19652 * Parse Text Tokens
19655 Parser.prototype.parseText = function() {
19656 var body = this.token.text;
19658 while (this.peek().type === 'text') {
19659 body += '\n' + this.next().text;
19662 return this.inline.output(body);
19666 * Parse Current Token
19669 Parser.prototype.tok = function() {
19670 switch (this.token.type) {
19675 return this.renderer.hr();
19678 return this.renderer.heading(
19679 this.inline.output(this.token.text),
19684 return this.renderer.code(this.token.text,
19686 this.token.escaped);
19699 for (i = 0; i < this.token.header.length; i++) {
19700 flags = { header: true, align: this.token.align[i] };
19701 cell += this.renderer.tablecell(
19702 this.inline.output(this.token.header[i]),
19703 { header: true, align: this.token.align[i] }
19706 header += this.renderer.tablerow(cell);
19708 for (i = 0; i < this.token.cells.length; i++) {
19709 row = this.token.cells[i];
19712 for (j = 0; j < row.length; j++) {
19713 cell += this.renderer.tablecell(
19714 this.inline.output(row[j]),
19715 { header: false, align: this.token.align[j] }
19719 body += this.renderer.tablerow(cell);
19721 return this.renderer.table(header, body);
19723 case 'blockquote_start': {
19726 while (this.next().type !== 'blockquote_end') {
19727 body += this.tok();
19730 return this.renderer.blockquote(body);
19732 case 'list_start': {
19734 , ordered = this.token.ordered;
19736 while (this.next().type !== 'list_end') {
19737 body += this.tok();
19740 return this.renderer.list(body, ordered);
19742 case 'list_item_start': {
19745 while (this.next().type !== 'list_item_end') {
19746 body += this.token.type === 'text'
19751 return this.renderer.listitem(body);
19753 case 'loose_item_start': {
19756 while (this.next().type !== 'list_item_end') {
19757 body += this.tok();
19760 return this.renderer.listitem(body);
19763 var html = !this.token.pre && !this.options.pedantic
19764 ? this.inline.output(this.token.text)
19766 return this.renderer.html(html);
19768 case 'paragraph': {
19769 return this.renderer.paragraph(this.inline.output(this.token.text));
19772 return this.renderer.paragraph(this.parseText());
19784 var marked = function (src, opt, callback) {
19785 if (callback || typeof opt === 'function') {
19791 opt = merge({}, marked.defaults, opt || {});
19793 var highlight = opt.highlight
19799 tokens = Lexer.lex(src, opt)
19801 return callback(e);
19804 pending = tokens.length;
19808 var done = function(err) {
19810 opt.highlight = highlight;
19811 return callback(err);
19817 out = Parser.parse(tokens, opt);
19822 opt.highlight = highlight;
19826 : callback(null, out);
19829 if (!highlight || highlight.length < 3) {
19833 delete opt.highlight;
19835 if (!pending) { return done(); }
19837 for (; i < tokens.length; i++) {
19839 if (token.type !== 'code') {
19840 return --pending || done();
19842 return highlight(token.text, token.lang, function(err, code) {
19843 if (err) { return done(err); }
19844 if (code == null || code === token.text) {
19845 return --pending || done();
19848 token.escaped = true;
19849 --pending || done();
19857 if (opt) { opt = merge({}, marked.defaults, opt); }
19858 return Parser.parse(Lexer.lex(src, opt), opt);
19860 e.message += '\nPlease report this to https://github.com/chjj/marked.';
19861 if ((opt || marked.defaults).silent) {
19862 return '<p>An error occured:</p><pre>'
19863 + escape(e.message + '', true)
19875 marked.setOptions = function(opt) {
19876 merge(marked.defaults, opt);
19880 marked.defaults = {
19891 langPrefix: 'lang-',
19892 smartypants: false,
19894 renderer: new Renderer,
19902 marked.Parser = Parser;
19903 marked.parser = Parser.parse;
19905 marked.Renderer = Renderer;
19907 marked.Lexer = Lexer;
19908 marked.lexer = Lexer.lex;
19910 marked.InlineLexer = InlineLexer;
19911 marked.inlineLexer = InlineLexer.output;
19913 marked.parse = marked;
19915 Roo.Markdown.marked = marked;
19919 * Ext JS Library 1.1.1
19920 * Copyright(c) 2006-2007, Ext JS, LLC.
19922 * Originally Released Under LGPL - original licence link has changed is not relivant.
19925 * <script type="text/javascript">
19931 * These classes are derivatives of the similarly named classes in the YUI Library.
19932 * The original license:
19933 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
19934 * Code licensed under the BSD License:
19935 * http://developer.yahoo.net/yui/license.txt
19940 var Event=Roo.EventManager;
19941 var Dom=Roo.lib.Dom;
19944 * @class Roo.dd.DragDrop
19945 * @extends Roo.util.Observable
19946 * Defines the interface and base operation of items that that can be
19947 * dragged or can be drop targets. It was designed to be extended, overriding
19948 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
19949 * Up to three html elements can be associated with a DragDrop instance:
19951 * <li>linked element: the element that is passed into the constructor.
19952 * This is the element which defines the boundaries for interaction with
19953 * other DragDrop objects.</li>
19954 * <li>handle element(s): The drag operation only occurs if the element that
19955 * was clicked matches a handle element. By default this is the linked
19956 * element, but there are times that you will want only a portion of the
19957 * linked element to initiate the drag operation, and the setHandleElId()
19958 * method provides a way to define this.</li>
19959 * <li>drag element: this represents the element that would be moved along
19960 * with the cursor during a drag operation. By default, this is the linked
19961 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
19962 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
19965 * This class should not be instantiated until the onload event to ensure that
19966 * the associated elements are available.
19967 * The following would define a DragDrop obj that would interact with any
19968 * other DragDrop obj in the "group1" group:
19970 * dd = new Roo.dd.DragDrop("div1", "group1");
19972 * Since none of the event handlers have been implemented, nothing would
19973 * actually happen if you were to run the code above. Normally you would
19974 * override this class or one of the default implementations, but you can
19975 * also override the methods you want on an instance of the class...
19977 * dd.onDragDrop = function(e, id) {
19978 * alert("dd was dropped on " + id);
19982 * @param {String} id of the element that is linked to this instance
19983 * @param {String} sGroup the group of related DragDrop objects
19984 * @param {object} config an object containing configurable attributes
19985 * Valid properties for DragDrop:
19986 * padding, isTarget, maintainOffset, primaryButtonOnly
19988 Roo.dd.DragDrop = function(id, sGroup, config) {
19990 this.init(id, sGroup, config);
19995 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
19998 * The id of the element associated with this object. This is what we
19999 * refer to as the "linked element" because the size and position of
20000 * this element is used to determine when the drag and drop objects have
20008 * Configuration attributes passed into the constructor
20015 * The id of the element that will be dragged. By default this is same
20016 * as the linked element , but could be changed to another element. Ex:
20018 * @property dragElId
20025 * the id of the element that initiates the drag operation. By default
20026 * this is the linked element, but could be changed to be a child of this
20027 * element. This lets us do things like only starting the drag when the
20028 * header element within the linked html element is clicked.
20029 * @property handleElId
20036 * An associative array of HTML tags that will be ignored if clicked.
20037 * @property invalidHandleTypes
20038 * @type {string: string}
20040 invalidHandleTypes: null,
20043 * An associative array of ids for elements that will be ignored if clicked
20044 * @property invalidHandleIds
20045 * @type {string: string}
20047 invalidHandleIds: null,
20050 * An indexted array of css class names for elements that will be ignored
20052 * @property invalidHandleClasses
20055 invalidHandleClasses: null,
20058 * The linked element's absolute X position at the time the drag was
20060 * @property startPageX
20067 * The linked element's absolute X position at the time the drag was
20069 * @property startPageY
20076 * The group defines a logical collection of DragDrop objects that are
20077 * related. Instances only get events when interacting with other
20078 * DragDrop object in the same group. This lets us define multiple
20079 * groups using a single DragDrop subclass if we want.
20081 * @type {string: string}
20086 * Individual drag/drop instances can be locked. This will prevent
20087 * onmousedown start drag.
20095 * Lock this instance
20098 lock: function() { this.locked = true; },
20101 * Unlock this instace
20104 unlock: function() { this.locked = false; },
20107 * By default, all insances can be a drop target. This can be disabled by
20108 * setting isTarget to false.
20115 * The padding configured for this drag and drop object for calculating
20116 * the drop zone intersection with this object.
20123 * Cached reference to the linked element
20124 * @property _domRef
20130 * Internal typeof flag
20131 * @property __ygDragDrop
20134 __ygDragDrop: true,
20137 * Set to true when horizontal contraints are applied
20138 * @property constrainX
20145 * Set to true when vertical contraints are applied
20146 * @property constrainY
20153 * The left constraint
20161 * The right constraint
20169 * The up constraint
20178 * The down constraint
20186 * Maintain offsets when we resetconstraints. Set to true when you want
20187 * the position of the element relative to its parent to stay the same
20188 * when the page changes
20190 * @property maintainOffset
20193 maintainOffset: false,
20196 * Array of pixel locations the element will snap to if we specified a
20197 * horizontal graduation/interval. This array is generated automatically
20198 * when you define a tick interval.
20205 * Array of pixel locations the element will snap to if we specified a
20206 * vertical graduation/interval. This array is generated automatically
20207 * when you define a tick interval.
20214 * By default the drag and drop instance will only respond to the primary
20215 * button click (left button for a right-handed mouse). Set to true to
20216 * allow drag and drop to start with any mouse click that is propogated
20218 * @property primaryButtonOnly
20221 primaryButtonOnly: true,
20224 * The availabe property is false until the linked dom element is accessible.
20225 * @property available
20231 * By default, drags can only be initiated if the mousedown occurs in the
20232 * region the linked element is. This is done in part to work around a
20233 * bug in some browsers that mis-report the mousedown if the previous
20234 * mouseup happened outside of the window. This property is set to true
20235 * if outer handles are defined.
20237 * @property hasOuterHandles
20241 hasOuterHandles: false,
20244 * Code that executes immediately before the startDrag event
20245 * @method b4StartDrag
20248 b4StartDrag: function(x, y) { },
20251 * Abstract method called after a drag/drop object is clicked
20252 * and the drag or mousedown time thresholds have beeen met.
20253 * @method startDrag
20254 * @param {int} X click location
20255 * @param {int} Y click location
20257 startDrag: function(x, y) { /* override this */ },
20260 * Code that executes immediately before the onDrag event
20264 b4Drag: function(e) { },
20267 * Abstract method called during the onMouseMove event while dragging an
20270 * @param {Event} e the mousemove event
20272 onDrag: function(e) { /* override this */ },
20275 * Abstract method called when this element fist begins hovering over
20276 * another DragDrop obj
20277 * @method onDragEnter
20278 * @param {Event} e the mousemove event
20279 * @param {String|DragDrop[]} id In POINT mode, the element
20280 * id this is hovering over. In INTERSECT mode, an array of one or more
20281 * dragdrop items being hovered over.
20283 onDragEnter: function(e, id) { /* override this */ },
20286 * Code that executes immediately before the onDragOver event
20287 * @method b4DragOver
20290 b4DragOver: function(e) { },
20293 * Abstract method called when this element is hovering over another
20295 * @method onDragOver
20296 * @param {Event} e the mousemove event
20297 * @param {String|DragDrop[]} id In POINT mode, the element
20298 * id this is hovering over. In INTERSECT mode, an array of dd items
20299 * being hovered over.
20301 onDragOver: function(e, id) { /* override this */ },
20304 * Code that executes immediately before the onDragOut event
20305 * @method b4DragOut
20308 b4DragOut: function(e) { },
20311 * Abstract method called when we are no longer hovering over an element
20312 * @method onDragOut
20313 * @param {Event} e the mousemove event
20314 * @param {String|DragDrop[]} id In POINT mode, the element
20315 * id this was hovering over. In INTERSECT mode, an array of dd items
20316 * that the mouse is no longer over.
20318 onDragOut: function(e, id) { /* override this */ },
20321 * Code that executes immediately before the onDragDrop event
20322 * @method b4DragDrop
20325 b4DragDrop: function(e) { },
20328 * Abstract method called when this item is dropped on another DragDrop
20330 * @method onDragDrop
20331 * @param {Event} e the mouseup event
20332 * @param {String|DragDrop[]} id In POINT mode, the element
20333 * id this was dropped on. In INTERSECT mode, an array of dd items this
20336 onDragDrop: function(e, id) { /* override this */ },
20339 * Abstract method called when this item is dropped on an area with no
20341 * @method onInvalidDrop
20342 * @param {Event} e the mouseup event
20344 onInvalidDrop: function(e) { /* override this */ },
20347 * Code that executes immediately before the endDrag event
20348 * @method b4EndDrag
20351 b4EndDrag: function(e) { },
20354 * Fired when we are done dragging the object
20356 * @param {Event} e the mouseup event
20358 endDrag: function(e) { /* override this */ },
20361 * Code executed immediately before the onMouseDown event
20362 * @method b4MouseDown
20363 * @param {Event} e the mousedown event
20366 b4MouseDown: function(e) { },
20369 * Event handler that fires when a drag/drop obj gets a mousedown
20370 * @method onMouseDown
20371 * @param {Event} e the mousedown event
20373 onMouseDown: function(e) { /* override this */ },
20376 * Event handler that fires when a drag/drop obj gets a mouseup
20377 * @method onMouseUp
20378 * @param {Event} e the mouseup event
20380 onMouseUp: function(e) { /* override this */ },
20383 * Override the onAvailable method to do what is needed after the initial
20384 * position was determined.
20385 * @method onAvailable
20387 onAvailable: function () {
20391 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
20394 defaultPadding : {left:0, right:0, top:0, bottom:0},
20397 * Initializes the drag drop object's constraints to restrict movement to a certain element.
20401 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
20402 { dragElId: "existingProxyDiv" });
20403 dd.startDrag = function(){
20404 this.constrainTo("parent-id");
20407 * Or you can initalize it using the {@link Roo.Element} object:
20409 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
20410 startDrag : function(){
20411 this.constrainTo("parent-id");
20415 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
20416 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
20417 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
20418 * an object containing the sides to pad. For example: {right:10, bottom:10}
20419 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
20421 constrainTo : function(constrainTo, pad, inContent){
20422 if(typeof pad == "number"){
20423 pad = {left: pad, right:pad, top:pad, bottom:pad};
20425 pad = pad || this.defaultPadding;
20426 var b = Roo.get(this.getEl()).getBox();
20427 var ce = Roo.get(constrainTo);
20428 var s = ce.getScroll();
20429 var c, cd = ce.dom;
20430 if(cd == document.body){
20431 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
20434 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
20438 var topSpace = b.y - c.y;
20439 var leftSpace = b.x - c.x;
20441 this.resetConstraints();
20442 this.setXConstraint(leftSpace - (pad.left||0), // left
20443 c.width - leftSpace - b.width - (pad.right||0) //right
20445 this.setYConstraint(topSpace - (pad.top||0), //top
20446 c.height - topSpace - b.height - (pad.bottom||0) //bottom
20451 * Returns a reference to the linked element
20453 * @return {HTMLElement} the html element
20455 getEl: function() {
20456 if (!this._domRef) {
20457 this._domRef = Roo.getDom(this.id);
20460 return this._domRef;
20464 * Returns a reference to the actual element to drag. By default this is
20465 * the same as the html element, but it can be assigned to another
20466 * element. An example of this can be found in Roo.dd.DDProxy
20467 * @method getDragEl
20468 * @return {HTMLElement} the html element
20470 getDragEl: function() {
20471 return Roo.getDom(this.dragElId);
20475 * Sets up the DragDrop object. Must be called in the constructor of any
20476 * Roo.dd.DragDrop subclass
20478 * @param id the id of the linked element
20479 * @param {String} sGroup the group of related items
20480 * @param {object} config configuration attributes
20482 init: function(id, sGroup, config) {
20483 this.initTarget(id, sGroup, config);
20484 if (!Roo.isTouch) {
20485 Event.on(this.id, "mousedown", this.handleMouseDown, this);
20487 Event.on(this.id, "touchstart", this.handleMouseDown, this);
20488 // Event.on(this.id, "selectstart", Event.preventDefault);
20492 * Initializes Targeting functionality only... the object does not
20493 * get a mousedown handler.
20494 * @method initTarget
20495 * @param id the id of the linked element
20496 * @param {String} sGroup the group of related items
20497 * @param {object} config configuration attributes
20499 initTarget: function(id, sGroup, config) {
20501 // configuration attributes
20502 this.config = config || {};
20504 // create a local reference to the drag and drop manager
20505 this.DDM = Roo.dd.DDM;
20506 // initialize the groups array
20509 // assume that we have an element reference instead of an id if the
20510 // parameter is not a string
20511 if (typeof id !== "string") {
20518 // add to an interaction group
20519 this.addToGroup((sGroup) ? sGroup : "default");
20521 // We don't want to register this as the handle with the manager
20522 // so we just set the id rather than calling the setter.
20523 this.handleElId = id;
20525 // the linked element is the element that gets dragged by default
20526 this.setDragElId(id);
20528 // by default, clicked anchors will not start drag operations.
20529 this.invalidHandleTypes = { A: "A" };
20530 this.invalidHandleIds = {};
20531 this.invalidHandleClasses = [];
20533 this.applyConfig();
20535 this.handleOnAvailable();
20539 * Applies the configuration parameters that were passed into the constructor.
20540 * This is supposed to happen at each level through the inheritance chain. So
20541 * a DDProxy implentation will execute apply config on DDProxy, DD, and
20542 * DragDrop in order to get all of the parameters that are available in
20544 * @method applyConfig
20546 applyConfig: function() {
20548 // configurable properties:
20549 // padding, isTarget, maintainOffset, primaryButtonOnly
20550 this.padding = this.config.padding || [0, 0, 0, 0];
20551 this.isTarget = (this.config.isTarget !== false);
20552 this.maintainOffset = (this.config.maintainOffset);
20553 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
20558 * Executed when the linked element is available
20559 * @method handleOnAvailable
20562 handleOnAvailable: function() {
20563 this.available = true;
20564 this.resetConstraints();
20565 this.onAvailable();
20569 * Configures the padding for the target zone in px. Effectively expands
20570 * (or reduces) the virtual object size for targeting calculations.
20571 * Supports css-style shorthand; if only one parameter is passed, all sides
20572 * will have that padding, and if only two are passed, the top and bottom
20573 * will have the first param, the left and right the second.
20574 * @method setPadding
20575 * @param {int} iTop Top pad
20576 * @param {int} iRight Right pad
20577 * @param {int} iBot Bot pad
20578 * @param {int} iLeft Left pad
20580 setPadding: function(iTop, iRight, iBot, iLeft) {
20581 // this.padding = [iLeft, iRight, iTop, iBot];
20582 if (!iRight && 0 !== iRight) {
20583 this.padding = [iTop, iTop, iTop, iTop];
20584 } else if (!iBot && 0 !== iBot) {
20585 this.padding = [iTop, iRight, iTop, iRight];
20587 this.padding = [iTop, iRight, iBot, iLeft];
20592 * Stores the initial placement of the linked element.
20593 * @method setInitialPosition
20594 * @param {int} diffX the X offset, default 0
20595 * @param {int} diffY the Y offset, default 0
20597 setInitPosition: function(diffX, diffY) {
20598 var el = this.getEl();
20600 if (!this.DDM.verifyEl(el)) {
20604 var dx = diffX || 0;
20605 var dy = diffY || 0;
20607 var p = Dom.getXY( el );
20609 this.initPageX = p[0] - dx;
20610 this.initPageY = p[1] - dy;
20612 this.lastPageX = p[0];
20613 this.lastPageY = p[1];
20616 this.setStartPosition(p);
20620 * Sets the start position of the element. This is set when the obj
20621 * is initialized, the reset when a drag is started.
20622 * @method setStartPosition
20623 * @param pos current position (from previous lookup)
20626 setStartPosition: function(pos) {
20627 var p = pos || Dom.getXY( this.getEl() );
20628 this.deltaSetXY = null;
20630 this.startPageX = p[0];
20631 this.startPageY = p[1];
20635 * Add this instance to a group of related drag/drop objects. All
20636 * instances belong to at least one group, and can belong to as many
20637 * groups as needed.
20638 * @method addToGroup
20639 * @param sGroup {string} the name of the group
20641 addToGroup: function(sGroup) {
20642 this.groups[sGroup] = true;
20643 this.DDM.regDragDrop(this, sGroup);
20647 * Remove's this instance from the supplied interaction group
20648 * @method removeFromGroup
20649 * @param {string} sGroup The group to drop
20651 removeFromGroup: function(sGroup) {
20652 if (this.groups[sGroup]) {
20653 delete this.groups[sGroup];
20656 this.DDM.removeDDFromGroup(this, sGroup);
20660 * Allows you to specify that an element other than the linked element
20661 * will be moved with the cursor during a drag
20662 * @method setDragElId
20663 * @param id {string} the id of the element that will be used to initiate the drag
20665 setDragElId: function(id) {
20666 this.dragElId = id;
20670 * Allows you to specify a child of the linked element that should be
20671 * used to initiate the drag operation. An example of this would be if
20672 * you have a content div with text and links. Clicking anywhere in the
20673 * content area would normally start the drag operation. Use this method
20674 * to specify that an element inside of the content div is the element
20675 * that starts the drag operation.
20676 * @method setHandleElId
20677 * @param id {string} the id of the element that will be used to
20678 * initiate the drag.
20680 setHandleElId: function(id) {
20681 if (typeof id !== "string") {
20684 this.handleElId = id;
20685 this.DDM.regHandle(this.id, id);
20689 * Allows you to set an element outside of the linked element as a drag
20691 * @method setOuterHandleElId
20692 * @param id the id of the element that will be used to initiate the drag
20694 setOuterHandleElId: function(id) {
20695 if (typeof id !== "string") {
20698 Event.on(id, "mousedown",
20699 this.handleMouseDown, this);
20700 this.setHandleElId(id);
20702 this.hasOuterHandles = true;
20706 * Remove all drag and drop hooks for this element
20709 unreg: function() {
20710 Event.un(this.id, "mousedown",
20711 this.handleMouseDown);
20712 Event.un(this.id, "touchstart",
20713 this.handleMouseDown);
20714 this._domRef = null;
20715 this.DDM._remove(this);
20718 destroy : function(){
20723 * Returns true if this instance is locked, or the drag drop mgr is locked
20724 * (meaning that all drag/drop is disabled on the page.)
20726 * @return {boolean} true if this obj or all drag/drop is locked, else
20729 isLocked: function() {
20730 return (this.DDM.isLocked() || this.locked);
20734 * Fired when this object is clicked
20735 * @method handleMouseDown
20737 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
20740 handleMouseDown: function(e, oDD){
20742 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
20743 //Roo.log('not touch/ button !=0');
20746 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
20747 return; // double touch..
20751 if (this.isLocked()) {
20752 //Roo.log('locked');
20756 this.DDM.refreshCache(this.groups);
20757 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
20758 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
20759 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
20760 //Roo.log('no outer handes or not over target');
20763 // Roo.log('check validator');
20764 if (this.clickValidator(e)) {
20765 // Roo.log('validate success');
20766 // set the initial element position
20767 this.setStartPosition();
20770 this.b4MouseDown(e);
20771 this.onMouseDown(e);
20773 this.DDM.handleMouseDown(e, this);
20775 this.DDM.stopEvent(e);
20783 clickValidator: function(e) {
20784 var target = e.getTarget();
20785 return ( this.isValidHandleChild(target) &&
20786 (this.id == this.handleElId ||
20787 this.DDM.handleWasClicked(target, this.id)) );
20791 * Allows you to specify a tag name that should not start a drag operation
20792 * when clicked. This is designed to facilitate embedding links within a
20793 * drag handle that do something other than start the drag.
20794 * @method addInvalidHandleType
20795 * @param {string} tagName the type of element to exclude
20797 addInvalidHandleType: function(tagName) {
20798 var type = tagName.toUpperCase();
20799 this.invalidHandleTypes[type] = type;
20803 * Lets you to specify an element id for a child of a drag handle
20804 * that should not initiate a drag
20805 * @method addInvalidHandleId
20806 * @param {string} id the element id of the element you wish to ignore
20808 addInvalidHandleId: function(id) {
20809 if (typeof id !== "string") {
20812 this.invalidHandleIds[id] = id;
20816 * Lets you specify a css class of elements that will not initiate a drag
20817 * @method addInvalidHandleClass
20818 * @param {string} cssClass the class of the elements you wish to ignore
20820 addInvalidHandleClass: function(cssClass) {
20821 this.invalidHandleClasses.push(cssClass);
20825 * Unsets an excluded tag name set by addInvalidHandleType
20826 * @method removeInvalidHandleType
20827 * @param {string} tagName the type of element to unexclude
20829 removeInvalidHandleType: function(tagName) {
20830 var type = tagName.toUpperCase();
20831 // this.invalidHandleTypes[type] = null;
20832 delete this.invalidHandleTypes[type];
20836 * Unsets an invalid handle id
20837 * @method removeInvalidHandleId
20838 * @param {string} id the id of the element to re-enable
20840 removeInvalidHandleId: function(id) {
20841 if (typeof id !== "string") {
20844 delete this.invalidHandleIds[id];
20848 * Unsets an invalid css class
20849 * @method removeInvalidHandleClass
20850 * @param {string} cssClass the class of the element(s) you wish to
20853 removeInvalidHandleClass: function(cssClass) {
20854 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
20855 if (this.invalidHandleClasses[i] == cssClass) {
20856 delete this.invalidHandleClasses[i];
20862 * Checks the tag exclusion list to see if this click should be ignored
20863 * @method isValidHandleChild
20864 * @param {HTMLElement} node the HTMLElement to evaluate
20865 * @return {boolean} true if this is a valid tag type, false if not
20867 isValidHandleChild: function(node) {
20870 // var n = (node.nodeName == "#text") ? node.parentNode : node;
20873 nodeName = node.nodeName.toUpperCase();
20875 nodeName = node.nodeName;
20877 valid = valid && !this.invalidHandleTypes[nodeName];
20878 valid = valid && !this.invalidHandleIds[node.id];
20880 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
20881 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
20890 * Create the array of horizontal tick marks if an interval was specified
20891 * in setXConstraint().
20892 * @method setXTicks
20895 setXTicks: function(iStartX, iTickSize) {
20897 this.xTickSize = iTickSize;
20901 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
20903 this.xTicks[this.xTicks.length] = i;
20908 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
20910 this.xTicks[this.xTicks.length] = i;
20915 this.xTicks.sort(this.DDM.numericSort) ;
20919 * Create the array of vertical tick marks if an interval was specified in
20920 * setYConstraint().
20921 * @method setYTicks
20924 setYTicks: function(iStartY, iTickSize) {
20926 this.yTickSize = iTickSize;
20930 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
20932 this.yTicks[this.yTicks.length] = i;
20937 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
20939 this.yTicks[this.yTicks.length] = i;
20944 this.yTicks.sort(this.DDM.numericSort) ;
20948 * By default, the element can be dragged any place on the screen. Use
20949 * this method to limit the horizontal travel of the element. Pass in
20950 * 0,0 for the parameters if you want to lock the drag to the y axis.
20951 * @method setXConstraint
20952 * @param {int} iLeft the number of pixels the element can move to the left
20953 * @param {int} iRight the number of pixels the element can move to the
20955 * @param {int} iTickSize optional parameter for specifying that the
20957 * should move iTickSize pixels at a time.
20959 setXConstraint: function(iLeft, iRight, iTickSize) {
20960 this.leftConstraint = iLeft;
20961 this.rightConstraint = iRight;
20963 this.minX = this.initPageX - iLeft;
20964 this.maxX = this.initPageX + iRight;
20965 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
20967 this.constrainX = true;
20971 * Clears any constraints applied to this instance. Also clears ticks
20972 * since they can't exist independent of a constraint at this time.
20973 * @method clearConstraints
20975 clearConstraints: function() {
20976 this.constrainX = false;
20977 this.constrainY = false;
20982 * Clears any tick interval defined for this instance
20983 * @method clearTicks
20985 clearTicks: function() {
20986 this.xTicks = null;
20987 this.yTicks = null;
20988 this.xTickSize = 0;
20989 this.yTickSize = 0;
20993 * By default, the element can be dragged any place on the screen. Set
20994 * this to limit the vertical travel of the element. Pass in 0,0 for the
20995 * parameters if you want to lock the drag to the x axis.
20996 * @method setYConstraint
20997 * @param {int} iUp the number of pixels the element can move up
20998 * @param {int} iDown the number of pixels the element can move down
20999 * @param {int} iTickSize optional parameter for specifying that the
21000 * element should move iTickSize pixels at a time.
21002 setYConstraint: function(iUp, iDown, iTickSize) {
21003 this.topConstraint = iUp;
21004 this.bottomConstraint = iDown;
21006 this.minY = this.initPageY - iUp;
21007 this.maxY = this.initPageY + iDown;
21008 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
21010 this.constrainY = true;
21015 * resetConstraints must be called if you manually reposition a dd element.
21016 * @method resetConstraints
21017 * @param {boolean} maintainOffset
21019 resetConstraints: function() {
21022 // Maintain offsets if necessary
21023 if (this.initPageX || this.initPageX === 0) {
21024 // figure out how much this thing has moved
21025 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
21026 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
21028 this.setInitPosition(dx, dy);
21030 // This is the first time we have detected the element's position
21032 this.setInitPosition();
21035 if (this.constrainX) {
21036 this.setXConstraint( this.leftConstraint,
21037 this.rightConstraint,
21041 if (this.constrainY) {
21042 this.setYConstraint( this.topConstraint,
21043 this.bottomConstraint,
21049 * Normally the drag element is moved pixel by pixel, but we can specify
21050 * that it move a number of pixels at a time. This method resolves the
21051 * location when we have it set up like this.
21053 * @param {int} val where we want to place the object
21054 * @param {int[]} tickArray sorted array of valid points
21055 * @return {int} the closest tick
21058 getTick: function(val, tickArray) {
21061 // If tick interval is not defined, it is effectively 1 pixel,
21062 // so we return the value passed to us.
21064 } else if (tickArray[0] >= val) {
21065 // The value is lower than the first tick, so we return the first
21067 return tickArray[0];
21069 for (var i=0, len=tickArray.length; i<len; ++i) {
21071 if (tickArray[next] && tickArray[next] >= val) {
21072 var diff1 = val - tickArray[i];
21073 var diff2 = tickArray[next] - val;
21074 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
21078 // The value is larger than the last tick, so we return the last
21080 return tickArray[tickArray.length - 1];
21087 * @return {string} string representation of the dd obj
21089 toString: function() {
21090 return ("DragDrop " + this.id);
21098 * Ext JS Library 1.1.1
21099 * Copyright(c) 2006-2007, Ext JS, LLC.
21101 * Originally Released Under LGPL - original licence link has changed is not relivant.
21104 * <script type="text/javascript">
21109 * The drag and drop utility provides a framework for building drag and drop
21110 * applications. In addition to enabling drag and drop for specific elements,
21111 * the drag and drop elements are tracked by the manager class, and the
21112 * interactions between the various elements are tracked during the drag and
21113 * the implementing code is notified about these important moments.
21116 // Only load the library once. Rewriting the manager class would orphan
21117 // existing drag and drop instances.
21118 if (!Roo.dd.DragDropMgr) {
21121 * @class Roo.dd.DragDropMgr
21122 * DragDropMgr is a singleton that tracks the element interaction for
21123 * all DragDrop items in the window. Generally, you will not call
21124 * this class directly, but it does have helper methods that could
21125 * be useful in your DragDrop implementations.
21128 Roo.dd.DragDropMgr = function() {
21130 var Event = Roo.EventManager;
21135 * Two dimensional Array of registered DragDrop objects. The first
21136 * dimension is the DragDrop item group, the second the DragDrop
21139 * @type {string: string}
21146 * Array of element ids defined as drag handles. Used to determine
21147 * if the element that generated the mousedown event is actually the
21148 * handle and not the html element itself.
21149 * @property handleIds
21150 * @type {string: string}
21157 * the DragDrop object that is currently being dragged
21158 * @property dragCurrent
21166 * the DragDrop object(s) that are being hovered over
21167 * @property dragOvers
21175 * the X distance between the cursor and the object being dragged
21184 * the Y distance between the cursor and the object being dragged
21193 * Flag to determine if we should prevent the default behavior of the
21194 * events we define. By default this is true, but this can be set to
21195 * false if you need the default behavior (not recommended)
21196 * @property preventDefault
21200 preventDefault: true,
21203 * Flag to determine if we should stop the propagation of the events
21204 * we generate. This is true by default but you may want to set it to
21205 * false if the html element contains other features that require the
21207 * @property stopPropagation
21211 stopPropagation: true,
21214 * Internal flag that is set to true when drag and drop has been
21216 * @property initialized
21223 * All drag and drop can be disabled.
21231 * Called the first time an element is registered.
21237 this.initialized = true;
21241 * In point mode, drag and drop interaction is defined by the
21242 * location of the cursor during the drag/drop
21250 * In intersect mode, drag and drop interactio nis defined by the
21251 * overlap of two or more drag and drop objects.
21252 * @property INTERSECT
21259 * The current drag and drop mode. Default: POINT
21267 * Runs method on all drag and drop objects
21268 * @method _execOnAll
21272 _execOnAll: function(sMethod, args) {
21273 for (var i in this.ids) {
21274 for (var j in this.ids[i]) {
21275 var oDD = this.ids[i][j];
21276 if (! this.isTypeOfDD(oDD)) {
21279 oDD[sMethod].apply(oDD, args);
21285 * Drag and drop initialization. Sets up the global event handlers
21290 _onLoad: function() {
21294 if (!Roo.isTouch) {
21295 Event.on(document, "mouseup", this.handleMouseUp, this, true);
21296 Event.on(document, "mousemove", this.handleMouseMove, this, true);
21298 Event.on(document, "touchend", this.handleMouseUp, this, true);
21299 Event.on(document, "touchmove", this.handleMouseMove, this, true);
21301 Event.on(window, "unload", this._onUnload, this, true);
21302 Event.on(window, "resize", this._onResize, this, true);
21303 // Event.on(window, "mouseout", this._test);
21308 * Reset constraints on all drag and drop objs
21309 * @method _onResize
21313 _onResize: function(e) {
21314 this._execOnAll("resetConstraints", []);
21318 * Lock all drag and drop functionality
21322 lock: function() { this.locked = true; },
21325 * Unlock all drag and drop functionality
21329 unlock: function() { this.locked = false; },
21332 * Is drag and drop locked?
21334 * @return {boolean} True if drag and drop is locked, false otherwise.
21337 isLocked: function() { return this.locked; },
21340 * Location cache that is set for all drag drop objects when a drag is
21341 * initiated, cleared when the drag is finished.
21342 * @property locationCache
21349 * Set useCache to false if you want to force object the lookup of each
21350 * drag and drop linked element constantly during a drag.
21351 * @property useCache
21358 * The number of pixels that the mouse needs to move after the
21359 * mousedown before the drag is initiated. Default=3;
21360 * @property clickPixelThresh
21364 clickPixelThresh: 3,
21367 * The number of milliseconds after the mousedown event to initiate the
21368 * drag if we don't get a mouseup event. Default=1000
21369 * @property clickTimeThresh
21373 clickTimeThresh: 350,
21376 * Flag that indicates that either the drag pixel threshold or the
21377 * mousdown time threshold has been met
21378 * @property dragThreshMet
21383 dragThreshMet: false,
21386 * Timeout used for the click time threshold
21387 * @property clickTimeout
21392 clickTimeout: null,
21395 * The X position of the mousedown event stored for later use when a
21396 * drag threshold is met.
21405 * The Y position of the mousedown event stored for later use when a
21406 * drag threshold is met.
21415 * Each DragDrop instance must be registered with the DragDropMgr.
21416 * This is executed in DragDrop.init()
21417 * @method regDragDrop
21418 * @param {DragDrop} oDD the DragDrop object to register
21419 * @param {String} sGroup the name of the group this element belongs to
21422 regDragDrop: function(oDD, sGroup) {
21423 if (!this.initialized) { this.init(); }
21425 if (!this.ids[sGroup]) {
21426 this.ids[sGroup] = {};
21428 this.ids[sGroup][oDD.id] = oDD;
21432 * Removes the supplied dd instance from the supplied group. Executed
21433 * by DragDrop.removeFromGroup, so don't call this function directly.
21434 * @method removeDDFromGroup
21438 removeDDFromGroup: function(oDD, sGroup) {
21439 if (!this.ids[sGroup]) {
21440 this.ids[sGroup] = {};
21443 var obj = this.ids[sGroup];
21444 if (obj && obj[oDD.id]) {
21445 delete obj[oDD.id];
21450 * Unregisters a drag and drop item. This is executed in
21451 * DragDrop.unreg, use that method instead of calling this directly.
21456 _remove: function(oDD) {
21457 for (var g in oDD.groups) {
21458 if (g && this.ids[g][oDD.id]) {
21459 delete this.ids[g][oDD.id];
21462 delete this.handleIds[oDD.id];
21466 * Each DragDrop handle element must be registered. This is done
21467 * automatically when executing DragDrop.setHandleElId()
21468 * @method regHandle
21469 * @param {String} sDDId the DragDrop id this element is a handle for
21470 * @param {String} sHandleId the id of the element that is the drag
21474 regHandle: function(sDDId, sHandleId) {
21475 if (!this.handleIds[sDDId]) {
21476 this.handleIds[sDDId] = {};
21478 this.handleIds[sDDId][sHandleId] = sHandleId;
21482 * Utility function to determine if a given element has been
21483 * registered as a drag drop item.
21484 * @method isDragDrop
21485 * @param {String} id the element id to check
21486 * @return {boolean} true if this element is a DragDrop item,
21490 isDragDrop: function(id) {
21491 return ( this.getDDById(id) ) ? true : false;
21495 * Returns the drag and drop instances that are in all groups the
21496 * passed in instance belongs to.
21497 * @method getRelated
21498 * @param {DragDrop} p_oDD the obj to get related data for
21499 * @param {boolean} bTargetsOnly if true, only return targetable objs
21500 * @return {DragDrop[]} the related instances
21503 getRelated: function(p_oDD, bTargetsOnly) {
21505 for (var i in p_oDD.groups) {
21506 for (j in this.ids[i]) {
21507 var dd = this.ids[i][j];
21508 if (! this.isTypeOfDD(dd)) {
21511 if (!bTargetsOnly || dd.isTarget) {
21512 oDDs[oDDs.length] = dd;
21521 * Returns true if the specified dd target is a legal target for
21522 * the specifice drag obj
21523 * @method isLegalTarget
21524 * @param {DragDrop} the drag obj
21525 * @param {DragDrop} the target
21526 * @return {boolean} true if the target is a legal target for the
21530 isLegalTarget: function (oDD, oTargetDD) {
21531 var targets = this.getRelated(oDD, true);
21532 for (var i=0, len=targets.length;i<len;++i) {
21533 if (targets[i].id == oTargetDD.id) {
21542 * My goal is to be able to transparently determine if an object is
21543 * typeof DragDrop, and the exact subclass of DragDrop. typeof
21544 * returns "object", oDD.constructor.toString() always returns
21545 * "DragDrop" and not the name of the subclass. So for now it just
21546 * evaluates a well-known variable in DragDrop.
21547 * @method isTypeOfDD
21548 * @param {Object} the object to evaluate
21549 * @return {boolean} true if typeof oDD = DragDrop
21552 isTypeOfDD: function (oDD) {
21553 return (oDD && oDD.__ygDragDrop);
21557 * Utility function to determine if a given element has been
21558 * registered as a drag drop handle for the given Drag Drop object.
21560 * @param {String} id the element id to check
21561 * @return {boolean} true if this element is a DragDrop handle, false
21565 isHandle: function(sDDId, sHandleId) {
21566 return ( this.handleIds[sDDId] &&
21567 this.handleIds[sDDId][sHandleId] );
21571 * Returns the DragDrop instance for a given id
21572 * @method getDDById
21573 * @param {String} id the id of the DragDrop object
21574 * @return {DragDrop} the drag drop object, null if it is not found
21577 getDDById: function(id) {
21578 for (var i in this.ids) {
21579 if (this.ids[i][id]) {
21580 return this.ids[i][id];
21587 * Fired after a registered DragDrop object gets the mousedown event.
21588 * Sets up the events required to track the object being dragged
21589 * @method handleMouseDown
21590 * @param {Event} e the event
21591 * @param oDD the DragDrop object being dragged
21595 handleMouseDown: function(e, oDD) {
21597 Roo.QuickTips.disable();
21599 this.currentTarget = e.getTarget();
21601 this.dragCurrent = oDD;
21603 var el = oDD.getEl();
21605 // track start position
21606 this.startX = e.getPageX();
21607 this.startY = e.getPageY();
21609 this.deltaX = this.startX - el.offsetLeft;
21610 this.deltaY = this.startY - el.offsetTop;
21612 this.dragThreshMet = false;
21614 this.clickTimeout = setTimeout(
21616 var DDM = Roo.dd.DDM;
21617 DDM.startDrag(DDM.startX, DDM.startY);
21619 this.clickTimeThresh );
21623 * Fired when either the drag pixel threshol or the mousedown hold
21624 * time threshold has been met.
21625 * @method startDrag
21626 * @param x {int} the X position of the original mousedown
21627 * @param y {int} the Y position of the original mousedown
21630 startDrag: function(x, y) {
21631 clearTimeout(this.clickTimeout);
21632 if (this.dragCurrent) {
21633 this.dragCurrent.b4StartDrag(x, y);
21634 this.dragCurrent.startDrag(x, y);
21636 this.dragThreshMet = true;
21640 * Internal function to handle the mouseup event. Will be invoked
21641 * from the context of the document.
21642 * @method handleMouseUp
21643 * @param {Event} e the event
21647 handleMouseUp: function(e) {
21650 Roo.QuickTips.enable();
21652 if (! this.dragCurrent) {
21656 clearTimeout(this.clickTimeout);
21658 if (this.dragThreshMet) {
21659 this.fireEvents(e, true);
21669 * Utility to stop event propagation and event default, if these
21670 * features are turned on.
21671 * @method stopEvent
21672 * @param {Event} e the event as returned by this.getEvent()
21675 stopEvent: function(e){
21676 if(this.stopPropagation) {
21677 e.stopPropagation();
21680 if (this.preventDefault) {
21681 e.preventDefault();
21686 * Internal function to clean up event handlers after the drag
21687 * operation is complete
21689 * @param {Event} e the event
21693 stopDrag: function(e) {
21694 // Fire the drag end event for the item that was dragged
21695 if (this.dragCurrent) {
21696 if (this.dragThreshMet) {
21697 this.dragCurrent.b4EndDrag(e);
21698 this.dragCurrent.endDrag(e);
21701 this.dragCurrent.onMouseUp(e);
21704 this.dragCurrent = null;
21705 this.dragOvers = {};
21709 * Internal function to handle the mousemove event. Will be invoked
21710 * from the context of the html element.
21712 * @TODO figure out what we can do about mouse events lost when the
21713 * user drags objects beyond the window boundary. Currently we can
21714 * detect this in internet explorer by verifying that the mouse is
21715 * down during the mousemove event. Firefox doesn't give us the
21716 * button state on the mousemove event.
21717 * @method handleMouseMove
21718 * @param {Event} e the event
21722 handleMouseMove: function(e) {
21723 if (! this.dragCurrent) {
21727 // var button = e.which || e.button;
21729 // check for IE mouseup outside of page boundary
21730 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
21732 return this.handleMouseUp(e);
21735 if (!this.dragThreshMet) {
21736 var diffX = Math.abs(this.startX - e.getPageX());
21737 var diffY = Math.abs(this.startY - e.getPageY());
21738 if (diffX > this.clickPixelThresh ||
21739 diffY > this.clickPixelThresh) {
21740 this.startDrag(this.startX, this.startY);
21744 if (this.dragThreshMet) {
21745 this.dragCurrent.b4Drag(e);
21746 this.dragCurrent.onDrag(e);
21747 if(!this.dragCurrent.moveOnly){
21748 this.fireEvents(e, false);
21758 * Iterates over all of the DragDrop elements to find ones we are
21759 * hovering over or dropping on
21760 * @method fireEvents
21761 * @param {Event} e the event
21762 * @param {boolean} isDrop is this a drop op or a mouseover op?
21766 fireEvents: function(e, isDrop) {
21767 var dc = this.dragCurrent;
21769 // If the user did the mouse up outside of the window, we could
21770 // get here even though we have ended the drag.
21771 if (!dc || dc.isLocked()) {
21775 var pt = e.getPoint();
21777 // cache the previous dragOver array
21783 var enterEvts = [];
21785 // Check to see if the object(s) we were hovering over is no longer
21786 // being hovered over so we can fire the onDragOut event
21787 for (var i in this.dragOvers) {
21789 var ddo = this.dragOvers[i];
21791 if (! this.isTypeOfDD(ddo)) {
21795 if (! this.isOverTarget(pt, ddo, this.mode)) {
21796 outEvts.push( ddo );
21799 oldOvers[i] = true;
21800 delete this.dragOvers[i];
21803 for (var sGroup in dc.groups) {
21805 if ("string" != typeof sGroup) {
21809 for (i in this.ids[sGroup]) {
21810 var oDD = this.ids[sGroup][i];
21811 if (! this.isTypeOfDD(oDD)) {
21815 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
21816 if (this.isOverTarget(pt, oDD, this.mode)) {
21817 // look for drop interactions
21819 dropEvts.push( oDD );
21820 // look for drag enter and drag over interactions
21823 // initial drag over: dragEnter fires
21824 if (!oldOvers[oDD.id]) {
21825 enterEvts.push( oDD );
21826 // subsequent drag overs: dragOver fires
21828 overEvts.push( oDD );
21831 this.dragOvers[oDD.id] = oDD;
21839 if (outEvts.length) {
21840 dc.b4DragOut(e, outEvts);
21841 dc.onDragOut(e, outEvts);
21844 if (enterEvts.length) {
21845 dc.onDragEnter(e, enterEvts);
21848 if (overEvts.length) {
21849 dc.b4DragOver(e, overEvts);
21850 dc.onDragOver(e, overEvts);
21853 if (dropEvts.length) {
21854 dc.b4DragDrop(e, dropEvts);
21855 dc.onDragDrop(e, dropEvts);
21859 // fire dragout events
21861 for (i=0, len=outEvts.length; i<len; ++i) {
21862 dc.b4DragOut(e, outEvts[i].id);
21863 dc.onDragOut(e, outEvts[i].id);
21866 // fire enter events
21867 for (i=0,len=enterEvts.length; i<len; ++i) {
21868 // dc.b4DragEnter(e, oDD.id);
21869 dc.onDragEnter(e, enterEvts[i].id);
21872 // fire over events
21873 for (i=0,len=overEvts.length; i<len; ++i) {
21874 dc.b4DragOver(e, overEvts[i].id);
21875 dc.onDragOver(e, overEvts[i].id);
21878 // fire drop events
21879 for (i=0, len=dropEvts.length; i<len; ++i) {
21880 dc.b4DragDrop(e, dropEvts[i].id);
21881 dc.onDragDrop(e, dropEvts[i].id);
21886 // notify about a drop that did not find a target
21887 if (isDrop && !dropEvts.length) {
21888 dc.onInvalidDrop(e);
21894 * Helper function for getting the best match from the list of drag
21895 * and drop objects returned by the drag and drop events when we are
21896 * in INTERSECT mode. It returns either the first object that the
21897 * cursor is over, or the object that has the greatest overlap with
21898 * the dragged element.
21899 * @method getBestMatch
21900 * @param {DragDrop[]} dds The array of drag and drop objects
21902 * @return {DragDrop} The best single match
21905 getBestMatch: function(dds) {
21907 // Return null if the input is not what we expect
21908 //if (!dds || !dds.length || dds.length == 0) {
21910 // If there is only one item, it wins
21911 //} else if (dds.length == 1) {
21913 var len = dds.length;
21918 // Loop through the targeted items
21919 for (var i=0; i<len; ++i) {
21921 // If the cursor is over the object, it wins. If the
21922 // cursor is over multiple matches, the first one we come
21924 if (dd.cursorIsOver) {
21927 // Otherwise the object with the most overlap wins
21930 winner.overlap.getArea() < dd.overlap.getArea()) {
21941 * Refreshes the cache of the top-left and bottom-right points of the
21942 * drag and drop objects in the specified group(s). This is in the
21943 * format that is stored in the drag and drop instance, so typical
21946 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
21950 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
21952 * @TODO this really should be an indexed array. Alternatively this
21953 * method could accept both.
21954 * @method refreshCache
21955 * @param {Object} groups an associative array of groups to refresh
21958 refreshCache: function(groups) {
21959 for (var sGroup in groups) {
21960 if ("string" != typeof sGroup) {
21963 for (var i in this.ids[sGroup]) {
21964 var oDD = this.ids[sGroup][i];
21966 if (this.isTypeOfDD(oDD)) {
21967 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
21968 var loc = this.getLocation(oDD);
21970 this.locationCache[oDD.id] = loc;
21972 delete this.locationCache[oDD.id];
21973 // this will unregister the drag and drop object if
21974 // the element is not in a usable state
21983 * This checks to make sure an element exists and is in the DOM. The
21984 * main purpose is to handle cases where innerHTML is used to remove
21985 * drag and drop objects from the DOM. IE provides an 'unspecified
21986 * error' when trying to access the offsetParent of such an element
21988 * @param {HTMLElement} el the element to check
21989 * @return {boolean} true if the element looks usable
21992 verifyEl: function(el) {
21997 parent = el.offsetParent;
22000 parent = el.offsetParent;
22011 * Returns a Region object containing the drag and drop element's position
22012 * and size, including the padding configured for it
22013 * @method getLocation
22014 * @param {DragDrop} oDD the drag and drop object to get the
22016 * @return {Roo.lib.Region} a Region object representing the total area
22017 * the element occupies, including any padding
22018 * the instance is configured for.
22021 getLocation: function(oDD) {
22022 if (! this.isTypeOfDD(oDD)) {
22026 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
22029 pos= Roo.lib.Dom.getXY(el);
22037 x2 = x1 + el.offsetWidth;
22039 y2 = y1 + el.offsetHeight;
22041 t = y1 - oDD.padding[0];
22042 r = x2 + oDD.padding[1];
22043 b = y2 + oDD.padding[2];
22044 l = x1 - oDD.padding[3];
22046 return new Roo.lib.Region( t, r, b, l );
22050 * Checks the cursor location to see if it over the target
22051 * @method isOverTarget
22052 * @param {Roo.lib.Point} pt The point to evaluate
22053 * @param {DragDrop} oTarget the DragDrop object we are inspecting
22054 * @return {boolean} true if the mouse is over the target
22058 isOverTarget: function(pt, oTarget, intersect) {
22059 // use cache if available
22060 var loc = this.locationCache[oTarget.id];
22061 if (!loc || !this.useCache) {
22062 loc = this.getLocation(oTarget);
22063 this.locationCache[oTarget.id] = loc;
22071 oTarget.cursorIsOver = loc.contains( pt );
22073 // DragDrop is using this as a sanity check for the initial mousedown
22074 // in this case we are done. In POINT mode, if the drag obj has no
22075 // contraints, we are also done. Otherwise we need to evaluate the
22076 // location of the target as related to the actual location of the
22077 // dragged element.
22078 var dc = this.dragCurrent;
22079 if (!dc || !dc.getTargetCoord ||
22080 (!intersect && !dc.constrainX && !dc.constrainY)) {
22081 return oTarget.cursorIsOver;
22084 oTarget.overlap = null;
22086 // Get the current location of the drag element, this is the
22087 // location of the mouse event less the delta that represents
22088 // where the original mousedown happened on the element. We
22089 // need to consider constraints and ticks as well.
22090 var pos = dc.getTargetCoord(pt.x, pt.y);
22092 var el = dc.getDragEl();
22093 var curRegion = new Roo.lib.Region( pos.y,
22094 pos.x + el.offsetWidth,
22095 pos.y + el.offsetHeight,
22098 var overlap = curRegion.intersect(loc);
22101 oTarget.overlap = overlap;
22102 return (intersect) ? true : oTarget.cursorIsOver;
22109 * unload event handler
22110 * @method _onUnload
22114 _onUnload: function(e, me) {
22115 Roo.dd.DragDropMgr.unregAll();
22119 * Cleans up the drag and drop events and objects.
22124 unregAll: function() {
22126 if (this.dragCurrent) {
22128 this.dragCurrent = null;
22131 this._execOnAll("unreg", []);
22133 for (i in this.elementCache) {
22134 delete this.elementCache[i];
22137 this.elementCache = {};
22142 * A cache of DOM elements
22143 * @property elementCache
22150 * Get the wrapper for the DOM element specified
22151 * @method getElWrapper
22152 * @param {String} id the id of the element to get
22153 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
22155 * @deprecated This wrapper isn't that useful
22158 getElWrapper: function(id) {
22159 var oWrapper = this.elementCache[id];
22160 if (!oWrapper || !oWrapper.el) {
22161 oWrapper = this.elementCache[id] =
22162 new this.ElementWrapper(Roo.getDom(id));
22168 * Returns the actual DOM element
22169 * @method getElement
22170 * @param {String} id the id of the elment to get
22171 * @return {Object} The element
22172 * @deprecated use Roo.getDom instead
22175 getElement: function(id) {
22176 return Roo.getDom(id);
22180 * Returns the style property for the DOM element (i.e.,
22181 * document.getElById(id).style)
22183 * @param {String} id the id of the elment to get
22184 * @return {Object} The style property of the element
22185 * @deprecated use Roo.getDom instead
22188 getCss: function(id) {
22189 var el = Roo.getDom(id);
22190 return (el) ? el.style : null;
22194 * Inner class for cached elements
22195 * @class DragDropMgr.ElementWrapper
22200 ElementWrapper: function(el) {
22205 this.el = el || null;
22210 this.id = this.el && el.id;
22212 * A reference to the style property
22215 this.css = this.el && el.style;
22219 * Returns the X position of an html element
22221 * @param el the element for which to get the position
22222 * @return {int} the X coordinate
22224 * @deprecated use Roo.lib.Dom.getX instead
22227 getPosX: function(el) {
22228 return Roo.lib.Dom.getX(el);
22232 * Returns the Y position of an html element
22234 * @param el the element for which to get the position
22235 * @return {int} the Y coordinate
22236 * @deprecated use Roo.lib.Dom.getY instead
22239 getPosY: function(el) {
22240 return Roo.lib.Dom.getY(el);
22244 * Swap two nodes. In IE, we use the native method, for others we
22245 * emulate the IE behavior
22247 * @param n1 the first node to swap
22248 * @param n2 the other node to swap
22251 swapNode: function(n1, n2) {
22255 var p = n2.parentNode;
22256 var s = n2.nextSibling;
22259 p.insertBefore(n1, n2);
22260 } else if (n2 == n1.nextSibling) {
22261 p.insertBefore(n2, n1);
22263 n1.parentNode.replaceChild(n2, n1);
22264 p.insertBefore(n1, s);
22270 * Returns the current scroll position
22271 * @method getScroll
22275 getScroll: function () {
22276 var t, l, dde=document.documentElement, db=document.body;
22277 if (dde && (dde.scrollTop || dde.scrollLeft)) {
22279 l = dde.scrollLeft;
22286 return { top: t, left: l };
22290 * Returns the specified element style property
22292 * @param {HTMLElement} el the element
22293 * @param {string} styleProp the style property
22294 * @return {string} The value of the style property
22295 * @deprecated use Roo.lib.Dom.getStyle
22298 getStyle: function(el, styleProp) {
22299 return Roo.fly(el).getStyle(styleProp);
22303 * Gets the scrollTop
22304 * @method getScrollTop
22305 * @return {int} the document's scrollTop
22308 getScrollTop: function () { return this.getScroll().top; },
22311 * Gets the scrollLeft
22312 * @method getScrollLeft
22313 * @return {int} the document's scrollTop
22316 getScrollLeft: function () { return this.getScroll().left; },
22319 * Sets the x/y position of an element to the location of the
22322 * @param {HTMLElement} moveEl The element to move
22323 * @param {HTMLElement} targetEl The position reference element
22326 moveToEl: function (moveEl, targetEl) {
22327 var aCoord = Roo.lib.Dom.getXY(targetEl);
22328 Roo.lib.Dom.setXY(moveEl, aCoord);
22332 * Numeric array sort function
22333 * @method numericSort
22336 numericSort: function(a, b) { return (a - b); },
22340 * @property _timeoutCount
22347 * Trying to make the load order less important. Without this we get
22348 * an error if this file is loaded before the Event Utility.
22349 * @method _addListeners
22353 _addListeners: function() {
22354 var DDM = Roo.dd.DDM;
22355 if ( Roo.lib.Event && document ) {
22358 if (DDM._timeoutCount > 2000) {
22360 setTimeout(DDM._addListeners, 10);
22361 if (document && document.body) {
22362 DDM._timeoutCount += 1;
22369 * Recursively searches the immediate parent and all child nodes for
22370 * the handle element in order to determine wheter or not it was
22372 * @method handleWasClicked
22373 * @param node the html element to inspect
22376 handleWasClicked: function(node, id) {
22377 if (this.isHandle(id, node.id)) {
22380 // check to see if this is a text node child of the one we want
22381 var p = node.parentNode;
22384 if (this.isHandle(id, p.id)) {
22399 // shorter alias, save a few bytes
22400 Roo.dd.DDM = Roo.dd.DragDropMgr;
22401 Roo.dd.DDM._addListeners();
22405 * Ext JS Library 1.1.1
22406 * Copyright(c) 2006-2007, Ext JS, LLC.
22408 * Originally Released Under LGPL - original licence link has changed is not relivant.
22411 * <script type="text/javascript">
22416 * A DragDrop implementation where the linked element follows the
22417 * mouse cursor during a drag.
22418 * @extends Roo.dd.DragDrop
22420 * @param {String} id the id of the linked element
22421 * @param {String} sGroup the group of related DragDrop items
22422 * @param {object} config an object containing configurable attributes
22423 * Valid properties for DD:
22426 Roo.dd.DD = function(id, sGroup, config) {
22428 this.init(id, sGroup, config);
22432 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
22435 * When set to true, the utility automatically tries to scroll the browser
22436 * window wehn a drag and drop element is dragged near the viewport boundary.
22437 * Defaults to true.
22444 * Sets the pointer offset to the distance between the linked element's top
22445 * left corner and the location the element was clicked
22446 * @method autoOffset
22447 * @param {int} iPageX the X coordinate of the click
22448 * @param {int} iPageY the Y coordinate of the click
22450 autoOffset: function(iPageX, iPageY) {
22451 var x = iPageX - this.startPageX;
22452 var y = iPageY - this.startPageY;
22453 this.setDelta(x, y);
22457 * Sets the pointer offset. You can call this directly to force the
22458 * offset to be in a particular location (e.g., pass in 0,0 to set it
22459 * to the center of the object)
22461 * @param {int} iDeltaX the distance from the left
22462 * @param {int} iDeltaY the distance from the top
22464 setDelta: function(iDeltaX, iDeltaY) {
22465 this.deltaX = iDeltaX;
22466 this.deltaY = iDeltaY;
22470 * Sets the drag element to the location of the mousedown or click event,
22471 * maintaining the cursor location relative to the location on the element
22472 * that was clicked. Override this if you want to place the element in a
22473 * location other than where the cursor is.
22474 * @method setDragElPos
22475 * @param {int} iPageX the X coordinate of the mousedown or drag event
22476 * @param {int} iPageY the Y coordinate of the mousedown or drag event
22478 setDragElPos: function(iPageX, iPageY) {
22479 // the first time we do this, we are going to check to make sure
22480 // the element has css positioning
22482 var el = this.getDragEl();
22483 this.alignElWithMouse(el, iPageX, iPageY);
22487 * Sets the element to the location of the mousedown or click event,
22488 * maintaining the cursor location relative to the location on the element
22489 * that was clicked. Override this if you want to place the element in a
22490 * location other than where the cursor is.
22491 * @method alignElWithMouse
22492 * @param {HTMLElement} el the element to move
22493 * @param {int} iPageX the X coordinate of the mousedown or drag event
22494 * @param {int} iPageY the Y coordinate of the mousedown or drag event
22496 alignElWithMouse: function(el, iPageX, iPageY) {
22497 var oCoord = this.getTargetCoord(iPageX, iPageY);
22498 var fly = el.dom ? el : Roo.fly(el);
22499 if (!this.deltaSetXY) {
22500 var aCoord = [oCoord.x, oCoord.y];
22502 var newLeft = fly.getLeft(true);
22503 var newTop = fly.getTop(true);
22504 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
22506 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
22509 this.cachePosition(oCoord.x, oCoord.y);
22510 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
22515 * Saves the most recent position so that we can reset the constraints and
22516 * tick marks on-demand. We need to know this so that we can calculate the
22517 * number of pixels the element is offset from its original position.
22518 * @method cachePosition
22519 * @param iPageX the current x position (optional, this just makes it so we
22520 * don't have to look it up again)
22521 * @param iPageY the current y position (optional, this just makes it so we
22522 * don't have to look it up again)
22524 cachePosition: function(iPageX, iPageY) {
22526 this.lastPageX = iPageX;
22527 this.lastPageY = iPageY;
22529 var aCoord = Roo.lib.Dom.getXY(this.getEl());
22530 this.lastPageX = aCoord[0];
22531 this.lastPageY = aCoord[1];
22536 * Auto-scroll the window if the dragged object has been moved beyond the
22537 * visible window boundary.
22538 * @method autoScroll
22539 * @param {int} x the drag element's x position
22540 * @param {int} y the drag element's y position
22541 * @param {int} h the height of the drag element
22542 * @param {int} w the width of the drag element
22545 autoScroll: function(x, y, h, w) {
22548 // The client height
22549 var clientH = Roo.lib.Dom.getViewWidth();
22551 // The client width
22552 var clientW = Roo.lib.Dom.getViewHeight();
22554 // The amt scrolled down
22555 var st = this.DDM.getScrollTop();
22557 // The amt scrolled right
22558 var sl = this.DDM.getScrollLeft();
22560 // Location of the bottom of the element
22563 // Location of the right of the element
22566 // The distance from the cursor to the bottom of the visible area,
22567 // adjusted so that we don't scroll if the cursor is beyond the
22568 // element drag constraints
22569 var toBot = (clientH + st - y - this.deltaY);
22571 // The distance from the cursor to the right of the visible area
22572 var toRight = (clientW + sl - x - this.deltaX);
22575 // How close to the edge the cursor must be before we scroll
22576 // var thresh = (document.all) ? 100 : 40;
22579 // How many pixels to scroll per autoscroll op. This helps to reduce
22580 // clunky scrolling. IE is more sensitive about this ... it needs this
22581 // value to be higher.
22582 var scrAmt = (document.all) ? 80 : 30;
22584 // Scroll down if we are near the bottom of the visible page and the
22585 // obj extends below the crease
22586 if ( bot > clientH && toBot < thresh ) {
22587 window.scrollTo(sl, st + scrAmt);
22590 // Scroll up if the window is scrolled down and the top of the object
22591 // goes above the top border
22592 if ( y < st && st > 0 && y - st < thresh ) {
22593 window.scrollTo(sl, st - scrAmt);
22596 // Scroll right if the obj is beyond the right border and the cursor is
22597 // near the border.
22598 if ( right > clientW && toRight < thresh ) {
22599 window.scrollTo(sl + scrAmt, st);
22602 // Scroll left if the window has been scrolled to the right and the obj
22603 // extends past the left border
22604 if ( x < sl && sl > 0 && x - sl < thresh ) {
22605 window.scrollTo(sl - scrAmt, st);
22611 * Finds the location the element should be placed if we want to move
22612 * it to where the mouse location less the click offset would place us.
22613 * @method getTargetCoord
22614 * @param {int} iPageX the X coordinate of the click
22615 * @param {int} iPageY the Y coordinate of the click
22616 * @return an object that contains the coordinates (Object.x and Object.y)
22619 getTargetCoord: function(iPageX, iPageY) {
22622 var x = iPageX - this.deltaX;
22623 var y = iPageY - this.deltaY;
22625 if (this.constrainX) {
22626 if (x < this.minX) { x = this.minX; }
22627 if (x > this.maxX) { x = this.maxX; }
22630 if (this.constrainY) {
22631 if (y < this.minY) { y = this.minY; }
22632 if (y > this.maxY) { y = this.maxY; }
22635 x = this.getTick(x, this.xTicks);
22636 y = this.getTick(y, this.yTicks);
22643 * Sets up config options specific to this class. Overrides
22644 * Roo.dd.DragDrop, but all versions of this method through the
22645 * inheritance chain are called
22647 applyConfig: function() {
22648 Roo.dd.DD.superclass.applyConfig.call(this);
22649 this.scroll = (this.config.scroll !== false);
22653 * Event that fires prior to the onMouseDown event. Overrides
22656 b4MouseDown: function(e) {
22657 // this.resetConstraints();
22658 this.autoOffset(e.getPageX(),
22663 * Event that fires prior to the onDrag event. Overrides
22666 b4Drag: function(e) {
22667 this.setDragElPos(e.getPageX(),
22671 toString: function() {
22672 return ("DD " + this.id);
22675 //////////////////////////////////////////////////////////////////////////
22676 // Debugging ygDragDrop events that can be overridden
22677 //////////////////////////////////////////////////////////////////////////
22679 startDrag: function(x, y) {
22682 onDrag: function(e) {
22685 onDragEnter: function(e, id) {
22688 onDragOver: function(e, id) {
22691 onDragOut: function(e, id) {
22694 onDragDrop: function(e, id) {
22697 endDrag: function(e) {
22704 * Ext JS Library 1.1.1
22705 * Copyright(c) 2006-2007, Ext JS, LLC.
22707 * Originally Released Under LGPL - original licence link has changed is not relivant.
22710 * <script type="text/javascript">
22714 * @class Roo.dd.DDProxy
22715 * A DragDrop implementation that inserts an empty, bordered div into
22716 * the document that follows the cursor during drag operations. At the time of
22717 * the click, the frame div is resized to the dimensions of the linked html
22718 * element, and moved to the exact location of the linked element.
22720 * References to the "frame" element refer to the single proxy element that
22721 * was created to be dragged in place of all DDProxy elements on the
22724 * @extends Roo.dd.DD
22726 * @param {String} id the id of the linked html element
22727 * @param {String} sGroup the group of related DragDrop objects
22728 * @param {object} config an object containing configurable attributes
22729 * Valid properties for DDProxy in addition to those in DragDrop:
22730 * resizeFrame, centerFrame, dragElId
22732 Roo.dd.DDProxy = function(id, sGroup, config) {
22734 this.init(id, sGroup, config);
22740 * The default drag frame div id
22741 * @property Roo.dd.DDProxy.dragElId
22745 Roo.dd.DDProxy.dragElId = "ygddfdiv";
22747 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
22750 * By default we resize the drag frame to be the same size as the element
22751 * we want to drag (this is to get the frame effect). We can turn it off
22752 * if we want a different behavior.
22753 * @property resizeFrame
22759 * By default the frame is positioned exactly where the drag element is, so
22760 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
22761 * you do not have constraints on the obj is to have the drag frame centered
22762 * around the cursor. Set centerFrame to true for this effect.
22763 * @property centerFrame
22766 centerFrame: false,
22769 * Creates the proxy element if it does not yet exist
22770 * @method createFrame
22772 createFrame: function() {
22774 var body = document.body;
22776 if (!body || !body.firstChild) {
22777 setTimeout( function() { self.createFrame(); }, 50 );
22781 var div = this.getDragEl();
22784 div = document.createElement("div");
22785 div.id = this.dragElId;
22788 s.position = "absolute";
22789 s.visibility = "hidden";
22791 s.border = "2px solid #aaa";
22794 // appendChild can blow up IE if invoked prior to the window load event
22795 // while rendering a table. It is possible there are other scenarios
22796 // that would cause this to happen as well.
22797 body.insertBefore(div, body.firstChild);
22802 * Initialization for the drag frame element. Must be called in the
22803 * constructor of all subclasses
22804 * @method initFrame
22806 initFrame: function() {
22807 this.createFrame();
22810 applyConfig: function() {
22811 Roo.dd.DDProxy.superclass.applyConfig.call(this);
22813 this.resizeFrame = (this.config.resizeFrame !== false);
22814 this.centerFrame = (this.config.centerFrame);
22815 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
22819 * Resizes the drag frame to the dimensions of the clicked object, positions
22820 * it over the object, and finally displays it
22821 * @method showFrame
22822 * @param {int} iPageX X click position
22823 * @param {int} iPageY Y click position
22826 showFrame: function(iPageX, iPageY) {
22827 var el = this.getEl();
22828 var dragEl = this.getDragEl();
22829 var s = dragEl.style;
22831 this._resizeProxy();
22833 if (this.centerFrame) {
22834 this.setDelta( Math.round(parseInt(s.width, 10)/2),
22835 Math.round(parseInt(s.height, 10)/2) );
22838 this.setDragElPos(iPageX, iPageY);
22840 Roo.fly(dragEl).show();
22844 * The proxy is automatically resized to the dimensions of the linked
22845 * element when a drag is initiated, unless resizeFrame is set to false
22846 * @method _resizeProxy
22849 _resizeProxy: function() {
22850 if (this.resizeFrame) {
22851 var el = this.getEl();
22852 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
22856 // overrides Roo.dd.DragDrop
22857 b4MouseDown: function(e) {
22858 var x = e.getPageX();
22859 var y = e.getPageY();
22860 this.autoOffset(x, y);
22861 this.setDragElPos(x, y);
22864 // overrides Roo.dd.DragDrop
22865 b4StartDrag: function(x, y) {
22866 // show the drag frame
22867 this.showFrame(x, y);
22870 // overrides Roo.dd.DragDrop
22871 b4EndDrag: function(e) {
22872 Roo.fly(this.getDragEl()).hide();
22875 // overrides Roo.dd.DragDrop
22876 // By default we try to move the element to the last location of the frame.
22877 // This is so that the default behavior mirrors that of Roo.dd.DD.
22878 endDrag: function(e) {
22880 var lel = this.getEl();
22881 var del = this.getDragEl();
22883 // Show the drag frame briefly so we can get its position
22884 del.style.visibility = "";
22887 // Hide the linked element before the move to get around a Safari
22889 lel.style.visibility = "hidden";
22890 Roo.dd.DDM.moveToEl(lel, del);
22891 del.style.visibility = "hidden";
22892 lel.style.visibility = "";
22897 beforeMove : function(){
22901 afterDrag : function(){
22905 toString: function() {
22906 return ("DDProxy " + this.id);
22912 * Ext JS Library 1.1.1
22913 * Copyright(c) 2006-2007, Ext JS, LLC.
22915 * Originally Released Under LGPL - original licence link has changed is not relivant.
22918 * <script type="text/javascript">
22922 * @class Roo.dd.DDTarget
22923 * A DragDrop implementation that does not move, but can be a drop
22924 * target. You would get the same result by simply omitting implementation
22925 * for the event callbacks, but this way we reduce the processing cost of the
22926 * event listener and the callbacks.
22927 * @extends Roo.dd.DragDrop
22929 * @param {String} id the id of the element that is a drop target
22930 * @param {String} sGroup the group of related DragDrop objects
22931 * @param {object} config an object containing configurable attributes
22932 * Valid properties for DDTarget in addition to those in
22936 Roo.dd.DDTarget = function(id, sGroup, config) {
22938 this.initTarget(id, sGroup, config);
22940 if (config && (config.listeners || config.events)) {
22941 Roo.dd.DragDrop.superclass.constructor.call(this, {
22942 listeners : config.listeners || {},
22943 events : config.events || {}
22948 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
22949 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
22950 toString: function() {
22951 return ("DDTarget " + this.id);
22956 * Ext JS Library 1.1.1
22957 * Copyright(c) 2006-2007, Ext JS, LLC.
22959 * Originally Released Under LGPL - original licence link has changed is not relivant.
22962 * <script type="text/javascript">
22967 * @class Roo.dd.ScrollManager
22968 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
22969 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
22972 Roo.dd.ScrollManager = function(){
22973 var ddm = Roo.dd.DragDropMgr;
22980 var onStop = function(e){
22985 var triggerRefresh = function(){
22986 if(ddm.dragCurrent){
22987 ddm.refreshCache(ddm.dragCurrent.groups);
22991 var doScroll = function(){
22992 if(ddm.dragCurrent){
22993 var dds = Roo.dd.ScrollManager;
22995 if(proc.el.scroll(proc.dir, dds.increment)){
22999 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
23004 var clearProc = function(){
23006 clearInterval(proc.id);
23013 var startProc = function(el, dir){
23014 Roo.log('scroll startproc');
23018 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
23021 var onFire = function(e, isDrop){
23023 if(isDrop || !ddm.dragCurrent){ return; }
23024 var dds = Roo.dd.ScrollManager;
23025 if(!dragEl || dragEl != ddm.dragCurrent){
23026 dragEl = ddm.dragCurrent;
23027 // refresh regions on drag start
23028 dds.refreshCache();
23031 var xy = Roo.lib.Event.getXY(e);
23032 var pt = new Roo.lib.Point(xy[0], xy[1]);
23033 for(var id in els){
23034 var el = els[id], r = el._region;
23035 if(r && r.contains(pt) && el.isScrollable()){
23036 if(r.bottom - pt.y <= dds.thresh){
23038 startProc(el, "down");
23041 }else if(r.right - pt.x <= dds.thresh){
23043 startProc(el, "left");
23046 }else if(pt.y - r.top <= dds.thresh){
23048 startProc(el, "up");
23051 }else if(pt.x - r.left <= dds.thresh){
23053 startProc(el, "right");
23062 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
23063 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
23067 * Registers new overflow element(s) to auto scroll
23068 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
23070 register : function(el){
23071 if(el instanceof Array){
23072 for(var i = 0, len = el.length; i < len; i++) {
23073 this.register(el[i]);
23079 Roo.dd.ScrollManager.els = els;
23083 * Unregisters overflow element(s) so they are no longer scrolled
23084 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
23086 unregister : function(el){
23087 if(el instanceof Array){
23088 for(var i = 0, len = el.length; i < len; i++) {
23089 this.unregister(el[i]);
23098 * The number of pixels from the edge of a container the pointer needs to be to
23099 * trigger scrolling (defaults to 25)
23105 * The number of pixels to scroll in each scroll increment (defaults to 50)
23111 * The frequency of scrolls in milliseconds (defaults to 500)
23117 * True to animate the scroll (defaults to true)
23123 * The animation duration in seconds -
23124 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
23130 * Manually trigger a cache refresh.
23132 refreshCache : function(){
23133 for(var id in els){
23134 if(typeof els[id] == 'object'){ // for people extending the object prototype
23135 els[id]._region = els[id].getRegion();
23142 * Ext JS Library 1.1.1
23143 * Copyright(c) 2006-2007, Ext JS, LLC.
23145 * Originally Released Under LGPL - original licence link has changed is not relivant.
23148 * <script type="text/javascript">
23153 * @class Roo.dd.Registry
23154 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
23155 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
23158 Roo.dd.Registry = function(){
23161 var autoIdSeed = 0;
23163 var getId = function(el, autogen){
23164 if(typeof el == "string"){
23168 if(!id && autogen !== false){
23169 id = "roodd-" + (++autoIdSeed);
23177 * Register a drag drop element
23178 * @param {String|HTMLElement} element The id or DOM node to register
23179 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
23180 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
23181 * knows how to interpret, plus there are some specific properties known to the Registry that should be
23182 * populated in the data object (if applicable):
23184 Value Description<br />
23185 --------- ------------------------------------------<br />
23186 handles Array of DOM nodes that trigger dragging<br />
23187 for the element being registered<br />
23188 isHandle True if the element passed in triggers<br />
23189 dragging itself, else false
23192 register : function(el, data){
23194 if(typeof el == "string"){
23195 el = document.getElementById(el);
23198 elements[getId(el)] = data;
23199 if(data.isHandle !== false){
23200 handles[data.ddel.id] = data;
23203 var hs = data.handles;
23204 for(var i = 0, len = hs.length; i < len; i++){
23205 handles[getId(hs[i])] = data;
23211 * Unregister a drag drop element
23212 * @param {String|HTMLElement} element The id or DOM node to unregister
23214 unregister : function(el){
23215 var id = getId(el, false);
23216 var data = elements[id];
23218 delete elements[id];
23220 var hs = data.handles;
23221 for(var i = 0, len = hs.length; i < len; i++){
23222 delete handles[getId(hs[i], false)];
23229 * Returns the handle registered for a DOM Node by id
23230 * @param {String|HTMLElement} id The DOM node or id to look up
23231 * @return {Object} handle The custom handle data
23233 getHandle : function(id){
23234 if(typeof id != "string"){ // must be element?
23237 return handles[id];
23241 * Returns the handle that is registered for the DOM node that is the target of the event
23242 * @param {Event} e The event
23243 * @return {Object} handle The custom handle data
23245 getHandleFromEvent : function(e){
23246 var t = Roo.lib.Event.getTarget(e);
23247 return t ? handles[t.id] : null;
23251 * Returns a custom data object that is registered for a DOM node by id
23252 * @param {String|HTMLElement} id The DOM node or id to look up
23253 * @return {Object} data The custom data
23255 getTarget : function(id){
23256 if(typeof id != "string"){ // must be element?
23259 return elements[id];
23263 * Returns a custom data object that is registered for the DOM node that is the target of the event
23264 * @param {Event} e The event
23265 * @return {Object} data The custom data
23267 getTargetFromEvent : function(e){
23268 var t = Roo.lib.Event.getTarget(e);
23269 return t ? elements[t.id] || handles[t.id] : null;
23274 * Ext JS Library 1.1.1
23275 * Copyright(c) 2006-2007, Ext JS, LLC.
23277 * Originally Released Under LGPL - original licence link has changed is not relivant.
23280 * <script type="text/javascript">
23285 * @class Roo.dd.StatusProxy
23286 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
23287 * default drag proxy used by all Roo.dd components.
23289 * @param {Object} config
23291 Roo.dd.StatusProxy = function(config){
23292 Roo.apply(this, config);
23293 this.id = this.id || Roo.id();
23294 this.el = new Roo.Layer({
23296 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
23297 {tag: "div", cls: "x-dd-drop-icon"},
23298 {tag: "div", cls: "x-dd-drag-ghost"}
23301 shadow: !config || config.shadow !== false
23303 this.ghost = Roo.get(this.el.dom.childNodes[1]);
23304 this.dropStatus = this.dropNotAllowed;
23307 Roo.dd.StatusProxy.prototype = {
23309 * @cfg {String} dropAllowed
23310 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
23312 dropAllowed : "x-dd-drop-ok",
23314 * @cfg {String} dropNotAllowed
23315 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
23317 dropNotAllowed : "x-dd-drop-nodrop",
23320 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
23321 * over the current target element.
23322 * @param {String} cssClass The css class for the new drop status indicator image
23324 setStatus : function(cssClass){
23325 cssClass = cssClass || this.dropNotAllowed;
23326 if(this.dropStatus != cssClass){
23327 this.el.replaceClass(this.dropStatus, cssClass);
23328 this.dropStatus = cssClass;
23333 * Resets the status indicator to the default dropNotAllowed value
23334 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
23336 reset : function(clearGhost){
23337 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
23338 this.dropStatus = this.dropNotAllowed;
23340 this.ghost.update("");
23345 * Updates the contents of the ghost element
23346 * @param {String} html The html that will replace the current innerHTML of the ghost element
23348 update : function(html){
23349 if(typeof html == "string"){
23350 this.ghost.update(html);
23352 this.ghost.update("");
23353 html.style.margin = "0";
23354 this.ghost.dom.appendChild(html);
23356 // ensure float = none set?? cant remember why though.
23357 var el = this.ghost.dom.firstChild;
23359 Roo.fly(el).setStyle('float', 'none');
23364 * Returns the underlying proxy {@link Roo.Layer}
23365 * @return {Roo.Layer} el
23367 getEl : function(){
23372 * Returns the ghost element
23373 * @return {Roo.Element} el
23375 getGhost : function(){
23381 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
23383 hide : function(clear){
23391 * Stops the repair animation if it's currently running
23394 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
23400 * Displays this proxy
23407 * Force the Layer to sync its shadow and shim positions to the element
23414 * Causes the proxy to return to its position of origin via an animation. Should be called after an
23415 * invalid drop operation by the item being dragged.
23416 * @param {Array} xy The XY position of the element ([x, y])
23417 * @param {Function} callback The function to call after the repair is complete
23418 * @param {Object} scope The scope in which to execute the callback
23420 repair : function(xy, callback, scope){
23421 this.callback = callback;
23422 this.scope = scope;
23423 if(xy && this.animRepair !== false){
23424 this.el.addClass("x-dd-drag-repair");
23425 this.el.hideUnders(true);
23426 this.anim = this.el.shift({
23427 duration: this.repairDuration || .5,
23431 callback: this.afterRepair,
23435 this.afterRepair();
23440 afterRepair : function(){
23442 if(typeof this.callback == "function"){
23443 this.callback.call(this.scope || this);
23445 this.callback = null;
23450 * Ext JS Library 1.1.1
23451 * Copyright(c) 2006-2007, Ext JS, LLC.
23453 * Originally Released Under LGPL - original licence link has changed is not relivant.
23456 * <script type="text/javascript">
23460 * @class Roo.dd.DragSource
23461 * @extends Roo.dd.DDProxy
23462 * A simple class that provides the basic implementation needed to make any element draggable.
23464 * @param {String/HTMLElement/Element} el The container element
23465 * @param {Object} config
23467 Roo.dd.DragSource = function(el, config){
23468 this.el = Roo.get(el);
23469 this.dragData = {};
23471 Roo.apply(this, config);
23474 this.proxy = new Roo.dd.StatusProxy();
23477 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
23478 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
23480 this.dragging = false;
23483 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
23485 * @cfg {String} dropAllowed
23486 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23488 dropAllowed : "x-dd-drop-ok",
23490 * @cfg {String} dropNotAllowed
23491 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23493 dropNotAllowed : "x-dd-drop-nodrop",
23496 * Returns the data object associated with this drag source
23497 * @return {Object} data An object containing arbitrary data
23499 getDragData : function(e){
23500 return this.dragData;
23504 onDragEnter : function(e, id){
23505 var target = Roo.dd.DragDropMgr.getDDById(id);
23506 this.cachedTarget = target;
23507 if(this.beforeDragEnter(target, e, id) !== false){
23508 if(target.isNotifyTarget){
23509 var status = target.notifyEnter(this, e, this.dragData);
23510 this.proxy.setStatus(status);
23512 this.proxy.setStatus(this.dropAllowed);
23515 if(this.afterDragEnter){
23517 * An empty function by default, but provided so that you can perform a custom action
23518 * when the dragged item enters the drop target by providing an implementation.
23519 * @param {Roo.dd.DragDrop} target The drop target
23520 * @param {Event} e The event object
23521 * @param {String} id The id of the dragged element
23522 * @method afterDragEnter
23524 this.afterDragEnter(target, e, id);
23530 * An empty function by default, but provided so that you can perform a custom action
23531 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
23532 * @param {Roo.dd.DragDrop} target The drop target
23533 * @param {Event} e The event object
23534 * @param {String} id The id of the dragged element
23535 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23537 beforeDragEnter : function(target, e, id){
23542 alignElWithMouse: function() {
23543 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
23548 onDragOver : function(e, id){
23549 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23550 if(this.beforeDragOver(target, e, id) !== false){
23551 if(target.isNotifyTarget){
23552 var status = target.notifyOver(this, e, this.dragData);
23553 this.proxy.setStatus(status);
23556 if(this.afterDragOver){
23558 * An empty function by default, but provided so that you can perform a custom action
23559 * while the dragged item is over the drop target by providing an implementation.
23560 * @param {Roo.dd.DragDrop} target The drop target
23561 * @param {Event} e The event object
23562 * @param {String} id The id of the dragged element
23563 * @method afterDragOver
23565 this.afterDragOver(target, e, id);
23571 * An empty function by default, but provided so that you can perform a custom action
23572 * while the dragged item is over the drop target and optionally cancel the onDragOver.
23573 * @param {Roo.dd.DragDrop} target The drop target
23574 * @param {Event} e The event object
23575 * @param {String} id The id of the dragged element
23576 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23578 beforeDragOver : function(target, e, id){
23583 onDragOut : function(e, id){
23584 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23585 if(this.beforeDragOut(target, e, id) !== false){
23586 if(target.isNotifyTarget){
23587 target.notifyOut(this, e, this.dragData);
23589 this.proxy.reset();
23590 if(this.afterDragOut){
23592 * An empty function by default, but provided so that you can perform a custom action
23593 * after the dragged item is dragged out of the target without dropping.
23594 * @param {Roo.dd.DragDrop} target The drop target
23595 * @param {Event} e The event object
23596 * @param {String} id The id of the dragged element
23597 * @method afterDragOut
23599 this.afterDragOut(target, e, id);
23602 this.cachedTarget = null;
23606 * An empty function by default, but provided so that you can perform a custom action before the dragged
23607 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
23608 * @param {Roo.dd.DragDrop} target The drop target
23609 * @param {Event} e The event object
23610 * @param {String} id The id of the dragged element
23611 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23613 beforeDragOut : function(target, e, id){
23618 onDragDrop : function(e, id){
23619 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23620 if(this.beforeDragDrop(target, e, id) !== false){
23621 if(target.isNotifyTarget){
23622 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
23623 this.onValidDrop(target, e, id);
23625 this.onInvalidDrop(target, e, id);
23628 this.onValidDrop(target, e, id);
23631 if(this.afterDragDrop){
23633 * An empty function by default, but provided so that you can perform a custom action
23634 * after a valid drag drop has occurred by providing an implementation.
23635 * @param {Roo.dd.DragDrop} target The drop target
23636 * @param {Event} e The event object
23637 * @param {String} id The id of the dropped element
23638 * @method afterDragDrop
23640 this.afterDragDrop(target, e, id);
23643 delete this.cachedTarget;
23647 * An empty function by default, but provided so that you can perform a custom action before the dragged
23648 * item is dropped onto the target and optionally cancel the onDragDrop.
23649 * @param {Roo.dd.DragDrop} target The drop target
23650 * @param {Event} e The event object
23651 * @param {String} id The id of the dragged element
23652 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
23654 beforeDragDrop : function(target, e, id){
23659 onValidDrop : function(target, e, id){
23661 if(this.afterValidDrop){
23663 * An empty function by default, but provided so that you can perform a custom action
23664 * after a valid drop has occurred by providing an implementation.
23665 * @param {Object} target The target DD
23666 * @param {Event} e The event object
23667 * @param {String} id The id of the dropped element
23668 * @method afterInvalidDrop
23670 this.afterValidDrop(target, e, id);
23675 getRepairXY : function(e, data){
23676 return this.el.getXY();
23680 onInvalidDrop : function(target, e, id){
23681 this.beforeInvalidDrop(target, e, id);
23682 if(this.cachedTarget){
23683 if(this.cachedTarget.isNotifyTarget){
23684 this.cachedTarget.notifyOut(this, e, this.dragData);
23686 this.cacheTarget = null;
23688 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
23690 if(this.afterInvalidDrop){
23692 * An empty function by default, but provided so that you can perform a custom action
23693 * after an invalid drop has occurred by providing an implementation.
23694 * @param {Event} e The event object
23695 * @param {String} id The id of the dropped element
23696 * @method afterInvalidDrop
23698 this.afterInvalidDrop(e, id);
23703 afterRepair : function(){
23705 this.el.highlight(this.hlColor || "c3daf9");
23707 this.dragging = false;
23711 * An empty function by default, but provided so that you can perform a custom action after an invalid
23712 * drop has occurred.
23713 * @param {Roo.dd.DragDrop} target The drop target
23714 * @param {Event} e The event object
23715 * @param {String} id The id of the dragged element
23716 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
23718 beforeInvalidDrop : function(target, e, id){
23723 handleMouseDown : function(e){
23724 if(this.dragging) {
23727 var data = this.getDragData(e);
23728 if(data && this.onBeforeDrag(data, e) !== false){
23729 this.dragData = data;
23731 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
23736 * An empty function by default, but provided so that you can perform a custom action before the initial
23737 * drag event begins and optionally cancel it.
23738 * @param {Object} data An object containing arbitrary data to be shared with drop targets
23739 * @param {Event} e The event object
23740 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23742 onBeforeDrag : function(data, e){
23747 * An empty function by default, but provided so that you can perform a custom action once the initial
23748 * drag event has begun. The drag cannot be canceled from this function.
23749 * @param {Number} x The x position of the click on the dragged object
23750 * @param {Number} y The y position of the click on the dragged object
23752 onStartDrag : Roo.emptyFn,
23754 // private - YUI override
23755 startDrag : function(x, y){
23756 this.proxy.reset();
23757 this.dragging = true;
23758 this.proxy.update("");
23759 this.onInitDrag(x, y);
23764 onInitDrag : function(x, y){
23765 var clone = this.el.dom.cloneNode(true);
23766 clone.id = Roo.id(); // prevent duplicate ids
23767 this.proxy.update(clone);
23768 this.onStartDrag(x, y);
23773 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
23774 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
23776 getProxy : function(){
23781 * Hides the drag source's {@link Roo.dd.StatusProxy}
23783 hideProxy : function(){
23785 this.proxy.reset(true);
23786 this.dragging = false;
23790 triggerCacheRefresh : function(){
23791 Roo.dd.DDM.refreshCache(this.groups);
23794 // private - override to prevent hiding
23795 b4EndDrag: function(e) {
23798 // private - override to prevent moving
23799 endDrag : function(e){
23800 this.onEndDrag(this.dragData, e);
23804 onEndDrag : function(data, e){
23807 // private - pin to cursor
23808 autoOffset : function(x, y) {
23809 this.setDelta(-12, -20);
23813 * Ext JS Library 1.1.1
23814 * Copyright(c) 2006-2007, Ext JS, LLC.
23816 * Originally Released Under LGPL - original licence link has changed is not relivant.
23819 * <script type="text/javascript">
23824 * @class Roo.dd.DropTarget
23825 * @extends Roo.dd.DDTarget
23826 * A simple class that provides the basic implementation needed to make any element a drop target that can have
23827 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
23829 * @param {String/HTMLElement/Element} el The container element
23830 * @param {Object} config
23832 Roo.dd.DropTarget = function(el, config){
23833 this.el = Roo.get(el);
23835 var listeners = false; ;
23836 if (config && config.listeners) {
23837 listeners= config.listeners;
23838 delete config.listeners;
23840 Roo.apply(this, config);
23842 if(this.containerScroll){
23843 Roo.dd.ScrollManager.register(this.el);
23847 * @scope Roo.dd.DropTarget
23852 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
23853 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
23854 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
23856 * IMPORTANT : it should set this.valid to true|false
23858 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23859 * @param {Event} e The event
23860 * @param {Object} data An object containing arbitrary data supplied by the drag source
23866 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
23867 * This method will be called on every mouse movement while the drag source is over the drop target.
23868 * This default implementation simply returns the dropAllowed config value.
23870 * IMPORTANT : it should set this.valid to true|false
23872 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23873 * @param {Event} e The event
23874 * @param {Object} data An object containing arbitrary data supplied by the drag source
23880 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
23881 * out of the target without dropping. This default implementation simply removes the CSS class specified by
23882 * overClass (if any) from the drop element.
23885 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23886 * @param {Event} e The event
23887 * @param {Object} data An object containing arbitrary data supplied by the drag source
23893 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
23894 * been dropped on it. This method has no default implementation and returns false, so you must provide an
23895 * implementation that does something to process the drop event and returns true so that the drag source's
23896 * repair action does not run.
23898 * IMPORTANT : it should set this.success
23900 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23901 * @param {Event} e The event
23902 * @param {Object} data An object containing arbitrary data supplied by the drag source
23908 Roo.dd.DropTarget.superclass.constructor.call( this,
23910 this.ddGroup || this.group,
23913 listeners : listeners || {}
23921 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
23923 * @cfg {String} overClass
23924 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
23927 * @cfg {String} ddGroup
23928 * The drag drop group to handle drop events for
23932 * @cfg {String} dropAllowed
23933 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23935 dropAllowed : "x-dd-drop-ok",
23937 * @cfg {String} dropNotAllowed
23938 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23940 dropNotAllowed : "x-dd-drop-nodrop",
23942 * @cfg {boolean} success
23943 * set this after drop listener..
23947 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
23948 * if the drop point is valid for over/enter..
23955 isNotifyTarget : true,
23960 notifyEnter : function(dd, e, data)
23963 this.fireEvent('enter', dd, e, data);
23964 if(this.overClass){
23965 this.el.addClass(this.overClass);
23967 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23968 this.valid ? this.dropAllowed : this.dropNotAllowed
23975 notifyOver : function(dd, e, data)
23978 this.fireEvent('over', dd, e, data);
23979 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23980 this.valid ? this.dropAllowed : this.dropNotAllowed
23987 notifyOut : function(dd, e, data)
23989 this.fireEvent('out', dd, e, data);
23990 if(this.overClass){
23991 this.el.removeClass(this.overClass);
23998 notifyDrop : function(dd, e, data)
24000 this.success = false;
24001 this.fireEvent('drop', dd, e, data);
24002 return this.success;
24006 * Ext JS Library 1.1.1
24007 * Copyright(c) 2006-2007, Ext JS, LLC.
24009 * Originally Released Under LGPL - original licence link has changed is not relivant.
24012 * <script type="text/javascript">
24017 * @class Roo.dd.DragZone
24018 * @extends Roo.dd.DragSource
24019 * This class provides a container DD instance that proxies for multiple child node sources.<br />
24020 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
24022 * @param {String/HTMLElement/Element} el The container element
24023 * @param {Object} config
24025 Roo.dd.DragZone = function(el, config){
24026 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
24027 if(this.containerScroll){
24028 Roo.dd.ScrollManager.register(this.el);
24032 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
24034 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
24035 * for auto scrolling during drag operations.
24038 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
24039 * method after a failed drop (defaults to "c3daf9" - light blue)
24043 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
24044 * for a valid target to drag based on the mouse down. Override this method
24045 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
24046 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
24047 * @param {EventObject} e The mouse down event
24048 * @return {Object} The dragData
24050 getDragData : function(e){
24051 return Roo.dd.Registry.getHandleFromEvent(e);
24055 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
24056 * this.dragData.ddel
24057 * @param {Number} x The x position of the click on the dragged object
24058 * @param {Number} y The y position of the click on the dragged object
24059 * @return {Boolean} true to continue the drag, false to cancel
24061 onInitDrag : function(x, y){
24062 this.proxy.update(this.dragData.ddel.cloneNode(true));
24063 this.onStartDrag(x, y);
24068 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
24070 afterRepair : function(){
24072 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
24074 this.dragging = false;
24078 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
24079 * the XY of this.dragData.ddel
24080 * @param {EventObject} e The mouse up event
24081 * @return {Array} The xy location (e.g. [100, 200])
24083 getRepairXY : function(e){
24084 return Roo.Element.fly(this.dragData.ddel).getXY();
24088 * Ext JS Library 1.1.1
24089 * Copyright(c) 2006-2007, Ext JS, LLC.
24091 * Originally Released Under LGPL - original licence link has changed is not relivant.
24094 * <script type="text/javascript">
24097 * @class Roo.dd.DropZone
24098 * @extends Roo.dd.DropTarget
24099 * This class provides a container DD instance that proxies for multiple child node targets.<br />
24100 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
24102 * @param {String/HTMLElement/Element} el The container element
24103 * @param {Object} config
24105 Roo.dd.DropZone = function(el, config){
24106 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
24109 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
24111 * Returns a custom data object associated with the DOM node that is the target of the event. By default
24112 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
24113 * provide your own custom lookup.
24114 * @param {Event} e The event
24115 * @return {Object} data The custom data
24117 getTargetFromEvent : function(e){
24118 return Roo.dd.Registry.getTargetFromEvent(e);
24122 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
24123 * that it has registered. This method has no default implementation and should be overridden to provide
24124 * node-specific processing if necessary.
24125 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24126 * {@link #getTargetFromEvent} for this node)
24127 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24128 * @param {Event} e The event
24129 * @param {Object} data An object containing arbitrary data supplied by the drag source
24131 onNodeEnter : function(n, dd, e, data){
24136 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
24137 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
24138 * overridden to provide the proper feedback.
24139 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24140 * {@link #getTargetFromEvent} for this node)
24141 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24142 * @param {Event} e The event
24143 * @param {Object} data An object containing arbitrary data supplied by the drag source
24144 * @return {String} status The CSS class that communicates the drop status back to the source so that the
24145 * underlying {@link Roo.dd.StatusProxy} can be updated
24147 onNodeOver : function(n, dd, e, data){
24148 return this.dropAllowed;
24152 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
24153 * the drop node without dropping. This method has no default implementation and should be overridden to provide
24154 * node-specific processing if necessary.
24155 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24156 * {@link #getTargetFromEvent} for this node)
24157 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24158 * @param {Event} e The event
24159 * @param {Object} data An object containing arbitrary data supplied by the drag source
24161 onNodeOut : function(n, dd, e, data){
24166 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
24167 * the drop node. The default implementation returns false, so it should be overridden to provide the
24168 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
24169 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24170 * {@link #getTargetFromEvent} for this node)
24171 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24172 * @param {Event} e The event
24173 * @param {Object} data An object containing arbitrary data supplied by the drag source
24174 * @return {Boolean} True if the drop was valid, else false
24176 onNodeDrop : function(n, dd, e, data){
24181 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
24182 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
24183 * it should be overridden to provide the proper feedback if necessary.
24184 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24185 * @param {Event} e The event
24186 * @param {Object} data An object containing arbitrary data supplied by the drag source
24187 * @return {String} status The CSS class that communicates the drop status back to the source so that the
24188 * underlying {@link Roo.dd.StatusProxy} can be updated
24190 onContainerOver : function(dd, e, data){
24191 return this.dropNotAllowed;
24195 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
24196 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
24197 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
24198 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
24199 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24200 * @param {Event} e The event
24201 * @param {Object} data An object containing arbitrary data supplied by the drag source
24202 * @return {Boolean} True if the drop was valid, else false
24204 onContainerDrop : function(dd, e, data){
24209 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
24210 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
24211 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
24212 * you should override this method and provide a custom implementation.
24213 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24214 * @param {Event} e The event
24215 * @param {Object} data An object containing arbitrary data supplied by the drag source
24216 * @return {String} status The CSS class that communicates the drop status back to the source so that the
24217 * underlying {@link Roo.dd.StatusProxy} can be updated
24219 notifyEnter : function(dd, e, data){
24220 return this.dropNotAllowed;
24224 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
24225 * This method will be called on every mouse movement while the drag source is over the drop zone.
24226 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
24227 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
24228 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
24229 * registered node, it will call {@link #onContainerOver}.
24230 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24231 * @param {Event} e The event
24232 * @param {Object} data An object containing arbitrary data supplied by the drag source
24233 * @return {String} status The CSS class that communicates the drop status back to the source so that the
24234 * underlying {@link Roo.dd.StatusProxy} can be updated
24236 notifyOver : function(dd, e, data){
24237 var n = this.getTargetFromEvent(e);
24238 if(!n){ // not over valid drop target
24239 if(this.lastOverNode){
24240 this.onNodeOut(this.lastOverNode, dd, e, data);
24241 this.lastOverNode = null;
24243 return this.onContainerOver(dd, e, data);
24245 if(this.lastOverNode != n){
24246 if(this.lastOverNode){
24247 this.onNodeOut(this.lastOverNode, dd, e, data);
24249 this.onNodeEnter(n, dd, e, data);
24250 this.lastOverNode = n;
24252 return this.onNodeOver(n, dd, e, data);
24256 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
24257 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
24258 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
24259 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24260 * @param {Event} e The event
24261 * @param {Object} data An object containing arbitrary data supplied by the drag zone
24263 notifyOut : function(dd, e, data){
24264 if(this.lastOverNode){
24265 this.onNodeOut(this.lastOverNode, dd, e, data);
24266 this.lastOverNode = null;
24271 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
24272 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
24273 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
24274 * otherwise it will call {@link #onContainerDrop}.
24275 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24276 * @param {Event} e The event
24277 * @param {Object} data An object containing arbitrary data supplied by the drag source
24278 * @return {Boolean} True if the drop was valid, else false
24280 notifyDrop : function(dd, e, data){
24281 if(this.lastOverNode){
24282 this.onNodeOut(this.lastOverNode, dd, e, data);
24283 this.lastOverNode = null;
24285 var n = this.getTargetFromEvent(e);
24287 this.onNodeDrop(n, dd, e, data) :
24288 this.onContainerDrop(dd, e, data);
24292 triggerCacheRefresh : function(){
24293 Roo.dd.DDM.refreshCache(this.groups);
24297 * Ext JS Library 1.1.1
24298 * Copyright(c) 2006-2007, Ext JS, LLC.
24300 * Originally Released Under LGPL - original licence link has changed is not relivant.
24303 * <script type="text/javascript">
24308 * @class Roo.data.SortTypes
24310 * Defines the default sorting (casting?) comparison functions used when sorting data.
24312 Roo.data.SortTypes = {
24314 * Default sort that does nothing
24315 * @param {Mixed} s The value being converted
24316 * @return {Mixed} The comparison value
24318 none : function(s){
24323 * The regular expression used to strip tags
24327 stripTagsRE : /<\/?[^>]+>/gi,
24330 * Strips all HTML tags to sort on text only
24331 * @param {Mixed} s The value being converted
24332 * @return {String} The comparison value
24334 asText : function(s){
24335 return String(s).replace(this.stripTagsRE, "");
24339 * Strips all HTML tags to sort on text only - Case insensitive
24340 * @param {Mixed} s The value being converted
24341 * @return {String} The comparison value
24343 asUCText : function(s){
24344 return String(s).toUpperCase().replace(this.stripTagsRE, "");
24348 * Case insensitive string
24349 * @param {Mixed} s The value being converted
24350 * @return {String} The comparison value
24352 asUCString : function(s) {
24353 return String(s).toUpperCase();
24358 * @param {Mixed} s The value being converted
24359 * @return {Number} The comparison value
24361 asDate : function(s) {
24365 if(s instanceof Date){
24366 return s.getTime();
24368 return Date.parse(String(s));
24373 * @param {Mixed} s The value being converted
24374 * @return {Float} The comparison value
24376 asFloat : function(s) {
24377 var val = parseFloat(String(s).replace(/,/g, ""));
24386 * @param {Mixed} s The value being converted
24387 * @return {Number} The comparison value
24389 asInt : function(s) {
24390 var val = parseInt(String(s).replace(/,/g, ""));
24398 * Ext JS Library 1.1.1
24399 * Copyright(c) 2006-2007, Ext JS, LLC.
24401 * Originally Released Under LGPL - original licence link has changed is not relivant.
24404 * <script type="text/javascript">
24408 * @class Roo.data.Record
24409 * Instances of this class encapsulate both record <em>definition</em> information, and record
24410 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
24411 * to access Records cached in an {@link Roo.data.Store} object.<br>
24413 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
24414 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
24417 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
24419 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
24420 * {@link #create}. The parameters are the same.
24421 * @param {Array} data An associative Array of data values keyed by the field name.
24422 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
24423 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
24424 * not specified an integer id is generated.
24426 Roo.data.Record = function(data, id){
24427 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
24432 * Generate a constructor for a specific record layout.
24433 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
24434 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
24435 * Each field definition object may contain the following properties: <ul>
24436 * <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,
24437 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
24438 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
24439 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
24440 * is being used, then this is a string containing the javascript expression to reference the data relative to
24441 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
24442 * to the data item relative to the record element. If the mapping expression is the same as the field name,
24443 * this may be omitted.</p></li>
24444 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
24445 * <ul><li>auto (Default, implies no conversion)</li>
24450 * <li>date</li></ul></p></li>
24451 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
24452 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
24453 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
24454 * by the Reader into an object that will be stored in the Record. It is passed the
24455 * following parameters:<ul>
24456 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
24458 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
24460 * <br>usage:<br><pre><code>
24461 var TopicRecord = Roo.data.Record.create(
24462 {name: 'title', mapping: 'topic_title'},
24463 {name: 'author', mapping: 'username'},
24464 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
24465 {name: 'lastPost', mapping: 'post_time', type: 'date'},
24466 {name: 'lastPoster', mapping: 'user2'},
24467 {name: 'excerpt', mapping: 'post_text'}
24470 var myNewRecord = new TopicRecord({
24471 title: 'Do my job please',
24474 lastPost: new Date(),
24475 lastPoster: 'Animal',
24476 excerpt: 'No way dude!'
24478 myStore.add(myNewRecord);
24483 Roo.data.Record.create = function(o){
24484 var f = function(){
24485 f.superclass.constructor.apply(this, arguments);
24487 Roo.extend(f, Roo.data.Record);
24488 var p = f.prototype;
24489 p.fields = new Roo.util.MixedCollection(false, function(field){
24492 for(var i = 0, len = o.length; i < len; i++){
24493 p.fields.add(new Roo.data.Field(o[i]));
24495 f.getField = function(name){
24496 return p.fields.get(name);
24501 Roo.data.Record.AUTO_ID = 1000;
24502 Roo.data.Record.EDIT = 'edit';
24503 Roo.data.Record.REJECT = 'reject';
24504 Roo.data.Record.COMMIT = 'commit';
24506 Roo.data.Record.prototype = {
24508 * Readonly flag - true if this record has been modified.
24517 join : function(store){
24518 this.store = store;
24522 * Set the named field to the specified value.
24523 * @param {String} name The name of the field to set.
24524 * @param {Object} value The value to set the field to.
24526 set : function(name, value){
24527 if(this.data[name] == value){
24531 if(!this.modified){
24532 this.modified = {};
24534 if(typeof this.modified[name] == 'undefined'){
24535 this.modified[name] = this.data[name];
24537 this.data[name] = value;
24538 if(!this.editing && this.store){
24539 this.store.afterEdit(this);
24544 * Get the value of the named field.
24545 * @param {String} name The name of the field to get the value of.
24546 * @return {Object} The value of the field.
24548 get : function(name){
24549 return this.data[name];
24553 beginEdit : function(){
24554 this.editing = true;
24555 this.modified = {};
24559 cancelEdit : function(){
24560 this.editing = false;
24561 delete this.modified;
24565 endEdit : function(){
24566 this.editing = false;
24567 if(this.dirty && this.store){
24568 this.store.afterEdit(this);
24573 * Usually called by the {@link Roo.data.Store} which owns the Record.
24574 * Rejects all changes made to the Record since either creation, or the last commit operation.
24575 * Modified fields are reverted to their original values.
24577 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
24578 * of reject operations.
24580 reject : function(){
24581 var m = this.modified;
24583 if(typeof m[n] != "function"){
24584 this.data[n] = m[n];
24587 this.dirty = false;
24588 delete this.modified;
24589 this.editing = false;
24591 this.store.afterReject(this);
24596 * Usually called by the {@link Roo.data.Store} which owns the Record.
24597 * Commits all changes made to the Record since either creation, or the last commit operation.
24599 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
24600 * of commit operations.
24602 commit : function(){
24603 this.dirty = false;
24604 delete this.modified;
24605 this.editing = false;
24607 this.store.afterCommit(this);
24612 hasError : function(){
24613 return this.error != null;
24617 clearError : function(){
24622 * Creates a copy of this record.
24623 * @param {String} id (optional) A new record id if you don't want to use this record's id
24626 copy : function(newId) {
24627 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
24631 * Ext JS Library 1.1.1
24632 * Copyright(c) 2006-2007, Ext JS, LLC.
24634 * Originally Released Under LGPL - original licence link has changed is not relivant.
24637 * <script type="text/javascript">
24643 * @class Roo.data.Store
24644 * @extends Roo.util.Observable
24645 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
24646 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
24648 * 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
24649 * has no knowledge of the format of the data returned by the Proxy.<br>
24651 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
24652 * instances from the data object. These records are cached and made available through accessor functions.
24654 * Creates a new Store.
24655 * @param {Object} config A config object containing the objects needed for the Store to access data,
24656 * and read the data into Records.
24658 Roo.data.Store = function(config){
24659 this.data = new Roo.util.MixedCollection(false);
24660 this.data.getKey = function(o){
24663 this.baseParams = {};
24665 this.paramNames = {
24670 "multisort" : "_multisort"
24673 if(config && config.data){
24674 this.inlineData = config.data;
24675 delete config.data;
24678 Roo.apply(this, config);
24680 if(this.reader){ // reader passed
24681 this.reader = Roo.factory(this.reader, Roo.data);
24682 this.reader.xmodule = this.xmodule || false;
24683 if(!this.recordType){
24684 this.recordType = this.reader.recordType;
24686 if(this.reader.onMetaChange){
24687 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
24691 if(this.recordType){
24692 this.fields = this.recordType.prototype.fields;
24694 this.modified = [];
24698 * @event datachanged
24699 * Fires when the data cache has changed, and a widget which is using this Store
24700 * as a Record cache should refresh its view.
24701 * @param {Store} this
24703 datachanged : true,
24705 * @event metachange
24706 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
24707 * @param {Store} this
24708 * @param {Object} meta The JSON metadata
24713 * Fires when Records have been added to the Store
24714 * @param {Store} this
24715 * @param {Roo.data.Record[]} records The array of Records added
24716 * @param {Number} index The index at which the record(s) were added
24721 * Fires when a Record has been removed from the Store
24722 * @param {Store} this
24723 * @param {Roo.data.Record} record The Record that was removed
24724 * @param {Number} index The index at which the record was removed
24729 * Fires when a Record has been updated
24730 * @param {Store} this
24731 * @param {Roo.data.Record} record The Record that was updated
24732 * @param {String} operation The update operation being performed. Value may be one of:
24734 Roo.data.Record.EDIT
24735 Roo.data.Record.REJECT
24736 Roo.data.Record.COMMIT
24742 * Fires when the data cache has been cleared.
24743 * @param {Store} this
24747 * @event beforeload
24748 * Fires before a request is made for a new data object. If the beforeload handler returns false
24749 * the load action will be canceled.
24750 * @param {Store} this
24751 * @param {Object} options The loading options that were specified (see {@link #load} for details)
24755 * @event beforeloadadd
24756 * Fires after a new set of Records has been loaded.
24757 * @param {Store} this
24758 * @param {Roo.data.Record[]} records The Records that were loaded
24759 * @param {Object} options The loading options that were specified (see {@link #load} for details)
24761 beforeloadadd : true,
24764 * Fires after a new set of Records has been loaded, before they are added to the store.
24765 * @param {Store} this
24766 * @param {Roo.data.Record[]} records The Records that were loaded
24767 * @param {Object} options The loading options that were specified (see {@link #load} for details)
24768 * @params {Object} return from reader
24772 * @event loadexception
24773 * Fires if an exception occurs in the Proxy during loading.
24774 * Called with the signature of the Proxy's "loadexception" event.
24775 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
24778 * @param {Object} return from JsonData.reader() - success, totalRecords, records
24779 * @param {Object} load options
24780 * @param {Object} jsonData from your request (normally this contains the Exception)
24782 loadexception : true
24786 this.proxy = Roo.factory(this.proxy, Roo.data);
24787 this.proxy.xmodule = this.xmodule || false;
24788 this.relayEvents(this.proxy, ["loadexception"]);
24790 this.sortToggle = {};
24791 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
24793 Roo.data.Store.superclass.constructor.call(this);
24795 if(this.inlineData){
24796 this.loadData(this.inlineData);
24797 delete this.inlineData;
24801 Roo.extend(Roo.data.Store, Roo.util.Observable, {
24803 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
24804 * without a remote query - used by combo/forms at present.
24808 * @cfg {Roo.data.DataProxy} proxy [required] The Proxy object which provides access to a data object.
24811 * @cfg {Array} data Inline data to be loaded when the store is initialized.
24814 * @cfg {Roo.data.DataReader} reader [required] The Reader object which processes the data object and returns
24815 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
24818 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
24819 * on any HTTP request
24822 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
24825 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
24829 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
24830 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
24832 remoteSort : false,
24835 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
24836 * loaded or when a record is removed. (defaults to false).
24838 pruneModifiedRecords : false,
24841 lastOptions : null,
24844 * Add Records to the Store and fires the add event.
24845 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
24847 add : function(records){
24848 records = [].concat(records);
24849 for(var i = 0, len = records.length; i < len; i++){
24850 records[i].join(this);
24852 var index = this.data.length;
24853 this.data.addAll(records);
24854 this.fireEvent("add", this, records, index);
24858 * Remove a Record from the Store and fires the remove event.
24859 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
24861 remove : function(record){
24862 var index = this.data.indexOf(record);
24863 this.data.removeAt(index);
24865 if(this.pruneModifiedRecords){
24866 this.modified.remove(record);
24868 this.fireEvent("remove", this, record, index);
24872 * Remove all Records from the Store and fires the clear event.
24874 removeAll : function(){
24876 if(this.pruneModifiedRecords){
24877 this.modified = [];
24879 this.fireEvent("clear", this);
24883 * Inserts Records to the Store at the given index and fires the add event.
24884 * @param {Number} index The start index at which to insert the passed Records.
24885 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
24887 insert : function(index, records){
24888 records = [].concat(records);
24889 for(var i = 0, len = records.length; i < len; i++){
24890 this.data.insert(index, records[i]);
24891 records[i].join(this);
24893 this.fireEvent("add", this, records, index);
24897 * Get the index within the cache of the passed Record.
24898 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
24899 * @return {Number} The index of the passed Record. Returns -1 if not found.
24901 indexOf : function(record){
24902 return this.data.indexOf(record);
24906 * Get the index within the cache of the Record with the passed id.
24907 * @param {String} id The id of the Record to find.
24908 * @return {Number} The index of the Record. Returns -1 if not found.
24910 indexOfId : function(id){
24911 return this.data.indexOfKey(id);
24915 * Get the Record with the specified id.
24916 * @param {String} id The id of the Record to find.
24917 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
24919 getById : function(id){
24920 return this.data.key(id);
24924 * Get the Record at the specified index.
24925 * @param {Number} index The index of the Record to find.
24926 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
24928 getAt : function(index){
24929 return this.data.itemAt(index);
24933 * Returns a range of Records between specified indices.
24934 * @param {Number} startIndex (optional) The starting index (defaults to 0)
24935 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
24936 * @return {Roo.data.Record[]} An array of Records
24938 getRange : function(start, end){
24939 return this.data.getRange(start, end);
24943 storeOptions : function(o){
24944 o = Roo.apply({}, o);
24947 this.lastOptions = o;
24951 * Loads the Record cache from the configured Proxy using the configured Reader.
24953 * If using remote paging, then the first load call must specify the <em>start</em>
24954 * and <em>limit</em> properties in the options.params property to establish the initial
24955 * position within the dataset, and the number of Records to cache on each read from the Proxy.
24957 * <strong>It is important to note that for remote data sources, loading is asynchronous,
24958 * and this call will return before the new data has been loaded. Perform any post-processing
24959 * in a callback function, or in a "load" event handler.</strong>
24961 * @param {Object} options An object containing properties which control loading options:<ul>
24962 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
24963 * <li>params.data {Object} if you are using a MemoryProxy / JsonReader, use this as the data to load stuff..
24966 data : data, // array of key=>value data like JsonReader
24967 total : data.length,
24973 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
24974 * passed the following arguments:<ul>
24975 * <li>r : Roo.data.Record[]</li>
24976 * <li>options: Options object from the load call</li>
24977 * <li>success: Boolean success indicator</li></ul></li>
24978 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
24979 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
24982 load : function(options){
24983 options = options || {};
24984 if(this.fireEvent("beforeload", this, options) !== false){
24985 this.storeOptions(options);
24986 var p = Roo.apply(options.params || {}, this.baseParams);
24987 // if meta was not loaded from remote source.. try requesting it.
24988 if (!this.reader.metaFromRemote) {
24989 p._requestMeta = 1;
24991 if(this.sortInfo && this.remoteSort){
24992 var pn = this.paramNames;
24993 p[pn["sort"]] = this.sortInfo.field;
24994 p[pn["dir"]] = this.sortInfo.direction;
24996 if (this.multiSort) {
24997 var pn = this.paramNames;
24998 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
25001 this.proxy.load(p, this.reader, this.loadRecords, this, options);
25006 * Reloads the Record cache from the configured Proxy using the configured Reader and
25007 * the options from the last load operation performed.
25008 * @param {Object} options (optional) An object containing properties which may override the options
25009 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
25010 * the most recently used options are reused).
25012 reload : function(options){
25013 this.load(Roo.applyIf(options||{}, this.lastOptions));
25017 // Called as a callback by the Reader during a load operation.
25018 loadRecords : function(o, options, success){
25021 if(success !== false){
25022 this.fireEvent("load", this, [], options, o);
25024 if(options.callback){
25025 options.callback.call(options.scope || this, [], options, false);
25029 // if data returned failure - throw an exception.
25030 if (o.success === false) {
25031 // show a message if no listener is registered.
25032 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
25033 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
25035 // loadmask wil be hooked into this..
25036 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
25039 var r = o.records, t = o.totalRecords || r.length;
25041 this.fireEvent("beforeloadadd", this, r, options, o);
25043 if(!options || options.add !== true){
25044 if(this.pruneModifiedRecords){
25045 this.modified = [];
25047 for(var i = 0, len = r.length; i < len; i++){
25051 this.data = this.snapshot;
25052 delete this.snapshot;
25055 this.data.addAll(r);
25056 this.totalLength = t;
25058 this.fireEvent("datachanged", this);
25060 this.totalLength = Math.max(t, this.data.length+r.length);
25064 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
25066 var e = new Roo.data.Record({});
25068 e.set(this.parent.displayField, this.parent.emptyTitle);
25069 e.set(this.parent.valueField, '');
25074 this.fireEvent("load", this, r, options, o);
25075 if(options.callback){
25076 options.callback.call(options.scope || this, r, options, true);
25082 * Loads data from a passed data block. A Reader which understands the format of the data
25083 * must have been configured in the constructor.
25084 * @param {Object} data The data block from which to read the Records. The format of the data expected
25085 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
25086 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
25088 loadData : function(o, append){
25089 var r = this.reader.readRecords(o);
25090 this.loadRecords(r, {add: append}, true);
25094 * using 'cn' the nested child reader read the child array into it's child stores.
25095 * @param {Object} rec The record with a 'children array
25097 loadDataFromChildren : function(rec)
25099 this.loadData(this.reader.toLoadData(rec));
25104 * Gets the number of cached records.
25106 * <em>If using paging, this may not be the total size of the dataset. If the data object
25107 * used by the Reader contains the dataset size, then the getTotalCount() function returns
25108 * the data set size</em>
25110 getCount : function(){
25111 return this.data.length || 0;
25115 * Gets the total number of records in the dataset as returned by the server.
25117 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
25118 * the dataset size</em>
25120 getTotalCount : function(){
25121 return this.totalLength || 0;
25125 * Returns the sort state of the Store as an object with two properties:
25127 field {String} The name of the field by which the Records are sorted
25128 direction {String} The sort order, "ASC" or "DESC"
25131 getSortState : function(){
25132 return this.sortInfo;
25136 applySort : function(){
25137 if(this.sortInfo && !this.remoteSort){
25138 var s = this.sortInfo, f = s.field;
25139 var st = this.fields.get(f).sortType;
25140 var fn = function(r1, r2){
25141 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
25142 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
25144 this.data.sort(s.direction, fn);
25145 if(this.snapshot && this.snapshot != this.data){
25146 this.snapshot.sort(s.direction, fn);
25152 * Sets the default sort column and order to be used by the next load operation.
25153 * @param {String} fieldName The name of the field to sort by.
25154 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
25156 setDefaultSort : function(field, dir){
25157 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
25161 * Sort the Records.
25162 * If remote sorting is used, the sort is performed on the server, and the cache is
25163 * reloaded. If local sorting is used, the cache is sorted internally.
25164 * @param {String} fieldName The name of the field to sort by.
25165 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
25167 sort : function(fieldName, dir){
25168 var f = this.fields.get(fieldName);
25170 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
25172 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
25173 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
25178 this.sortToggle[f.name] = dir;
25179 this.sortInfo = {field: f.name, direction: dir};
25180 if(!this.remoteSort){
25182 this.fireEvent("datachanged", this);
25184 this.load(this.lastOptions);
25189 * Calls the specified function for each of the Records in the cache.
25190 * @param {Function} fn The function to call. The Record is passed as the first parameter.
25191 * Returning <em>false</em> aborts and exits the iteration.
25192 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
25194 each : function(fn, scope){
25195 this.data.each(fn, scope);
25199 * Gets all records modified since the last commit. Modified records are persisted across load operations
25200 * (e.g., during paging).
25201 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
25203 getModifiedRecords : function(){
25204 return this.modified;
25208 createFilterFn : function(property, value, anyMatch){
25209 if(!value.exec){ // not a regex
25210 value = String(value);
25211 if(value.length == 0){
25214 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
25216 return function(r){
25217 return value.test(r.data[property]);
25222 * Sums the value of <i>property</i> for each record between start and end and returns the result.
25223 * @param {String} property A field on your records
25224 * @param {Number} start The record index to start at (defaults to 0)
25225 * @param {Number} end The last record index to include (defaults to length - 1)
25226 * @return {Number} The sum
25228 sum : function(property, start, end){
25229 var rs = this.data.items, v = 0;
25230 start = start || 0;
25231 end = (end || end === 0) ? end : rs.length-1;
25233 for(var i = start; i <= end; i++){
25234 v += (rs[i].data[property] || 0);
25240 * Filter the records by a specified property.
25241 * @param {String} field A field on your records
25242 * @param {String/RegExp} value Either a string that the field
25243 * should start with or a RegExp to test against the field
25244 * @param {Boolean} anyMatch True to match any part not just the beginning
25246 filter : function(property, value, anyMatch){
25247 var fn = this.createFilterFn(property, value, anyMatch);
25248 return fn ? this.filterBy(fn) : this.clearFilter();
25252 * Filter by a function. The specified function will be called with each
25253 * record in this data source. If the function returns true the record is included,
25254 * otherwise it is filtered.
25255 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
25256 * @param {Object} scope (optional) The scope of the function (defaults to this)
25258 filterBy : function(fn, scope){
25259 this.snapshot = this.snapshot || this.data;
25260 this.data = this.queryBy(fn, scope||this);
25261 this.fireEvent("datachanged", this);
25265 * Query the records by a specified property.
25266 * @param {String} field A field on your records
25267 * @param {String/RegExp} value Either a string that the field
25268 * should start with or a RegExp to test against the field
25269 * @param {Boolean} anyMatch True to match any part not just the beginning
25270 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
25272 query : function(property, value, anyMatch){
25273 var fn = this.createFilterFn(property, value, anyMatch);
25274 return fn ? this.queryBy(fn) : this.data.clone();
25278 * Query by a function. The specified function will be called with each
25279 * record in this data source. If the function returns true the record is included
25281 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
25282 * @param {Object} scope (optional) The scope of the function (defaults to this)
25283 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
25285 queryBy : function(fn, scope){
25286 var data = this.snapshot || this.data;
25287 return data.filterBy(fn, scope||this);
25291 * Collects unique values for a particular dataIndex from this store.
25292 * @param {String} dataIndex The property to collect
25293 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
25294 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
25295 * @return {Array} An array of the unique values
25297 collect : function(dataIndex, allowNull, bypassFilter){
25298 var d = (bypassFilter === true && this.snapshot) ?
25299 this.snapshot.items : this.data.items;
25300 var v, sv, r = [], l = {};
25301 for(var i = 0, len = d.length; i < len; i++){
25302 v = d[i].data[dataIndex];
25304 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
25313 * Revert to a view of the Record cache with no filtering applied.
25314 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
25316 clearFilter : function(suppressEvent){
25317 if(this.snapshot && this.snapshot != this.data){
25318 this.data = this.snapshot;
25319 delete this.snapshot;
25320 if(suppressEvent !== true){
25321 this.fireEvent("datachanged", this);
25327 afterEdit : function(record){
25328 if(this.modified.indexOf(record) == -1){
25329 this.modified.push(record);
25331 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
25335 afterReject : function(record){
25336 this.modified.remove(record);
25337 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
25341 afterCommit : function(record){
25342 this.modified.remove(record);
25343 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
25347 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
25348 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
25350 commitChanges : function(){
25351 var m = this.modified.slice(0);
25352 this.modified = [];
25353 for(var i = 0, len = m.length; i < len; i++){
25359 * Cancel outstanding changes on all changed records.
25361 rejectChanges : function(){
25362 var m = this.modified.slice(0);
25363 this.modified = [];
25364 for(var i = 0, len = m.length; i < len; i++){
25369 onMetaChange : function(meta, rtype, o){
25370 this.recordType = rtype;
25371 this.fields = rtype.prototype.fields;
25372 delete this.snapshot;
25373 this.sortInfo = meta.sortInfo || this.sortInfo;
25374 this.modified = [];
25375 this.fireEvent('metachange', this, this.reader.meta);
25378 moveIndex : function(data, type)
25380 var index = this.indexOf(data);
25382 var newIndex = index + type;
25386 this.insert(newIndex, data);
25391 * Ext JS Library 1.1.1
25392 * Copyright(c) 2006-2007, Ext JS, LLC.
25394 * Originally Released Under LGPL - original licence link has changed is not relivant.
25397 * <script type="text/javascript">
25401 * @class Roo.data.SimpleStore
25402 * @extends Roo.data.Store
25403 * Small helper class to make creating Stores from Array data easier.
25404 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
25405 * @cfg {Array} fields An array of field definition objects, or field name strings.
25406 * @cfg {Object} an existing reader (eg. copied from another store)
25407 * @cfg {Array} data The multi-dimensional array of data
25408 * @cfg {Roo.data.DataProxy} proxy [not-required]
25409 * @cfg {Roo.data.Reader} reader [not-required]
25411 * @param {Object} config
25413 Roo.data.SimpleStore = function(config)
25415 Roo.data.SimpleStore.superclass.constructor.call(this, {
25417 reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
25420 Roo.data.Record.create(config.fields)
25422 proxy : new Roo.data.MemoryProxy(config.data)
25426 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
25428 * Ext JS Library 1.1.1
25429 * Copyright(c) 2006-2007, Ext JS, LLC.
25431 * Originally Released Under LGPL - original licence link has changed is not relivant.
25434 * <script type="text/javascript">
25439 * @extends Roo.data.Store
25440 * @class Roo.data.JsonStore
25441 * Small helper class to make creating Stores for JSON data easier. <br/>
25443 var store = new Roo.data.JsonStore({
25444 url: 'get-images.php',
25446 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
25449 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
25450 * JsonReader and HttpProxy (unless inline data is provided).</b>
25451 * @cfg {Array} fields An array of field definition objects, or field name strings.
25453 * @param {Object} config
25455 Roo.data.JsonStore = function(c){
25456 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
25457 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
25458 reader: new Roo.data.JsonReader(c, c.fields)
25461 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
25463 * Ext JS Library 1.1.1
25464 * Copyright(c) 2006-2007, Ext JS, LLC.
25466 * Originally Released Under LGPL - original licence link has changed is not relivant.
25469 * <script type="text/javascript">
25473 Roo.data.Field = function(config){
25474 if(typeof config == "string"){
25475 config = {name: config};
25477 Roo.apply(this, config);
25480 this.type = "auto";
25483 var st = Roo.data.SortTypes;
25484 // named sortTypes are supported, here we look them up
25485 if(typeof this.sortType == "string"){
25486 this.sortType = st[this.sortType];
25489 // set default sortType for strings and dates
25490 if(!this.sortType){
25493 this.sortType = st.asUCString;
25496 this.sortType = st.asDate;
25499 this.sortType = st.none;
25504 var stripRe = /[\$,%]/g;
25506 // prebuilt conversion function for this field, instead of
25507 // switching every time we're reading a value
25509 var cv, dateFormat = this.dateFormat;
25514 cv = function(v){ return v; };
25517 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
25521 return v !== undefined && v !== null && v !== '' ?
25522 parseInt(String(v).replace(stripRe, ""), 10) : '';
25527 return v !== undefined && v !== null && v !== '' ?
25528 parseFloat(String(v).replace(stripRe, ""), 10) : '';
25533 cv = function(v){ return v === true || v === "true" || v == 1; };
25540 if(v instanceof Date){
25544 if(dateFormat == "timestamp"){
25545 return new Date(v*1000);
25547 return Date.parseDate(v, dateFormat);
25549 var parsed = Date.parse(v);
25550 return parsed ? new Date(parsed) : null;
25559 Roo.data.Field.prototype = {
25567 * Ext JS Library 1.1.1
25568 * Copyright(c) 2006-2007, Ext JS, LLC.
25570 * Originally Released Under LGPL - original licence link has changed is not relivant.
25573 * <script type="text/javascript">
25576 // Base class for reading structured data from a data source. This class is intended to be
25577 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
25580 * @class Roo.data.DataReader
25582 * Base class for reading structured data from a data source. This class is intended to be
25583 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
25586 Roo.data.DataReader = function(meta, recordType){
25590 this.recordType = recordType instanceof Array ?
25591 Roo.data.Record.create(recordType) : recordType;
25594 Roo.data.DataReader.prototype = {
25597 readerType : 'Data',
25599 * Create an empty record
25600 * @param {Object} data (optional) - overlay some values
25601 * @return {Roo.data.Record} record created.
25603 newRow : function(d) {
25605 this.recordType.prototype.fields.each(function(c) {
25607 case 'int' : da[c.name] = 0; break;
25608 case 'date' : da[c.name] = new Date(); break;
25609 case 'float' : da[c.name] = 0.0; break;
25610 case 'boolean' : da[c.name] = false; break;
25611 default : da[c.name] = ""; break;
25615 return new this.recordType(Roo.apply(da, d));
25621 * Ext JS Library 1.1.1
25622 * Copyright(c) 2006-2007, Ext JS, LLC.
25624 * Originally Released Under LGPL - original licence link has changed is not relivant.
25627 * <script type="text/javascript">
25631 * @class Roo.data.DataProxy
25632 * @extends Roo.util.Observable
25634 * This class is an abstract base class for implementations which provide retrieval of
25635 * unformatted data objects.<br>
25637 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
25638 * (of the appropriate type which knows how to parse the data object) to provide a block of
25639 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
25641 * Custom implementations must implement the load method as described in
25642 * {@link Roo.data.HttpProxy#load}.
25644 Roo.data.DataProxy = function(){
25647 * @event beforeload
25648 * Fires before a network request is made to retrieve a data object.
25649 * @param {Object} This DataProxy object.
25650 * @param {Object} params The params parameter to the load function.
25655 * Fires before the load method's callback is called.
25656 * @param {Object} This DataProxy object.
25657 * @param {Object} o The data object.
25658 * @param {Object} arg The callback argument object passed to the load function.
25662 * @event loadexception
25663 * Fires if an Exception occurs during data retrieval.
25664 * @param {Object} This DataProxy object.
25665 * @param {Object} o The data object.
25666 * @param {Object} arg The callback argument object passed to the load function.
25667 * @param {Object} e The Exception.
25669 loadexception : true
25671 Roo.data.DataProxy.superclass.constructor.call(this);
25674 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
25677 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
25681 * Ext JS Library 1.1.1
25682 * Copyright(c) 2006-2007, Ext JS, LLC.
25684 * Originally Released Under LGPL - original licence link has changed is not relivant.
25687 * <script type="text/javascript">
25690 * @class Roo.data.MemoryProxy
25691 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
25692 * to the Reader when its load method is called.
25694 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
25696 Roo.data.MemoryProxy = function(data){
25700 Roo.data.MemoryProxy.superclass.constructor.call(this);
25704 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
25707 * Load data from the requested source (in this case an in-memory
25708 * data object passed to the constructor), read the data object into
25709 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
25710 * process that block using the passed callback.
25711 * @param {Object} params This parameter is not used by the MemoryProxy class.
25712 * @param {Roo.data.DataReader} reader The Reader object which converts the data
25713 * object into a block of Roo.data.Records.
25714 * @param {Function} callback The function into which to pass the block of Roo.data.records.
25715 * The function must be passed <ul>
25716 * <li>The Record block object</li>
25717 * <li>The "arg" argument from the load function</li>
25718 * <li>A boolean success indicator</li>
25720 * @param {Object} scope The scope in which to call the callback
25721 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
25723 load : function(params, reader, callback, scope, arg){
25724 params = params || {};
25727 result = reader.readRecords(params.data ? params.data :this.data);
25729 this.fireEvent("loadexception", this, arg, null, e);
25730 callback.call(scope, null, arg, false);
25733 callback.call(scope, result, arg, true);
25737 update : function(params, records){
25742 * Ext JS Library 1.1.1
25743 * Copyright(c) 2006-2007, Ext JS, LLC.
25745 * Originally Released Under LGPL - original licence link has changed is not relivant.
25748 * <script type="text/javascript">
25751 * @class Roo.data.HttpProxy
25752 * @extends Roo.data.DataProxy
25753 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
25754 * configured to reference a certain URL.<br><br>
25756 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
25757 * from which the running page was served.<br><br>
25759 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
25761 * Be aware that to enable the browser to parse an XML document, the server must set
25762 * the Content-Type header in the HTTP response to "text/xml".
25764 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
25765 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
25766 * will be used to make the request.
25768 Roo.data.HttpProxy = function(conn){
25769 Roo.data.HttpProxy.superclass.constructor.call(this);
25770 // is conn a conn config or a real conn?
25772 this.useAjax = !conn || !conn.events;
25776 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
25777 // thse are take from connection...
25780 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
25783 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
25784 * extra parameters to each request made by this object. (defaults to undefined)
25787 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
25788 * to each request made by this object. (defaults to undefined)
25791 * @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)
25794 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
25797 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
25803 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
25807 * Return the {@link Roo.data.Connection} object being used by this Proxy.
25808 * @return {Connection} The Connection object. This object may be used to subscribe to events on
25809 * a finer-grained basis than the DataProxy events.
25811 getConnection : function(){
25812 return this.useAjax ? Roo.Ajax : this.conn;
25816 * Load data from the configured {@link Roo.data.Connection}, read the data object into
25817 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
25818 * process that block using the passed callback.
25819 * @param {Object} params An object containing properties which are to be used as HTTP parameters
25820 * for the request to the remote server.
25821 * @param {Roo.data.DataReader} reader The Reader object which converts the data
25822 * object into a block of Roo.data.Records.
25823 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
25824 * The function must be passed <ul>
25825 * <li>The Record block object</li>
25826 * <li>The "arg" argument from the load function</li>
25827 * <li>A boolean success indicator</li>
25829 * @param {Object} scope The scope in which to call the callback
25830 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
25832 load : function(params, reader, callback, scope, arg){
25833 if(this.fireEvent("beforeload", this, params) !== false){
25835 params : params || {},
25837 callback : callback,
25842 callback : this.loadResponse,
25846 Roo.applyIf(o, this.conn);
25847 if(this.activeRequest){
25848 Roo.Ajax.abort(this.activeRequest);
25850 this.activeRequest = Roo.Ajax.request(o);
25852 this.conn.request(o);
25855 callback.call(scope||this, null, arg, false);
25860 loadResponse : function(o, success, response){
25861 delete this.activeRequest;
25863 this.fireEvent("loadexception", this, o, response);
25864 o.request.callback.call(o.request.scope, null, o.request.arg, false);
25869 result = o.reader.read(response);
25872 o.raw = { errorMsg : response.responseText };
25873 this.fireEvent("loadexception", this, o, response, e);
25874 o.request.callback.call(o.request.scope, o, o.request.arg, false);
25878 this.fireEvent("load", this, o, o.request.arg);
25879 o.request.callback.call(o.request.scope, result, o.request.arg, true);
25883 update : function(dataSet){
25888 updateResponse : function(dataSet){
25893 * Ext JS Library 1.1.1
25894 * Copyright(c) 2006-2007, Ext JS, LLC.
25896 * Originally Released Under LGPL - original licence link has changed is not relivant.
25899 * <script type="text/javascript">
25903 * @class Roo.data.ScriptTagProxy
25904 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
25905 * other than the originating domain of the running page.<br><br>
25907 * <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
25908 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
25910 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
25911 * source code that is used as the source inside a <script> tag.<br><br>
25913 * In order for the browser to process the returned data, the server must wrap the data object
25914 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
25915 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
25916 * depending on whether the callback name was passed:
25919 boolean scriptTag = false;
25920 String cb = request.getParameter("callback");
25923 response.setContentType("text/javascript");
25925 response.setContentType("application/x-json");
25927 Writer out = response.getWriter();
25929 out.write(cb + "(");
25931 out.print(dataBlock.toJsonString());
25938 * @param {Object} config A configuration object.
25940 Roo.data.ScriptTagProxy = function(config){
25941 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
25942 Roo.apply(this, config);
25943 this.head = document.getElementsByTagName("head")[0];
25946 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
25948 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
25950 * @cfg {String} url The URL from which to request the data object.
25953 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
25957 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
25958 * the server the name of the callback function set up by the load call to process the returned data object.
25959 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
25960 * javascript output which calls this named function passing the data object as its only parameter.
25962 callbackParam : "callback",
25964 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
25965 * name to the request.
25970 * Load data from the configured URL, read the data object into
25971 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
25972 * process that block using the passed callback.
25973 * @param {Object} params An object containing properties which are to be used as HTTP parameters
25974 * for the request to the remote server.
25975 * @param {Roo.data.DataReader} reader The Reader object which converts the data
25976 * object into a block of Roo.data.Records.
25977 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
25978 * The function must be passed <ul>
25979 * <li>The Record block object</li>
25980 * <li>The "arg" argument from the load function</li>
25981 * <li>A boolean success indicator</li>
25983 * @param {Object} scope The scope in which to call the callback
25984 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
25986 load : function(params, reader, callback, scope, arg){
25987 if(this.fireEvent("beforeload", this, params) !== false){
25989 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
25991 var url = this.url;
25992 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
25994 url += "&_dc=" + (new Date().getTime());
25996 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
25999 cb : "stcCallback"+transId,
26000 scriptId : "stcScript"+transId,
26004 callback : callback,
26010 window[trans.cb] = function(o){
26011 conn.handleResponse(o, trans);
26014 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
26016 if(this.autoAbort !== false){
26020 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
26022 var script = document.createElement("script");
26023 script.setAttribute("src", url);
26024 script.setAttribute("type", "text/javascript");
26025 script.setAttribute("id", trans.scriptId);
26026 this.head.appendChild(script);
26028 this.trans = trans;
26030 callback.call(scope||this, null, arg, false);
26035 isLoading : function(){
26036 return this.trans ? true : false;
26040 * Abort the current server request.
26042 abort : function(){
26043 if(this.isLoading()){
26044 this.destroyTrans(this.trans);
26049 destroyTrans : function(trans, isLoaded){
26050 this.head.removeChild(document.getElementById(trans.scriptId));
26051 clearTimeout(trans.timeoutId);
26053 window[trans.cb] = undefined;
26055 delete window[trans.cb];
26058 // if hasn't been loaded, wait for load to remove it to prevent script error
26059 window[trans.cb] = function(){
26060 window[trans.cb] = undefined;
26062 delete window[trans.cb];
26069 handleResponse : function(o, trans){
26070 this.trans = false;
26071 this.destroyTrans(trans, true);
26074 result = trans.reader.readRecords(o);
26076 this.fireEvent("loadexception", this, o, trans.arg, e);
26077 trans.callback.call(trans.scope||window, null, trans.arg, false);
26080 this.fireEvent("load", this, o, trans.arg);
26081 trans.callback.call(trans.scope||window, result, trans.arg, true);
26085 handleFailure : function(trans){
26086 this.trans = false;
26087 this.destroyTrans(trans, false);
26088 this.fireEvent("loadexception", this, null, trans.arg);
26089 trans.callback.call(trans.scope||window, null, trans.arg, false);
26093 * Ext JS Library 1.1.1
26094 * Copyright(c) 2006-2007, Ext JS, LLC.
26096 * Originally Released Under LGPL - original licence link has changed is not relivant.
26099 * <script type="text/javascript">
26103 * @class Roo.data.JsonReader
26104 * @extends Roo.data.DataReader
26105 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
26106 * based on mappings in a provided Roo.data.Record constructor.
26108 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
26109 * in the reply previously.
26114 var RecordDef = Roo.data.Record.create([
26115 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
26116 {name: 'occupation'} // This field will use "occupation" as the mapping.
26118 var myReader = new Roo.data.JsonReader({
26119 totalProperty: "results", // The property which contains the total dataset size (optional)
26120 root: "rows", // The property which contains an Array of row objects
26121 id: "id" // The property within each row object that provides an ID for the record (optional)
26125 * This would consume a JSON file like this:
26127 { 'results': 2, 'rows': [
26128 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
26129 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
26132 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
26133 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
26134 * paged from the remote server.
26135 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
26136 * @cfg {String} root name of the property which contains the Array of row objects.
26137 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
26138 * @cfg {Array} fields Array of field definition objects
26140 * Create a new JsonReader
26141 * @param {Object} meta Metadata configuration options
26142 * @param {Object} recordType Either an Array of field definition objects,
26143 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
26145 Roo.data.JsonReader = function(meta, recordType){
26148 // set some defaults:
26149 Roo.applyIf(meta, {
26150 totalProperty: 'total',
26151 successProperty : 'success',
26156 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
26158 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
26160 readerType : 'Json',
26163 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
26164 * Used by Store query builder to append _requestMeta to params.
26167 metaFromRemote : false,
26169 * This method is only used by a DataProxy which has retrieved data from a remote server.
26170 * @param {Object} response The XHR object which contains the JSON data in its responseText.
26171 * @return {Object} data A data block which is used by an Roo.data.Store object as
26172 * a cache of Roo.data.Records.
26174 read : function(response){
26175 var json = response.responseText;
26177 var o = /* eval:var:o */ eval("("+json+")");
26179 throw {message: "JsonReader.read: Json object not found"};
26185 this.metaFromRemote = true;
26186 this.meta = o.metaData;
26187 this.recordType = Roo.data.Record.create(o.metaData.fields);
26188 this.onMetaChange(this.meta, this.recordType, o);
26190 return this.readRecords(o);
26193 // private function a store will implement
26194 onMetaChange : function(meta, recordType, o){
26201 simpleAccess: function(obj, subsc) {
26208 getJsonAccessor: function(){
26210 return function(expr) {
26212 return(re.test(expr))
26213 ? new Function("obj", "return obj." + expr)
26218 return Roo.emptyFn;
26223 * Create a data block containing Roo.data.Records from an XML document.
26224 * @param {Object} o An object which contains an Array of row objects in the property specified
26225 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
26226 * which contains the total size of the dataset.
26227 * @return {Object} data A data block which is used by an Roo.data.Store object as
26228 * a cache of Roo.data.Records.
26230 readRecords : function(o){
26232 * After any data loads, the raw JSON data is available for further custom processing.
26236 var s = this.meta, Record = this.recordType,
26237 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
26239 // Generate extraction functions for the totalProperty, the root, the id, and for each field
26241 if(s.totalProperty) {
26242 this.getTotal = this.getJsonAccessor(s.totalProperty);
26244 if(s.successProperty) {
26245 this.getSuccess = this.getJsonAccessor(s.successProperty);
26247 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
26249 var g = this.getJsonAccessor(s.id);
26250 this.getId = function(rec) {
26252 return (r === undefined || r === "") ? null : r;
26255 this.getId = function(){return null;};
26258 for(var jj = 0; jj < fl; jj++){
26260 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
26261 this.ef[jj] = this.getJsonAccessor(map);
26265 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
26266 if(s.totalProperty){
26267 var vt = parseInt(this.getTotal(o), 10);
26272 if(s.successProperty){
26273 var vs = this.getSuccess(o);
26274 if(vs === false || vs === 'false'){
26279 for(var i = 0; i < c; i++){
26282 var id = this.getId(n);
26283 for(var j = 0; j < fl; j++){
26285 var v = this.ef[j](n);
26287 Roo.log('missing convert for ' + f.name);
26291 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
26295 raw : { errorMsg : "JSON Reader Error: fields or metadata not available to create Record" },
26301 var record = new Record(values, id);
26303 records[i] = record;
26309 totalRecords : totalRecords
26312 // used when loading children.. @see loadDataFromChildren
26313 toLoadData: function(rec)
26315 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
26316 var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
26317 return { data : data, total : data.length };
26322 * Ext JS Library 1.1.1
26323 * Copyright(c) 2006-2007, Ext JS, LLC.
26325 * Originally Released Under LGPL - original licence link has changed is not relivant.
26328 * <script type="text/javascript">
26332 * @class Roo.data.XmlReader
26333 * @extends Roo.data.DataReader
26334 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
26335 * based on mappings in a provided Roo.data.Record constructor.<br><br>
26337 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
26338 * header in the HTTP response must be set to "text/xml".</em>
26342 var RecordDef = Roo.data.Record.create([
26343 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
26344 {name: 'occupation'} // This field will use "occupation" as the mapping.
26346 var myReader = new Roo.data.XmlReader({
26347 totalRecords: "results", // The element which contains the total dataset size (optional)
26348 record: "row", // The repeated element which contains row information
26349 id: "id" // The element within the row that provides an ID for the record (optional)
26353 * This would consume an XML file like this:
26357 <results>2</results>
26360 <name>Bill</name>
26361 <occupation>Gardener</occupation>
26365 <name>Ben</name>
26366 <occupation>Horticulturalist</occupation>
26370 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
26371 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
26372 * paged from the remote server.
26373 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
26374 * @cfg {String} success The DomQuery path to the success attribute used by forms.
26375 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
26376 * a record identifier value.
26378 * Create a new XmlReader
26379 * @param {Object} meta Metadata configuration options
26380 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
26381 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
26382 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
26384 Roo.data.XmlReader = function(meta, recordType){
26386 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
26388 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
26390 readerType : 'Xml',
26393 * This method is only used by a DataProxy which has retrieved data from a remote server.
26394 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
26395 * to contain a method called 'responseXML' that returns an XML document object.
26396 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
26397 * a cache of Roo.data.Records.
26399 read : function(response){
26400 var doc = response.responseXML;
26402 throw {message: "XmlReader.read: XML Document not available"};
26404 return this.readRecords(doc);
26408 * Create a data block containing Roo.data.Records from an XML document.
26409 * @param {Object} doc A parsed XML document.
26410 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
26411 * a cache of Roo.data.Records.
26413 readRecords : function(doc){
26415 * After any data loads/reads, the raw XML Document is available for further custom processing.
26416 * @type XMLDocument
26418 this.xmlData = doc;
26419 var root = doc.documentElement || doc;
26420 var q = Roo.DomQuery;
26421 var recordType = this.recordType, fields = recordType.prototype.fields;
26422 var sid = this.meta.id;
26423 var totalRecords = 0, success = true;
26424 if(this.meta.totalRecords){
26425 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
26428 if(this.meta.success){
26429 var sv = q.selectValue(this.meta.success, root, true);
26430 success = sv !== false && sv !== 'false';
26433 var ns = q.select(this.meta.record, root);
26434 for(var i = 0, len = ns.length; i < len; i++) {
26437 var id = sid ? q.selectValue(sid, n) : undefined;
26438 for(var j = 0, jlen = fields.length; j < jlen; j++){
26439 var f = fields.items[j];
26440 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
26442 values[f.name] = v;
26444 var record = new recordType(values, id);
26446 records[records.length] = record;
26452 totalRecords : totalRecords || records.length
26457 * Ext JS Library 1.1.1
26458 * Copyright(c) 2006-2007, Ext JS, LLC.
26460 * Originally Released Under LGPL - original licence link has changed is not relivant.
26463 * <script type="text/javascript">
26467 * @class Roo.data.ArrayReader
26468 * @extends Roo.data.DataReader
26469 * Data reader class to create an Array of Roo.data.Record objects from an Array.
26470 * Each element of that Array represents a row of data fields. The
26471 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
26472 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
26476 var RecordDef = Roo.data.Record.create([
26477 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
26478 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
26480 var myReader = new Roo.data.ArrayReader({
26481 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
26485 * This would consume an Array like this:
26487 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
26491 * Create a new JsonReader
26492 * @param {Object} meta Metadata configuration options.
26493 * @param {Object|Array} recordType Either an Array of field definition objects
26495 * @cfg {Array} fields Array of field definition objects
26496 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
26497 * as specified to {@link Roo.data.Record#create},
26498 * or an {@link Roo.data.Record} object
26501 * created using {@link Roo.data.Record#create}.
26503 Roo.data.ArrayReader = function(meta, recordType)
26505 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
26508 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
26511 * Create a data block containing Roo.data.Records from an XML document.
26512 * @param {Object} o An Array of row objects which represents the dataset.
26513 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
26514 * a cache of Roo.data.Records.
26516 readRecords : function(o)
26518 var sid = this.meta ? this.meta.id : null;
26519 var recordType = this.recordType, fields = recordType.prototype.fields;
26522 for(var i = 0; i < root.length; i++){
26525 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
26526 for(var j = 0, jlen = fields.length; j < jlen; j++){
26527 var f = fields.items[j];
26528 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
26529 var v = n[k] !== undefined ? n[k] : f.defaultValue;
26531 values[f.name] = v;
26533 var record = new recordType(values, id);
26535 records[records.length] = record;
26539 totalRecords : records.length
26542 // used when loading children.. @see loadDataFromChildren
26543 toLoadData: function(rec)
26545 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
26546 return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
26553 * Ext JS Library 1.1.1
26554 * Copyright(c) 2006-2007, Ext JS, LLC.
26556 * Originally Released Under LGPL - original licence link has changed is not relivant.
26559 * <script type="text/javascript">
26564 * @class Roo.data.Tree
26565 * @extends Roo.util.Observable
26566 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
26567 * in the tree have most standard DOM functionality.
26569 * @param {Node} root (optional) The root node
26571 Roo.data.Tree = function(root){
26572 this.nodeHash = {};
26574 * The root node for this tree
26579 this.setRootNode(root);
26584 * Fires when a new child node is appended to a node in this tree.
26585 * @param {Tree} tree The owner tree
26586 * @param {Node} parent The parent node
26587 * @param {Node} node The newly appended node
26588 * @param {Number} index The index of the newly appended node
26593 * Fires when a child node is removed from a node in this tree.
26594 * @param {Tree} tree The owner tree
26595 * @param {Node} parent The parent node
26596 * @param {Node} node The child node removed
26601 * Fires when a node is moved to a new location in the tree
26602 * @param {Tree} tree The owner tree
26603 * @param {Node} node The node moved
26604 * @param {Node} oldParent The old parent of this node
26605 * @param {Node} newParent The new parent of this node
26606 * @param {Number} index The index it was moved to
26611 * Fires when a new child node is inserted in a node in this tree.
26612 * @param {Tree} tree The owner tree
26613 * @param {Node} parent The parent node
26614 * @param {Node} node The child node inserted
26615 * @param {Node} refNode The child node the node was inserted before
26619 * @event beforeappend
26620 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
26621 * @param {Tree} tree The owner tree
26622 * @param {Node} parent The parent node
26623 * @param {Node} node The child node to be appended
26625 "beforeappend" : true,
26627 * @event beforeremove
26628 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
26629 * @param {Tree} tree The owner tree
26630 * @param {Node} parent The parent node
26631 * @param {Node} node The child node to be removed
26633 "beforeremove" : true,
26635 * @event beforemove
26636 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
26637 * @param {Tree} tree The owner tree
26638 * @param {Node} node The node being moved
26639 * @param {Node} oldParent The parent of the node
26640 * @param {Node} newParent The new parent the node is moving to
26641 * @param {Number} index The index it is being moved to
26643 "beforemove" : true,
26645 * @event beforeinsert
26646 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
26647 * @param {Tree} tree The owner tree
26648 * @param {Node} parent The parent node
26649 * @param {Node} node The child node to be inserted
26650 * @param {Node} refNode The child node the node is being inserted before
26652 "beforeinsert" : true
26655 Roo.data.Tree.superclass.constructor.call(this);
26658 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
26659 pathSeparator: "/",
26661 proxyNodeEvent : function(){
26662 return this.fireEvent.apply(this, arguments);
26666 * Returns the root node for this tree.
26669 getRootNode : function(){
26674 * Sets the root node for this tree.
26675 * @param {Node} node
26678 setRootNode : function(node){
26680 node.ownerTree = this;
26681 node.isRoot = true;
26682 this.registerNode(node);
26687 * Gets a node in this tree by its id.
26688 * @param {String} id
26691 getNodeById : function(id){
26692 return this.nodeHash[id];
26695 registerNode : function(node){
26696 this.nodeHash[node.id] = node;
26699 unregisterNode : function(node){
26700 delete this.nodeHash[node.id];
26703 toString : function(){
26704 return "[Tree"+(this.id?" "+this.id:"")+"]";
26709 * @class Roo.data.Node
26710 * @extends Roo.util.Observable
26711 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
26712 * @cfg {String} id The id for this node. If one is not specified, one is generated.
26714 * @param {Object} attributes The attributes/config for the node
26716 Roo.data.Node = function(attributes){
26718 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
26721 this.attributes = attributes || {};
26722 this.leaf = this.attributes.leaf;
26724 * The node id. @type String
26726 this.id = this.attributes.id;
26728 this.id = Roo.id(null, "ynode-");
26729 this.attributes.id = this.id;
26734 * All child nodes of this node. @type Array
26736 this.childNodes = [];
26737 if(!this.childNodes.indexOf){ // indexOf is a must
26738 this.childNodes.indexOf = function(o){
26739 for(var i = 0, len = this.length; i < len; i++){
26748 * The parent node for this node. @type Node
26750 this.parentNode = null;
26752 * The first direct child node of this node, or null if this node has no child nodes. @type Node
26754 this.firstChild = null;
26756 * The last direct child node of this node, or null if this node has no child nodes. @type Node
26758 this.lastChild = null;
26760 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
26762 this.previousSibling = null;
26764 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
26766 this.nextSibling = null;
26771 * Fires when a new child node is appended
26772 * @param {Tree} tree The owner tree
26773 * @param {Node} this This node
26774 * @param {Node} node The newly appended node
26775 * @param {Number} index The index of the newly appended node
26780 * Fires when a child node is removed
26781 * @param {Tree} tree The owner tree
26782 * @param {Node} this This node
26783 * @param {Node} node The removed node
26788 * Fires when this node is moved to a new location in the tree
26789 * @param {Tree} tree The owner tree
26790 * @param {Node} this This node
26791 * @param {Node} oldParent The old parent of this node
26792 * @param {Node} newParent The new parent of this node
26793 * @param {Number} index The index it was moved to
26798 * Fires when a new child node is inserted.
26799 * @param {Tree} tree The owner tree
26800 * @param {Node} this This node
26801 * @param {Node} node The child node inserted
26802 * @param {Node} refNode The child node the node was inserted before
26806 * @event beforeappend
26807 * Fires before a new child is appended, return false to cancel the append.
26808 * @param {Tree} tree The owner tree
26809 * @param {Node} this This node
26810 * @param {Node} node The child node to be appended
26812 "beforeappend" : true,
26814 * @event beforeremove
26815 * Fires before a child is removed, return false to cancel the remove.
26816 * @param {Tree} tree The owner tree
26817 * @param {Node} this This node
26818 * @param {Node} node The child node to be removed
26820 "beforeremove" : true,
26822 * @event beforemove
26823 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
26824 * @param {Tree} tree The owner tree
26825 * @param {Node} this This node
26826 * @param {Node} oldParent The parent of this node
26827 * @param {Node} newParent The new parent this node is moving to
26828 * @param {Number} index The index it is being moved to
26830 "beforemove" : true,
26832 * @event beforeinsert
26833 * Fires before a new child is inserted, return false to cancel the insert.
26834 * @param {Tree} tree The owner tree
26835 * @param {Node} this This node
26836 * @param {Node} node The child node to be inserted
26837 * @param {Node} refNode The child node the node is being inserted before
26839 "beforeinsert" : true
26841 this.listeners = this.attributes.listeners;
26842 Roo.data.Node.superclass.constructor.call(this);
26845 Roo.extend(Roo.data.Node, Roo.util.Observable, {
26846 fireEvent : function(evtName){
26847 // first do standard event for this node
26848 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
26851 // then bubble it up to the tree if the event wasn't cancelled
26852 var ot = this.getOwnerTree();
26854 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
26862 * Returns true if this node is a leaf
26863 * @return {Boolean}
26865 isLeaf : function(){
26866 return this.leaf === true;
26870 setFirstChild : function(node){
26871 this.firstChild = node;
26875 setLastChild : function(node){
26876 this.lastChild = node;
26881 * Returns true if this node is the last child of its parent
26882 * @return {Boolean}
26884 isLast : function(){
26885 return (!this.parentNode ? true : this.parentNode.lastChild == this);
26889 * Returns true if this node is the first child of its parent
26890 * @return {Boolean}
26892 isFirst : function(){
26893 return (!this.parentNode ? true : this.parentNode.firstChild == this);
26896 hasChildNodes : function(){
26897 return !this.isLeaf() && this.childNodes.length > 0;
26901 * Insert node(s) as the last child node of this node.
26902 * @param {Node/Array} node The node or Array of nodes to append
26903 * @return {Node} The appended node if single append, or null if an array was passed
26905 appendChild : function(node){
26907 if(node instanceof Array){
26909 }else if(arguments.length > 1){
26913 // if passed an array or multiple args do them one by one
26915 for(var i = 0, len = multi.length; i < len; i++) {
26916 this.appendChild(multi[i]);
26919 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
26922 var index = this.childNodes.length;
26923 var oldParent = node.parentNode;
26924 // it's a move, make sure we move it cleanly
26926 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
26929 oldParent.removeChild(node);
26932 index = this.childNodes.length;
26934 this.setFirstChild(node);
26936 this.childNodes.push(node);
26937 node.parentNode = this;
26938 var ps = this.childNodes[index-1];
26940 node.previousSibling = ps;
26941 ps.nextSibling = node;
26943 node.previousSibling = null;
26945 node.nextSibling = null;
26946 this.setLastChild(node);
26947 node.setOwnerTree(this.getOwnerTree());
26948 this.fireEvent("append", this.ownerTree, this, node, index);
26949 if(this.ownerTree) {
26950 this.ownerTree.fireEvent("appendnode", this, node, index);
26953 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
26960 * Removes a child node from this node.
26961 * @param {Node} node The node to remove
26962 * @return {Node} The removed node
26964 removeChild : function(node){
26965 var index = this.childNodes.indexOf(node);
26969 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
26973 // remove it from childNodes collection
26974 this.childNodes.splice(index, 1);
26977 if(node.previousSibling){
26978 node.previousSibling.nextSibling = node.nextSibling;
26980 if(node.nextSibling){
26981 node.nextSibling.previousSibling = node.previousSibling;
26984 // update child refs
26985 if(this.firstChild == node){
26986 this.setFirstChild(node.nextSibling);
26988 if(this.lastChild == node){
26989 this.setLastChild(node.previousSibling);
26992 node.setOwnerTree(null);
26993 // clear any references from the node
26994 node.parentNode = null;
26995 node.previousSibling = null;
26996 node.nextSibling = null;
26997 this.fireEvent("remove", this.ownerTree, this, node);
27002 * Inserts the first node before the second node in this nodes childNodes collection.
27003 * @param {Node} node The node to insert
27004 * @param {Node} refNode The node to insert before (if null the node is appended)
27005 * @return {Node} The inserted node
27007 insertBefore : function(node, refNode){
27008 if(!refNode){ // like standard Dom, refNode can be null for append
27009 return this.appendChild(node);
27012 if(node == refNode){
27016 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
27019 var index = this.childNodes.indexOf(refNode);
27020 var oldParent = node.parentNode;
27021 var refIndex = index;
27023 // when moving internally, indexes will change after remove
27024 if(oldParent == this && this.childNodes.indexOf(node) < index){
27028 // it's a move, make sure we move it cleanly
27030 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
27033 oldParent.removeChild(node);
27036 this.setFirstChild(node);
27038 this.childNodes.splice(refIndex, 0, node);
27039 node.parentNode = this;
27040 var ps = this.childNodes[refIndex-1];
27042 node.previousSibling = ps;
27043 ps.nextSibling = node;
27045 node.previousSibling = null;
27047 node.nextSibling = refNode;
27048 refNode.previousSibling = node;
27049 node.setOwnerTree(this.getOwnerTree());
27050 this.fireEvent("insert", this.ownerTree, this, node, refNode);
27052 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
27058 * Returns the child node at the specified index.
27059 * @param {Number} index
27062 item : function(index){
27063 return this.childNodes[index];
27067 * Replaces one child node in this node with another.
27068 * @param {Node} newChild The replacement node
27069 * @param {Node} oldChild The node to replace
27070 * @return {Node} The replaced node
27072 replaceChild : function(newChild, oldChild){
27073 this.insertBefore(newChild, oldChild);
27074 this.removeChild(oldChild);
27079 * Returns the index of a child node
27080 * @param {Node} node
27081 * @return {Number} The index of the node or -1 if it was not found
27083 indexOf : function(child){
27084 return this.childNodes.indexOf(child);
27088 * Returns the tree this node is in.
27091 getOwnerTree : function(){
27092 // if it doesn't have one, look for one
27093 if(!this.ownerTree){
27097 this.ownerTree = p.ownerTree;
27103 return this.ownerTree;
27107 * Returns depth of this node (the root node has a depth of 0)
27110 getDepth : function(){
27113 while(p.parentNode){
27121 setOwnerTree : function(tree){
27122 // if it's move, we need to update everyone
27123 if(tree != this.ownerTree){
27124 if(this.ownerTree){
27125 this.ownerTree.unregisterNode(this);
27127 this.ownerTree = tree;
27128 var cs = this.childNodes;
27129 for(var i = 0, len = cs.length; i < len; i++) {
27130 cs[i].setOwnerTree(tree);
27133 tree.registerNode(this);
27139 * Returns the path for this node. The path can be used to expand or select this node programmatically.
27140 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
27141 * @return {String} The path
27143 getPath : function(attr){
27144 attr = attr || "id";
27145 var p = this.parentNode;
27146 var b = [this.attributes[attr]];
27148 b.unshift(p.attributes[attr]);
27151 var sep = this.getOwnerTree().pathSeparator;
27152 return sep + b.join(sep);
27156 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
27157 * function call will be the scope provided or the current node. The arguments to the function
27158 * will be the args provided or the current node. If the function returns false at any point,
27159 * the bubble is stopped.
27160 * @param {Function} fn The function to call
27161 * @param {Object} scope (optional) The scope of the function (defaults to current node)
27162 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
27164 bubble : function(fn, scope, args){
27167 if(fn.call(scope || p, args || p) === false){
27175 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
27176 * function call will be the scope provided or the current node. The arguments to the function
27177 * will be the args provided or the current node. If the function returns false at any point,
27178 * the cascade is stopped on that branch.
27179 * @param {Function} fn The function to call
27180 * @param {Object} scope (optional) The scope of the function (defaults to current node)
27181 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
27183 cascade : function(fn, scope, args){
27184 if(fn.call(scope || this, args || this) !== false){
27185 var cs = this.childNodes;
27186 for(var i = 0, len = cs.length; i < len; i++) {
27187 cs[i].cascade(fn, scope, args);
27193 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
27194 * function call will be the scope provided or the current node. The arguments to the function
27195 * will be the args provided or the current node. If the function returns false at any point,
27196 * the iteration stops.
27197 * @param {Function} fn The function to call
27198 * @param {Object} scope (optional) The scope of the function (defaults to current node)
27199 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
27201 eachChild : function(fn, scope, args){
27202 var cs = this.childNodes;
27203 for(var i = 0, len = cs.length; i < len; i++) {
27204 if(fn.call(scope || this, args || cs[i]) === false){
27211 * Finds the first child that has the attribute with the specified value.
27212 * @param {String} attribute The attribute name
27213 * @param {Mixed} value The value to search for
27214 * @return {Node} The found child or null if none was found
27216 findChild : function(attribute, value){
27217 var cs = this.childNodes;
27218 for(var i = 0, len = cs.length; i < len; i++) {
27219 if(cs[i].attributes[attribute] == value){
27227 * Finds the first child by a custom function. The child matches if the function passed
27229 * @param {Function} fn
27230 * @param {Object} scope (optional)
27231 * @return {Node} The found child or null if none was found
27233 findChildBy : function(fn, scope){
27234 var cs = this.childNodes;
27235 for(var i = 0, len = cs.length; i < len; i++) {
27236 if(fn.call(scope||cs[i], cs[i]) === true){
27244 * Sorts this nodes children using the supplied sort function
27245 * @param {Function} fn
27246 * @param {Object} scope (optional)
27248 sort : function(fn, scope){
27249 var cs = this.childNodes;
27250 var len = cs.length;
27252 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
27254 for(var i = 0; i < len; i++){
27256 n.previousSibling = cs[i-1];
27257 n.nextSibling = cs[i+1];
27259 this.setFirstChild(n);
27262 this.setLastChild(n);
27269 * Returns true if this node is an ancestor (at any point) of the passed node.
27270 * @param {Node} node
27271 * @return {Boolean}
27273 contains : function(node){
27274 return node.isAncestor(this);
27278 * Returns true if the passed node is an ancestor (at any point) of this node.
27279 * @param {Node} node
27280 * @return {Boolean}
27282 isAncestor : function(node){
27283 var p = this.parentNode;
27293 toString : function(){
27294 return "[Node"+(this.id?" "+this.id:"")+"]";
27298 * Ext JS Library 1.1.1
27299 * Copyright(c) 2006-2007, Ext JS, LLC.
27301 * Originally Released Under LGPL - original licence link has changed is not relivant.
27304 * <script type="text/javascript">
27309 * @class Roo.Shadow
27310 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
27311 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
27312 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
27314 * Create a new Shadow
27315 * @param {Object} config The config object
27317 Roo.Shadow = function(config){
27318 Roo.apply(this, config);
27319 if(typeof this.mode != "string"){
27320 this.mode = this.defaultMode;
27322 var o = this.offset, a = {h: 0};
27323 var rad = Math.floor(this.offset/2);
27324 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
27330 a.l -= this.offset + rad;
27331 a.t -= this.offset + rad;
27342 a.l -= (this.offset - rad);
27343 a.t -= this.offset + rad;
27345 a.w -= (this.offset - rad)*2;
27356 a.l -= (this.offset - rad);
27357 a.t -= (this.offset - rad);
27359 a.w -= (this.offset + rad + 1);
27360 a.h -= (this.offset + rad);
27369 Roo.Shadow.prototype = {
27371 * @cfg {String} mode
27372 * The shadow display mode. Supports the following options:<br />
27373 * sides: Shadow displays on both sides and bottom only<br />
27374 * frame: Shadow displays equally on all four sides<br />
27375 * drop: Traditional bottom-right drop shadow (default)
27379 * @cfg {String} offset
27380 * The number of pixels to offset the shadow from the element (defaults to 4)
27385 defaultMode: "drop",
27388 * Displays the shadow under the target element
27389 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
27391 show : function(target){
27392 target = Roo.get(target);
27394 this.el = Roo.Shadow.Pool.pull();
27395 if(this.el.dom.nextSibling != target.dom){
27396 this.el.insertBefore(target);
27399 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
27401 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
27404 target.getLeft(true),
27405 target.getTop(true),
27409 this.el.dom.style.display = "block";
27413 * Returns true if the shadow is visible, else false
27415 isVisible : function(){
27416 return this.el ? true : false;
27420 * Direct alignment when values are already available. Show must be called at least once before
27421 * calling this method to ensure it is initialized.
27422 * @param {Number} left The target element left position
27423 * @param {Number} top The target element top position
27424 * @param {Number} width The target element width
27425 * @param {Number} height The target element height
27427 realign : function(l, t, w, h){
27431 var a = this.adjusts, d = this.el.dom, s = d.style;
27433 s.left = (l+a.l)+"px";
27434 s.top = (t+a.t)+"px";
27435 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
27437 if(s.width != sws || s.height != shs){
27441 var cn = d.childNodes;
27442 var sww = Math.max(0, (sw-12))+"px";
27443 cn[0].childNodes[1].style.width = sww;
27444 cn[1].childNodes[1].style.width = sww;
27445 cn[2].childNodes[1].style.width = sww;
27446 cn[1].style.height = Math.max(0, (sh-12))+"px";
27452 * Hides this shadow
27456 this.el.dom.style.display = "none";
27457 Roo.Shadow.Pool.push(this.el);
27463 * Adjust the z-index of this shadow
27464 * @param {Number} zindex The new z-index
27466 setZIndex : function(z){
27469 this.el.setStyle("z-index", z);
27474 // Private utility class that manages the internal Shadow cache
27475 Roo.Shadow.Pool = function(){
27477 var markup = Roo.isIE ?
27478 '<div class="x-ie-shadow"></div>' :
27479 '<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>';
27482 var sh = p.shift();
27484 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
27485 sh.autoBoxAdjust = false;
27490 push : function(sh){
27496 * Ext JS Library 1.1.1
27497 * Copyright(c) 2006-2007, Ext JS, LLC.
27499 * Originally Released Under LGPL - original licence link has changed is not relivant.
27502 * <script type="text/javascript">
27507 * @class Roo.SplitBar
27508 * @extends Roo.util.Observable
27509 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
27513 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
27514 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
27515 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
27516 split.minSize = 100;
27517 split.maxSize = 600;
27518 split.animate = true;
27519 split.on('moved', splitterMoved);
27522 * Create a new SplitBar
27523 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
27524 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
27525 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
27526 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
27527 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
27528 position of the SplitBar).
27530 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
27533 this.el = Roo.get(dragElement, true);
27534 this.el.dom.unselectable = "on";
27536 this.resizingEl = Roo.get(resizingElement, true);
27540 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
27541 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
27544 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
27547 * The minimum size of the resizing element. (Defaults to 0)
27553 * The maximum size of the resizing element. (Defaults to 2000)
27556 this.maxSize = 2000;
27559 * Whether to animate the transition to the new size
27562 this.animate = false;
27565 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
27568 this.useShim = false;
27573 if(!existingProxy){
27575 this.proxy = Roo.SplitBar.createProxy(this.orientation);
27577 this.proxy = Roo.get(existingProxy).dom;
27580 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
27583 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
27586 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
27589 this.dragSpecs = {};
27592 * @private The adapter to use to positon and resize elements
27594 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
27595 this.adapter.init(this);
27597 if(this.orientation == Roo.SplitBar.HORIZONTAL){
27599 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
27600 this.el.addClass("x-splitbar-h");
27603 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
27604 this.el.addClass("x-splitbar-v");
27610 * Fires when the splitter is moved (alias for {@link #event-moved})
27611 * @param {Roo.SplitBar} this
27612 * @param {Number} newSize the new width or height
27617 * Fires when the splitter is moved
27618 * @param {Roo.SplitBar} this
27619 * @param {Number} newSize the new width or height
27623 * @event beforeresize
27624 * Fires before the splitter is dragged
27625 * @param {Roo.SplitBar} this
27627 "beforeresize" : true,
27629 "beforeapply" : true
27632 Roo.util.Observable.call(this);
27635 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
27636 onStartProxyDrag : function(x, y){
27637 this.fireEvent("beforeresize", this);
27639 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
27641 o.enableDisplayMode("block");
27642 // all splitbars share the same overlay
27643 Roo.SplitBar.prototype.overlay = o;
27645 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27646 this.overlay.show();
27647 Roo.get(this.proxy).setDisplayed("block");
27648 var size = this.adapter.getElementSize(this);
27649 this.activeMinSize = this.getMinimumSize();;
27650 this.activeMaxSize = this.getMaximumSize();;
27651 var c1 = size - this.activeMinSize;
27652 var c2 = Math.max(this.activeMaxSize - size, 0);
27653 if(this.orientation == Roo.SplitBar.HORIZONTAL){
27654 this.dd.resetConstraints();
27655 this.dd.setXConstraint(
27656 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
27657 this.placement == Roo.SplitBar.LEFT ? c2 : c1
27659 this.dd.setYConstraint(0, 0);
27661 this.dd.resetConstraints();
27662 this.dd.setXConstraint(0, 0);
27663 this.dd.setYConstraint(
27664 this.placement == Roo.SplitBar.TOP ? c1 : c2,
27665 this.placement == Roo.SplitBar.TOP ? c2 : c1
27668 this.dragSpecs.startSize = size;
27669 this.dragSpecs.startPoint = [x, y];
27670 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
27674 * @private Called after the drag operation by the DDProxy
27676 onEndProxyDrag : function(e){
27677 Roo.get(this.proxy).setDisplayed(false);
27678 var endPoint = Roo.lib.Event.getXY(e);
27680 this.overlay.hide();
27683 if(this.orientation == Roo.SplitBar.HORIZONTAL){
27684 newSize = this.dragSpecs.startSize +
27685 (this.placement == Roo.SplitBar.LEFT ?
27686 endPoint[0] - this.dragSpecs.startPoint[0] :
27687 this.dragSpecs.startPoint[0] - endPoint[0]
27690 newSize = this.dragSpecs.startSize +
27691 (this.placement == Roo.SplitBar.TOP ?
27692 endPoint[1] - this.dragSpecs.startPoint[1] :
27693 this.dragSpecs.startPoint[1] - endPoint[1]
27696 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
27697 if(newSize != this.dragSpecs.startSize){
27698 if(this.fireEvent('beforeapply', this, newSize) !== false){
27699 this.adapter.setElementSize(this, newSize);
27700 this.fireEvent("moved", this, newSize);
27701 this.fireEvent("resize", this, newSize);
27707 * Get the adapter this SplitBar uses
27708 * @return The adapter object
27710 getAdapter : function(){
27711 return this.adapter;
27715 * Set the adapter this SplitBar uses
27716 * @param {Object} adapter A SplitBar adapter object
27718 setAdapter : function(adapter){
27719 this.adapter = adapter;
27720 this.adapter.init(this);
27724 * Gets the minimum size for the resizing element
27725 * @return {Number} The minimum size
27727 getMinimumSize : function(){
27728 return this.minSize;
27732 * Sets the minimum size for the resizing element
27733 * @param {Number} minSize The minimum size
27735 setMinimumSize : function(minSize){
27736 this.minSize = minSize;
27740 * Gets the maximum size for the resizing element
27741 * @return {Number} The maximum size
27743 getMaximumSize : function(){
27744 return this.maxSize;
27748 * Sets the maximum size for the resizing element
27749 * @param {Number} maxSize The maximum size
27751 setMaximumSize : function(maxSize){
27752 this.maxSize = maxSize;
27756 * Sets the initialize size for the resizing element
27757 * @param {Number} size The initial size
27759 setCurrentSize : function(size){
27760 var oldAnimate = this.animate;
27761 this.animate = false;
27762 this.adapter.setElementSize(this, size);
27763 this.animate = oldAnimate;
27767 * Destroy this splitbar.
27768 * @param {Boolean} removeEl True to remove the element
27770 destroy : function(removeEl){
27772 this.shim.remove();
27775 this.proxy.parentNode.removeChild(this.proxy);
27783 * @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.
27785 Roo.SplitBar.createProxy = function(dir){
27786 var proxy = new Roo.Element(document.createElement("div"));
27787 proxy.unselectable();
27788 var cls = 'x-splitbar-proxy';
27789 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
27790 document.body.appendChild(proxy.dom);
27795 * @class Roo.SplitBar.BasicLayoutAdapter
27796 * Default Adapter. It assumes the splitter and resizing element are not positioned
27797 * elements and only gets/sets the width of the element. Generally used for table based layouts.
27799 Roo.SplitBar.BasicLayoutAdapter = function(){
27802 Roo.SplitBar.BasicLayoutAdapter.prototype = {
27803 // do nothing for now
27804 init : function(s){
27808 * Called before drag operations to get the current size of the resizing element.
27809 * @param {Roo.SplitBar} s The SplitBar using this adapter
27811 getElementSize : function(s){
27812 if(s.orientation == Roo.SplitBar.HORIZONTAL){
27813 return s.resizingEl.getWidth();
27815 return s.resizingEl.getHeight();
27820 * Called after drag operations to set the size of the resizing element.
27821 * @param {Roo.SplitBar} s The SplitBar using this adapter
27822 * @param {Number} newSize The new size to set
27823 * @param {Function} onComplete A function to be invoked when resizing is complete
27825 setElementSize : function(s, newSize, onComplete){
27826 if(s.orientation == Roo.SplitBar.HORIZONTAL){
27828 s.resizingEl.setWidth(newSize);
27830 onComplete(s, newSize);
27833 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
27838 s.resizingEl.setHeight(newSize);
27840 onComplete(s, newSize);
27843 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
27850 *@class Roo.SplitBar.AbsoluteLayoutAdapter
27851 * @extends Roo.SplitBar.BasicLayoutAdapter
27852 * Adapter that moves the splitter element to align with the resized sizing element.
27853 * Used with an absolute positioned SplitBar.
27854 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
27855 * document.body, make sure you assign an id to the body element.
27857 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
27858 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
27859 this.container = Roo.get(container);
27862 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
27863 init : function(s){
27864 this.basic.init(s);
27867 getElementSize : function(s){
27868 return this.basic.getElementSize(s);
27871 setElementSize : function(s, newSize, onComplete){
27872 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
27875 moveSplitter : function(s){
27876 var yes = Roo.SplitBar;
27877 switch(s.placement){
27879 s.el.setX(s.resizingEl.getRight());
27882 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
27885 s.el.setY(s.resizingEl.getBottom());
27888 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
27895 * Orientation constant - Create a vertical SplitBar
27899 Roo.SplitBar.VERTICAL = 1;
27902 * Orientation constant - Create a horizontal SplitBar
27906 Roo.SplitBar.HORIZONTAL = 2;
27909 * Placement constant - The resizing element is to the left of the splitter element
27913 Roo.SplitBar.LEFT = 1;
27916 * Placement constant - The resizing element is to the right of the splitter element
27920 Roo.SplitBar.RIGHT = 2;
27923 * Placement constant - The resizing element is positioned above the splitter element
27927 Roo.SplitBar.TOP = 3;
27930 * Placement constant - The resizing element is positioned under splitter element
27934 Roo.SplitBar.BOTTOM = 4;
27937 * Ext JS Library 1.1.1
27938 * Copyright(c) 2006-2007, Ext JS, LLC.
27940 * Originally Released Under LGPL - original licence link has changed is not relivant.
27943 * <script type="text/javascript">
27948 * @extends Roo.util.Observable
27949 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
27950 * This class also supports single and multi selection modes. <br>
27951 * Create a data model bound view:
27953 var store = new Roo.data.Store(...);
27955 var view = new Roo.View({
27957 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
27959 singleSelect: true,
27960 selectedClass: "ydataview-selected",
27964 // listen for node click?
27965 view.on("click", function(vw, index, node, e){
27966 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27970 dataModel.load("foobar.xml");
27972 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
27974 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
27975 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
27977 * Note: old style constructor is still suported (container, template, config)
27980 * Create a new View
27981 * @param {Object} config The config object
27984 Roo.View = function(config, depreciated_tpl, depreciated_config){
27986 this.parent = false;
27988 if (typeof(depreciated_tpl) == 'undefined') {
27989 // new way.. - universal constructor.
27990 Roo.apply(this, config);
27991 this.el = Roo.get(this.el);
27994 this.el = Roo.get(config);
27995 this.tpl = depreciated_tpl;
27996 Roo.apply(this, depreciated_config);
27998 this.wrapEl = this.el.wrap().wrap();
27999 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
28002 if(typeof(this.tpl) == "string"){
28003 this.tpl = new Roo.Template(this.tpl);
28005 // support xtype ctors..
28006 this.tpl = new Roo.factory(this.tpl, Roo);
28010 this.tpl.compile();
28015 * @event beforeclick
28016 * Fires before a click is processed. Returns false to cancel the default action.
28017 * @param {Roo.View} this
28018 * @param {Number} index The index of the target node
28019 * @param {HTMLElement} node The target node
28020 * @param {Roo.EventObject} e The raw event object
28022 "beforeclick" : true,
28025 * Fires when a template node is clicked.
28026 * @param {Roo.View} this
28027 * @param {Number} index The index of the target node
28028 * @param {HTMLElement} node The target node
28029 * @param {Roo.EventObject} e The raw event object
28034 * Fires when a template node is double clicked.
28035 * @param {Roo.View} this
28036 * @param {Number} index The index of the target node
28037 * @param {HTMLElement} node The target node
28038 * @param {Roo.EventObject} e The raw event object
28042 * @event contextmenu
28043 * Fires when a template node is right clicked.
28044 * @param {Roo.View} this
28045 * @param {Number} index The index of the target node
28046 * @param {HTMLElement} node The target node
28047 * @param {Roo.EventObject} e The raw event object
28049 "contextmenu" : true,
28051 * @event selectionchange
28052 * Fires when the selected nodes change.
28053 * @param {Roo.View} this
28054 * @param {Array} selections Array of the selected nodes
28056 "selectionchange" : true,
28059 * @event beforeselect
28060 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
28061 * @param {Roo.View} this
28062 * @param {HTMLElement} node The node to be selected
28063 * @param {Array} selections Array of currently selected nodes
28065 "beforeselect" : true,
28067 * @event preparedata
28068 * Fires on every row to render, to allow you to change the data.
28069 * @param {Roo.View} this
28070 * @param {Object} data to be rendered (change this)
28072 "preparedata" : true
28080 "click": this.onClick,
28081 "dblclick": this.onDblClick,
28082 "contextmenu": this.onContextMenu,
28086 this.selections = [];
28088 this.cmp = new Roo.CompositeElementLite([]);
28090 this.store = Roo.factory(this.store, Roo.data);
28091 this.setStore(this.store, true);
28094 if ( this.footer && this.footer.xtype) {
28096 var fctr = this.wrapEl.appendChild(document.createElement("div"));
28098 this.footer.dataSource = this.store;
28099 this.footer.container = fctr;
28100 this.footer = Roo.factory(this.footer, Roo);
28101 fctr.insertFirst(this.el);
28103 // this is a bit insane - as the paging toolbar seems to detach the el..
28104 // dom.parentNode.parentNode.parentNode
28105 // they get detached?
28109 Roo.View.superclass.constructor.call(this);
28114 Roo.extend(Roo.View, Roo.util.Observable, {
28117 * @cfg {Roo.data.Store} store Data store to load data from.
28122 * @cfg {String|Roo.Element} el The container element.
28127 * @cfg {String|Roo.Template} tpl The template used by this View
28131 * @cfg {String} dataName the named area of the template to use as the data area
28132 * Works with domtemplates roo-name="name"
28136 * @cfg {String} selectedClass The css class to add to selected nodes
28138 selectedClass : "x-view-selected",
28140 * @cfg {String} emptyText The empty text to show when nothing is loaded.
28145 * @cfg {String} text to display on mask (default Loading)
28149 * @cfg {Boolean} multiSelect Allow multiple selection
28151 multiSelect : false,
28153 * @cfg {Boolean} singleSelect Allow single selection
28155 singleSelect: false,
28158 * @cfg {Boolean} toggleSelect - selecting
28160 toggleSelect : false,
28163 * @cfg {Boolean} tickable - selecting
28168 * Returns the element this view is bound to.
28169 * @return {Roo.Element}
28171 getEl : function(){
28172 return this.wrapEl;
28178 * Refreshes the view. - called by datachanged on the store. - do not call directly.
28180 refresh : function(){
28181 //Roo.log('refresh');
28184 // if we are using something like 'domtemplate', then
28185 // the what gets used is:
28186 // t.applySubtemplate(NAME, data, wrapping data..)
28187 // the outer template then get' applied with
28188 // the store 'extra data'
28189 // and the body get's added to the
28190 // roo-name="data" node?
28191 // <span class='roo-tpl-{name}'></span> ?????
28195 this.clearSelections();
28196 this.el.update("");
28198 var records = this.store.getRange();
28199 if(records.length < 1) {
28201 // is this valid?? = should it render a template??
28203 this.el.update(this.emptyText);
28207 if (this.dataName) {
28208 this.el.update(t.apply(this.store.meta)); //????
28209 el = this.el.child('.roo-tpl-' + this.dataName);
28212 for(var i = 0, len = records.length; i < len; i++){
28213 var data = this.prepareData(records[i].data, i, records[i]);
28214 this.fireEvent("preparedata", this, data, i, records[i]);
28216 var d = Roo.apply({}, data);
28219 Roo.apply(d, {'roo-id' : Roo.id()});
28223 Roo.each(this.parent.item, function(item){
28224 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
28227 Roo.apply(d, {'roo-data-checked' : 'checked'});
28231 html[html.length] = Roo.util.Format.trim(
28233 t.applySubtemplate(this.dataName, d, this.store.meta) :
28240 el.update(html.join(""));
28241 this.nodes = el.dom.childNodes;
28242 this.updateIndexes(0);
28247 * Function to override to reformat the data that is sent to
28248 * the template for each node.
28249 * DEPRICATED - use the preparedata event handler.
28250 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
28251 * a JSON object for an UpdateManager bound view).
28253 prepareData : function(data, index, record)
28255 this.fireEvent("preparedata", this, data, index, record);
28259 onUpdate : function(ds, record){
28260 // Roo.log('on update');
28261 this.clearSelections();
28262 var index = this.store.indexOf(record);
28263 var n = this.nodes[index];
28264 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
28265 n.parentNode.removeChild(n);
28266 this.updateIndexes(index, index);
28272 onAdd : function(ds, records, index)
28274 //Roo.log(['on Add', ds, records, index] );
28275 this.clearSelections();
28276 if(this.nodes.length == 0){
28280 var n = this.nodes[index];
28281 for(var i = 0, len = records.length; i < len; i++){
28282 var d = this.prepareData(records[i].data, i, records[i]);
28284 this.tpl.insertBefore(n, d);
28287 this.tpl.append(this.el, d);
28290 this.updateIndexes(index);
28293 onRemove : function(ds, record, index){
28294 // Roo.log('onRemove');
28295 this.clearSelections();
28296 var el = this.dataName ?
28297 this.el.child('.roo-tpl-' + this.dataName) :
28300 el.dom.removeChild(this.nodes[index]);
28301 this.updateIndexes(index);
28305 * Refresh an individual node.
28306 * @param {Number} index
28308 refreshNode : function(index){
28309 this.onUpdate(this.store, this.store.getAt(index));
28312 updateIndexes : function(startIndex, endIndex){
28313 var ns = this.nodes;
28314 startIndex = startIndex || 0;
28315 endIndex = endIndex || ns.length - 1;
28316 for(var i = startIndex; i <= endIndex; i++){
28317 ns[i].nodeIndex = i;
28322 * Changes the data store this view uses and refresh the view.
28323 * @param {Store} store
28325 setStore : function(store, initial){
28326 if(!initial && this.store){
28327 this.store.un("datachanged", this.refresh);
28328 this.store.un("add", this.onAdd);
28329 this.store.un("remove", this.onRemove);
28330 this.store.un("update", this.onUpdate);
28331 this.store.un("clear", this.refresh);
28332 this.store.un("beforeload", this.onBeforeLoad);
28333 this.store.un("load", this.onLoad);
28334 this.store.un("loadexception", this.onLoad);
28338 store.on("datachanged", this.refresh, this);
28339 store.on("add", this.onAdd, this);
28340 store.on("remove", this.onRemove, this);
28341 store.on("update", this.onUpdate, this);
28342 store.on("clear", this.refresh, this);
28343 store.on("beforeload", this.onBeforeLoad, this);
28344 store.on("load", this.onLoad, this);
28345 store.on("loadexception", this.onLoad, this);
28353 * onbeforeLoad - masks the loading area.
28356 onBeforeLoad : function(store,opts)
28358 //Roo.log('onBeforeLoad');
28360 this.el.update("");
28362 this.el.mask(this.mask ? this.mask : "Loading" );
28364 onLoad : function ()
28371 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
28372 * @param {HTMLElement} node
28373 * @return {HTMLElement} The template node
28375 findItemFromChild : function(node){
28376 var el = this.dataName ?
28377 this.el.child('.roo-tpl-' + this.dataName,true) :
28380 if(!node || node.parentNode == el){
28383 var p = node.parentNode;
28384 while(p && p != el){
28385 if(p.parentNode == el){
28394 onClick : function(e){
28395 var item = this.findItemFromChild(e.getTarget());
28397 var index = this.indexOf(item);
28398 if(this.onItemClick(item, index, e) !== false){
28399 this.fireEvent("click", this, index, item, e);
28402 this.clearSelections();
28407 onContextMenu : function(e){
28408 var item = this.findItemFromChild(e.getTarget());
28410 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
28415 onDblClick : function(e){
28416 var item = this.findItemFromChild(e.getTarget());
28418 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
28422 onItemClick : function(item, index, e)
28424 if(this.fireEvent("beforeclick", this, index, item, e) === false){
28427 if (this.toggleSelect) {
28428 var m = this.isSelected(item) ? 'unselect' : 'select';
28431 _t[m](item, true, false);
28434 if(this.multiSelect || this.singleSelect){
28435 if(this.multiSelect && e.shiftKey && this.lastSelection){
28436 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
28438 this.select(item, this.multiSelect && e.ctrlKey);
28439 this.lastSelection = item;
28442 if(!this.tickable){
28443 e.preventDefault();
28451 * Get the number of selected nodes.
28454 getSelectionCount : function(){
28455 return this.selections.length;
28459 * Get the currently selected nodes.
28460 * @return {Array} An array of HTMLElements
28462 getSelectedNodes : function(){
28463 return this.selections;
28467 * Get the indexes of the selected nodes.
28470 getSelectedIndexes : function(){
28471 var indexes = [], s = this.selections;
28472 for(var i = 0, len = s.length; i < len; i++){
28473 indexes.push(s[i].nodeIndex);
28479 * Clear all selections
28480 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
28482 clearSelections : function(suppressEvent){
28483 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
28484 this.cmp.elements = this.selections;
28485 this.cmp.removeClass(this.selectedClass);
28486 this.selections = [];
28487 if(!suppressEvent){
28488 this.fireEvent("selectionchange", this, this.selections);
28494 * Returns true if the passed node is selected
28495 * @param {HTMLElement/Number} node The node or node index
28496 * @return {Boolean}
28498 isSelected : function(node){
28499 var s = this.selections;
28503 node = this.getNode(node);
28504 return s.indexOf(node) !== -1;
28509 * @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
28510 * @param {Boolean} keepExisting (optional) true to keep existing selections
28511 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
28513 select : function(nodeInfo, keepExisting, suppressEvent){
28514 if(nodeInfo instanceof Array){
28516 this.clearSelections(true);
28518 for(var i = 0, len = nodeInfo.length; i < len; i++){
28519 this.select(nodeInfo[i], true, true);
28523 var node = this.getNode(nodeInfo);
28524 if(!node || this.isSelected(node)){
28525 return; // already selected.
28528 this.clearSelections(true);
28531 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
28532 Roo.fly(node).addClass(this.selectedClass);
28533 this.selections.push(node);
28534 if(!suppressEvent){
28535 this.fireEvent("selectionchange", this, this.selections);
28543 * @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
28544 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
28545 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
28547 unselect : function(nodeInfo, keepExisting, suppressEvent)
28549 if(nodeInfo instanceof Array){
28550 Roo.each(this.selections, function(s) {
28551 this.unselect(s, nodeInfo);
28555 var node = this.getNode(nodeInfo);
28556 if(!node || !this.isSelected(node)){
28557 //Roo.log("not selected");
28558 return; // not selected.
28562 Roo.each(this.selections, function(s) {
28564 Roo.fly(node).removeClass(this.selectedClass);
28571 this.selections= ns;
28572 this.fireEvent("selectionchange", this, this.selections);
28576 * Gets a template node.
28577 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
28578 * @return {HTMLElement} The node or null if it wasn't found
28580 getNode : function(nodeInfo){
28581 if(typeof nodeInfo == "string"){
28582 return document.getElementById(nodeInfo);
28583 }else if(typeof nodeInfo == "number"){
28584 return this.nodes[nodeInfo];
28590 * Gets a range template nodes.
28591 * @param {Number} startIndex
28592 * @param {Number} endIndex
28593 * @return {Array} An array of nodes
28595 getNodes : function(start, end){
28596 var ns = this.nodes;
28597 start = start || 0;
28598 end = typeof end == "undefined" ? ns.length - 1 : end;
28601 for(var i = start; i <= end; i++){
28605 for(var i = start; i >= end; i--){
28613 * Finds the index of the passed node
28614 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
28615 * @return {Number} The index of the node or -1
28617 indexOf : function(node){
28618 node = this.getNode(node);
28619 if(typeof node.nodeIndex == "number"){
28620 return node.nodeIndex;
28622 var ns = this.nodes;
28623 for(var i = 0, len = ns.length; i < len; i++){
28633 * Ext JS Library 1.1.1
28634 * Copyright(c) 2006-2007, Ext JS, LLC.
28636 * Originally Released Under LGPL - original licence link has changed is not relivant.
28639 * <script type="text/javascript">
28643 * @class Roo.JsonView
28644 * @extends Roo.View
28645 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
28647 var view = new Roo.JsonView({
28648 container: "my-element",
28649 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
28654 // listen for node click?
28655 view.on("click", function(vw, index, node, e){
28656 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
28659 // direct load of JSON data
28660 view.load("foobar.php");
28662 // Example from my blog list
28663 var tpl = new Roo.Template(
28664 '<div class="entry">' +
28665 '<a class="entry-title" href="{link}">{title}</a>' +
28666 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
28667 "</div><hr />"
28670 var moreView = new Roo.JsonView({
28671 container : "entry-list",
28675 moreView.on("beforerender", this.sortEntries, this);
28677 url: "/blog/get-posts.php",
28678 params: "allposts=true",
28679 text: "Loading Blog Entries..."
28683 * Note: old code is supported with arguments : (container, template, config)
28687 * Create a new JsonView
28689 * @param {Object} config The config object
28692 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
28695 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
28697 var um = this.el.getUpdateManager();
28698 um.setRenderer(this);
28699 um.on("update", this.onLoad, this);
28700 um.on("failure", this.onLoadException, this);
28703 * @event beforerender
28704 * Fires before rendering of the downloaded JSON data.
28705 * @param {Roo.JsonView} this
28706 * @param {Object} data The JSON data loaded
28710 * Fires when data is loaded.
28711 * @param {Roo.JsonView} this
28712 * @param {Object} data The JSON data loaded
28713 * @param {Object} response The raw Connect response object
28716 * @event loadexception
28717 * Fires when loading fails.
28718 * @param {Roo.JsonView} this
28719 * @param {Object} response The raw Connect response object
28722 'beforerender' : true,
28724 'loadexception' : true
28727 Roo.extend(Roo.JsonView, Roo.View, {
28729 * @type {String} The root property in the loaded JSON object that contains the data
28734 * Refreshes the view.
28736 refresh : function(){
28737 this.clearSelections();
28738 this.el.update("");
28740 var o = this.jsonData;
28741 if(o && o.length > 0){
28742 for(var i = 0, len = o.length; i < len; i++){
28743 var data = this.prepareData(o[i], i, o);
28744 html[html.length] = this.tpl.apply(data);
28747 html.push(this.emptyText);
28749 this.el.update(html.join(""));
28750 this.nodes = this.el.dom.childNodes;
28751 this.updateIndexes(0);
28755 * 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.
28756 * @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:
28759 url: "your-url.php",
28760 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
28761 callback: yourFunction,
28762 scope: yourObject, //(optional scope)
28765 text: "Loading...",
28770 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
28771 * 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.
28772 * @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}
28773 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
28774 * @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.
28777 var um = this.el.getUpdateManager();
28778 um.update.apply(um, arguments);
28781 // note - render is a standard framework call...
28782 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
28783 render : function(el, response){
28785 this.clearSelections();
28786 this.el.update("");
28789 if (response != '') {
28790 o = Roo.util.JSON.decode(response.responseText);
28793 o = o[this.jsonRoot];
28799 * The current JSON data or null
28802 this.beforeRender();
28807 * Get the number of records in the current JSON dataset
28810 getCount : function(){
28811 return this.jsonData ? this.jsonData.length : 0;
28815 * Returns the JSON object for the specified node(s)
28816 * @param {HTMLElement/Array} node The node or an array of nodes
28817 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
28818 * you get the JSON object for the node
28820 getNodeData : function(node){
28821 if(node instanceof Array){
28823 for(var i = 0, len = node.length; i < len; i++){
28824 data.push(this.getNodeData(node[i]));
28828 return this.jsonData[this.indexOf(node)] || null;
28831 beforeRender : function(){
28832 this.snapshot = this.jsonData;
28834 this.sort.apply(this, this.sortInfo);
28836 this.fireEvent("beforerender", this, this.jsonData);
28839 onLoad : function(el, o){
28840 this.fireEvent("load", this, this.jsonData, o);
28843 onLoadException : function(el, o){
28844 this.fireEvent("loadexception", this, o);
28848 * Filter the data by a specific property.
28849 * @param {String} property A property on your JSON objects
28850 * @param {String/RegExp} value Either string that the property values
28851 * should start with, or a RegExp to test against the property
28853 filter : function(property, value){
28856 var ss = this.snapshot;
28857 if(typeof value == "string"){
28858 var vlen = value.length;
28860 this.clearFilter();
28863 value = value.toLowerCase();
28864 for(var i = 0, len = ss.length; i < len; i++){
28866 if(o[property].substr(0, vlen).toLowerCase() == value){
28870 } else if(value.exec){ // regex?
28871 for(var i = 0, len = ss.length; i < len; i++){
28873 if(value.test(o[property])){
28880 this.jsonData = data;
28886 * Filter by a function. The passed function will be called with each
28887 * object in the current dataset. If the function returns true the value is kept,
28888 * otherwise it is filtered.
28889 * @param {Function} fn
28890 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
28892 filterBy : function(fn, scope){
28895 var ss = this.snapshot;
28896 for(var i = 0, len = ss.length; i < len; i++){
28898 if(fn.call(scope || this, o)){
28902 this.jsonData = data;
28908 * Clears the current filter.
28910 clearFilter : function(){
28911 if(this.snapshot && this.jsonData != this.snapshot){
28912 this.jsonData = this.snapshot;
28919 * Sorts the data for this view and refreshes it.
28920 * @param {String} property A property on your JSON objects to sort on
28921 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
28922 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
28924 sort : function(property, dir, sortType){
28925 this.sortInfo = Array.prototype.slice.call(arguments, 0);
28928 var dsc = dir && dir.toLowerCase() == "desc";
28929 var f = function(o1, o2){
28930 var v1 = sortType ? sortType(o1[p]) : o1[p];
28931 var v2 = sortType ? sortType(o2[p]) : o2[p];
28934 return dsc ? +1 : -1;
28935 } else if(v1 > v2){
28936 return dsc ? -1 : +1;
28941 this.jsonData.sort(f);
28943 if(this.jsonData != this.snapshot){
28944 this.snapshot.sort(f);
28950 * Ext JS Library 1.1.1
28951 * Copyright(c) 2006-2007, Ext JS, LLC.
28953 * Originally Released Under LGPL - original licence link has changed is not relivant.
28956 * <script type="text/javascript">
28961 * @class Roo.ColorPalette
28962 * @extends Roo.Component
28963 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
28964 * Here's an example of typical usage:
28966 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
28967 cp.render('my-div');
28969 cp.on('select', function(palette, selColor){
28970 // do something with selColor
28974 * Create a new ColorPalette
28975 * @param {Object} config The config object
28977 Roo.ColorPalette = function(config){
28978 Roo.ColorPalette.superclass.constructor.call(this, config);
28982 * Fires when a color is selected
28983 * @param {ColorPalette} this
28984 * @param {String} color The 6-digit color hex code (without the # symbol)
28990 this.on("select", this.handler, this.scope, true);
28993 Roo.extend(Roo.ColorPalette, Roo.Component, {
28995 * @cfg {String} itemCls
28996 * The CSS class to apply to the containing element (defaults to "x-color-palette")
28998 itemCls : "x-color-palette",
29000 * @cfg {String} value
29001 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
29002 * the hex codes are case-sensitive.
29005 clickEvent:'click',
29007 ctype: "Roo.ColorPalette",
29010 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
29012 allowReselect : false,
29015 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
29016 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
29017 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
29018 * of colors with the width setting until the box is symmetrical.</p>
29019 * <p>You can override individual colors if needed:</p>
29021 var cp = new Roo.ColorPalette();
29022 cp.colors[0] = "FF0000"; // change the first box to red
29025 Or you can provide a custom array of your own for complete control:
29027 var cp = new Roo.ColorPalette();
29028 cp.colors = ["000000", "993300", "333300"];
29033 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
29034 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
29035 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
29036 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
29037 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
29041 onRender : function(container, position){
29042 var t = new Roo.MasterTemplate(
29043 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
29045 var c = this.colors;
29046 for(var i = 0, len = c.length; i < len; i++){
29049 var el = document.createElement("div");
29050 el.className = this.itemCls;
29052 container.dom.insertBefore(el, position);
29053 this.el = Roo.get(el);
29054 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
29055 if(this.clickEvent != 'click'){
29056 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
29061 afterRender : function(){
29062 Roo.ColorPalette.superclass.afterRender.call(this);
29064 var s = this.value;
29071 handleClick : function(e, t){
29072 e.preventDefault();
29073 if(!this.disabled){
29074 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
29075 this.select(c.toUpperCase());
29080 * Selects the specified color in the palette (fires the select event)
29081 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
29083 select : function(color){
29084 color = color.replace("#", "");
29085 if(color != this.value || this.allowReselect){
29088 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
29090 el.child("a.color-"+color).addClass("x-color-palette-sel");
29091 this.value = color;
29092 this.fireEvent("select", this, color);
29097 * Ext JS Library 1.1.1
29098 * Copyright(c) 2006-2007, Ext JS, LLC.
29100 * Originally Released Under LGPL - original licence link has changed is not relivant.
29103 * <script type="text/javascript">
29107 * @class Roo.DatePicker
29108 * @extends Roo.Component
29109 * Simple date picker class.
29111 * Create a new DatePicker
29112 * @param {Object} config The config object
29114 Roo.DatePicker = function(config){
29115 Roo.DatePicker.superclass.constructor.call(this, config);
29117 this.value = config && config.value ?
29118 config.value.clearTime() : new Date().clearTime();
29123 * Fires when a date is selected
29124 * @param {DatePicker} this
29125 * @param {Date} date The selected date
29129 * @event monthchange
29130 * Fires when the displayed month changes
29131 * @param {DatePicker} this
29132 * @param {Date} date The selected month
29134 'monthchange': true
29138 this.on("select", this.handler, this.scope || this);
29140 // build the disabledDatesRE
29141 if(!this.disabledDatesRE && this.disabledDates){
29142 var dd = this.disabledDates;
29144 for(var i = 0; i < dd.length; i++){
29146 if(i != dd.length-1) {
29150 this.disabledDatesRE = new RegExp(re + ")");
29154 Roo.extend(Roo.DatePicker, Roo.Component, {
29156 * @cfg {String} todayText
29157 * The text to display on the button that selects the current date (defaults to "Today")
29159 todayText : "Today",
29161 * @cfg {String} okText
29162 * The text to display on the ok button
29164 okText : " OK ", //   to give the user extra clicking room
29166 * @cfg {String} cancelText
29167 * The text to display on the cancel button
29169 cancelText : "Cancel",
29171 * @cfg {String} todayTip
29172 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
29174 todayTip : "{0} (Spacebar)",
29176 * @cfg {Date} minDate
29177 * Minimum allowable date (JavaScript date object, defaults to null)
29181 * @cfg {Date} maxDate
29182 * Maximum allowable date (JavaScript date object, defaults to null)
29186 * @cfg {String} minText
29187 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
29189 minText : "This date is before the minimum date",
29191 * @cfg {String} maxText
29192 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
29194 maxText : "This date is after the maximum date",
29196 * @cfg {String} format
29197 * The default date format string which can be overriden for localization support. The format must be
29198 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
29202 * @cfg {Array} disabledDays
29203 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
29205 disabledDays : null,
29207 * @cfg {String} disabledDaysText
29208 * The tooltip to display when the date falls on a disabled day (defaults to "")
29210 disabledDaysText : "",
29212 * @cfg {RegExp} disabledDatesRE
29213 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
29215 disabledDatesRE : null,
29217 * @cfg {String} disabledDatesText
29218 * The tooltip text to display when the date falls on a disabled date (defaults to "")
29220 disabledDatesText : "",
29222 * @cfg {Boolean} constrainToViewport
29223 * True to constrain the date picker to the viewport (defaults to true)
29225 constrainToViewport : true,
29227 * @cfg {Array} monthNames
29228 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
29230 monthNames : Date.monthNames,
29232 * @cfg {Array} dayNames
29233 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
29235 dayNames : Date.dayNames,
29237 * @cfg {String} nextText
29238 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
29240 nextText: 'Next Month (Control+Right)',
29242 * @cfg {String} prevText
29243 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
29245 prevText: 'Previous Month (Control+Left)',
29247 * @cfg {String} monthYearText
29248 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
29250 monthYearText: 'Choose a month (Control+Up/Down to move years)',
29252 * @cfg {Number} startDay
29253 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
29257 * @cfg {Bool} showClear
29258 * Show a clear button (usefull for date form elements that can be blank.)
29264 * Sets the value of the date field
29265 * @param {Date} value The date to set
29267 setValue : function(value){
29268 var old = this.value;
29270 if (typeof(value) == 'string') {
29272 value = Date.parseDate(value, this.format);
29275 value = new Date();
29278 this.value = value.clearTime(true);
29280 this.update(this.value);
29285 * Gets the current selected value of the date field
29286 * @return {Date} The selected date
29288 getValue : function(){
29293 focus : function(){
29295 this.update(this.activeDate);
29300 onRender : function(container, position){
29303 '<table cellspacing="0">',
29304 '<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>',
29305 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
29306 var dn = this.dayNames;
29307 for(var i = 0; i < 7; i++){
29308 var d = this.startDay+i;
29312 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
29314 m[m.length] = "</tr></thead><tbody><tr>";
29315 for(var i = 0; i < 42; i++) {
29316 if(i % 7 == 0 && i != 0){
29317 m[m.length] = "</tr><tr>";
29319 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
29321 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
29322 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
29324 var el = document.createElement("div");
29325 el.className = "x-date-picker";
29326 el.innerHTML = m.join("");
29328 container.dom.insertBefore(el, position);
29330 this.el = Roo.get(el);
29331 this.eventEl = Roo.get(el.firstChild);
29333 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
29334 handler: this.showPrevMonth,
29336 preventDefault:true,
29340 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
29341 handler: this.showNextMonth,
29343 preventDefault:true,
29347 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
29349 this.monthPicker = this.el.down('div.x-date-mp');
29350 this.monthPicker.enableDisplayMode('block');
29352 var kn = new Roo.KeyNav(this.eventEl, {
29353 "left" : function(e){
29355 this.showPrevMonth() :
29356 this.update(this.activeDate.add("d", -1));
29359 "right" : function(e){
29361 this.showNextMonth() :
29362 this.update(this.activeDate.add("d", 1));
29365 "up" : function(e){
29367 this.showNextYear() :
29368 this.update(this.activeDate.add("d", -7));
29371 "down" : function(e){
29373 this.showPrevYear() :
29374 this.update(this.activeDate.add("d", 7));
29377 "pageUp" : function(e){
29378 this.showNextMonth();
29381 "pageDown" : function(e){
29382 this.showPrevMonth();
29385 "enter" : function(e){
29386 e.stopPropagation();
29393 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
29395 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
29397 this.el.unselectable();
29399 this.cells = this.el.select("table.x-date-inner tbody td");
29400 this.textNodes = this.el.query("table.x-date-inner tbody span");
29402 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
29404 tooltip: this.monthYearText
29407 this.mbtn.on('click', this.showMonthPicker, this);
29408 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
29411 var today = (new Date()).dateFormat(this.format);
29413 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
29414 if (this.showClear) {
29415 baseTb.add( new Roo.Toolbar.Fill());
29418 text: String.format(this.todayText, today),
29419 tooltip: String.format(this.todayTip, today),
29420 handler: this.selectToday,
29424 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
29427 if (this.showClear) {
29429 baseTb.add( new Roo.Toolbar.Fill());
29432 cls: 'x-btn-icon x-btn-clear',
29433 handler: function() {
29435 this.fireEvent("select", this, '');
29445 this.update(this.value);
29448 createMonthPicker : function(){
29449 if(!this.monthPicker.dom.firstChild){
29450 var buf = ['<table border="0" cellspacing="0">'];
29451 for(var i = 0; i < 6; i++){
29453 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
29454 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
29456 '<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>' :
29457 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
29461 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
29463 '</button><button type="button" class="x-date-mp-cancel">',
29465 '</button></td></tr>',
29468 this.monthPicker.update(buf.join(''));
29469 this.monthPicker.on('click', this.onMonthClick, this);
29470 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
29472 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
29473 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
29475 this.mpMonths.each(function(m, a, i){
29478 m.dom.xmonth = 5 + Math.round(i * .5);
29480 m.dom.xmonth = Math.round((i-1) * .5);
29486 showMonthPicker : function(){
29487 this.createMonthPicker();
29488 var size = this.el.getSize();
29489 this.monthPicker.setSize(size);
29490 this.monthPicker.child('table').setSize(size);
29492 this.mpSelMonth = (this.activeDate || this.value).getMonth();
29493 this.updateMPMonth(this.mpSelMonth);
29494 this.mpSelYear = (this.activeDate || this.value).getFullYear();
29495 this.updateMPYear(this.mpSelYear);
29497 this.monthPicker.slideIn('t', {duration:.2});
29500 updateMPYear : function(y){
29502 var ys = this.mpYears.elements;
29503 for(var i = 1; i <= 10; i++){
29504 var td = ys[i-1], y2;
29506 y2 = y + Math.round(i * .5);
29507 td.firstChild.innerHTML = y2;
29510 y2 = y - (5-Math.round(i * .5));
29511 td.firstChild.innerHTML = y2;
29514 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
29518 updateMPMonth : function(sm){
29519 this.mpMonths.each(function(m, a, i){
29520 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
29524 selectMPMonth: function(m){
29528 onMonthClick : function(e, t){
29530 var el = new Roo.Element(t), pn;
29531 if(el.is('button.x-date-mp-cancel')){
29532 this.hideMonthPicker();
29534 else if(el.is('button.x-date-mp-ok')){
29535 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
29536 this.hideMonthPicker();
29538 else if(pn = el.up('td.x-date-mp-month', 2)){
29539 this.mpMonths.removeClass('x-date-mp-sel');
29540 pn.addClass('x-date-mp-sel');
29541 this.mpSelMonth = pn.dom.xmonth;
29543 else if(pn = el.up('td.x-date-mp-year', 2)){
29544 this.mpYears.removeClass('x-date-mp-sel');
29545 pn.addClass('x-date-mp-sel');
29546 this.mpSelYear = pn.dom.xyear;
29548 else if(el.is('a.x-date-mp-prev')){
29549 this.updateMPYear(this.mpyear-10);
29551 else if(el.is('a.x-date-mp-next')){
29552 this.updateMPYear(this.mpyear+10);
29556 onMonthDblClick : function(e, t){
29558 var el = new Roo.Element(t), pn;
29559 if(pn = el.up('td.x-date-mp-month', 2)){
29560 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
29561 this.hideMonthPicker();
29563 else if(pn = el.up('td.x-date-mp-year', 2)){
29564 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
29565 this.hideMonthPicker();
29569 hideMonthPicker : function(disableAnim){
29570 if(this.monthPicker){
29571 if(disableAnim === true){
29572 this.monthPicker.hide();
29574 this.monthPicker.slideOut('t', {duration:.2});
29580 showPrevMonth : function(e){
29581 this.update(this.activeDate.add("mo", -1));
29585 showNextMonth : function(e){
29586 this.update(this.activeDate.add("mo", 1));
29590 showPrevYear : function(){
29591 this.update(this.activeDate.add("y", -1));
29595 showNextYear : function(){
29596 this.update(this.activeDate.add("y", 1));
29600 handleMouseWheel : function(e){
29601 var delta = e.getWheelDelta();
29603 this.showPrevMonth();
29605 } else if(delta < 0){
29606 this.showNextMonth();
29612 handleDateClick : function(e, t){
29614 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
29615 this.setValue(new Date(t.dateValue));
29616 this.fireEvent("select", this, this.value);
29621 selectToday : function(){
29622 this.setValue(new Date().clearTime());
29623 this.fireEvent("select", this, this.value);
29627 update : function(date)
29629 var vd = this.activeDate;
29630 this.activeDate = date;
29632 var t = date.getTime();
29633 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
29634 this.cells.removeClass("x-date-selected");
29635 this.cells.each(function(c){
29636 if(c.dom.firstChild.dateValue == t){
29637 c.addClass("x-date-selected");
29638 setTimeout(function(){
29639 try{c.dom.firstChild.focus();}catch(e){}
29648 var days = date.getDaysInMonth();
29649 var firstOfMonth = date.getFirstDateOfMonth();
29650 var startingPos = firstOfMonth.getDay()-this.startDay;
29652 if(startingPos <= this.startDay){
29656 var pm = date.add("mo", -1);
29657 var prevStart = pm.getDaysInMonth()-startingPos;
29659 var cells = this.cells.elements;
29660 var textEls = this.textNodes;
29661 days += startingPos;
29663 // convert everything to numbers so it's fast
29664 var day = 86400000;
29665 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
29666 var today = new Date().clearTime().getTime();
29667 var sel = date.clearTime().getTime();
29668 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
29669 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
29670 var ddMatch = this.disabledDatesRE;
29671 var ddText = this.disabledDatesText;
29672 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
29673 var ddaysText = this.disabledDaysText;
29674 var format = this.format;
29676 var setCellClass = function(cal, cell){
29678 var t = d.getTime();
29679 cell.firstChild.dateValue = t;
29681 cell.className += " x-date-today";
29682 cell.title = cal.todayText;
29685 cell.className += " x-date-selected";
29686 setTimeout(function(){
29687 try{cell.firstChild.focus();}catch(e){}
29692 cell.className = " x-date-disabled";
29693 cell.title = cal.minText;
29697 cell.className = " x-date-disabled";
29698 cell.title = cal.maxText;
29702 if(ddays.indexOf(d.getDay()) != -1){
29703 cell.title = ddaysText;
29704 cell.className = " x-date-disabled";
29707 if(ddMatch && format){
29708 var fvalue = d.dateFormat(format);
29709 if(ddMatch.test(fvalue)){
29710 cell.title = ddText.replace("%0", fvalue);
29711 cell.className = " x-date-disabled";
29717 for(; i < startingPos; i++) {
29718 textEls[i].innerHTML = (++prevStart);
29719 d.setDate(d.getDate()+1);
29720 cells[i].className = "x-date-prevday";
29721 setCellClass(this, cells[i]);
29723 for(; i < days; i++){
29724 intDay = i - startingPos + 1;
29725 textEls[i].innerHTML = (intDay);
29726 d.setDate(d.getDate()+1);
29727 cells[i].className = "x-date-active";
29728 setCellClass(this, cells[i]);
29731 for(; i < 42; i++) {
29732 textEls[i].innerHTML = (++extraDays);
29733 d.setDate(d.getDate()+1);
29734 cells[i].className = "x-date-nextday";
29735 setCellClass(this, cells[i]);
29738 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
29739 this.fireEvent('monthchange', this, date);
29741 if(!this.internalRender){
29742 var main = this.el.dom.firstChild;
29743 var w = main.offsetWidth;
29744 this.el.setWidth(w + this.el.getBorderWidth("lr"));
29745 Roo.fly(main).setWidth(w);
29746 this.internalRender = true;
29747 // opera does not respect the auto grow header center column
29748 // then, after it gets a width opera refuses to recalculate
29749 // without a second pass
29750 if(Roo.isOpera && !this.secondPass){
29751 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
29752 this.secondPass = true;
29753 this.update.defer(10, this, [date]);
29761 * Ext JS Library 1.1.1
29762 * Copyright(c) 2006-2007, Ext JS, LLC.
29764 * Originally Released Under LGPL - original licence link has changed is not relivant.
29767 * <script type="text/javascript">
29770 * @class Roo.TabPanel
29771 * @extends Roo.util.Observable
29772 * A lightweight tab container.
29776 // basic tabs 1, built from existing content
29777 var tabs = new Roo.TabPanel("tabs1");
29778 tabs.addTab("script", "View Script");
29779 tabs.addTab("markup", "View Markup");
29780 tabs.activate("script");
29782 // more advanced tabs, built from javascript
29783 var jtabs = new Roo.TabPanel("jtabs");
29784 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
29786 // set up the UpdateManager
29787 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
29788 var updater = tab2.getUpdateManager();
29789 updater.setDefaultUrl("ajax1.htm");
29790 tab2.on('activate', updater.refresh, updater, true);
29792 // Use setUrl for Ajax loading
29793 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
29794 tab3.setUrl("ajax2.htm", null, true);
29797 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
29800 jtabs.activate("jtabs-1");
29803 * Create a new TabPanel.
29804 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
29805 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
29807 Roo.TabPanel = function(container, config){
29809 * The container element for this TabPanel.
29810 * @type Roo.Element
29812 this.el = Roo.get(container, true);
29814 if(typeof config == "boolean"){
29815 this.tabPosition = config ? "bottom" : "top";
29817 Roo.apply(this, config);
29820 if(this.tabPosition == "bottom"){
29821 this.bodyEl = Roo.get(this.createBody(this.el.dom));
29822 this.el.addClass("x-tabs-bottom");
29824 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
29825 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
29826 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
29828 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
29830 if(this.tabPosition != "bottom"){
29831 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
29832 * @type Roo.Element
29834 this.bodyEl = Roo.get(this.createBody(this.el.dom));
29835 this.el.addClass("x-tabs-top");
29839 this.bodyEl.setStyle("position", "relative");
29841 this.active = null;
29842 this.activateDelegate = this.activate.createDelegate(this);
29847 * Fires when the active tab changes
29848 * @param {Roo.TabPanel} this
29849 * @param {Roo.TabPanelItem} activePanel The new active tab
29853 * @event beforetabchange
29854 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
29855 * @param {Roo.TabPanel} this
29856 * @param {Object} e Set cancel to true on this object to cancel the tab change
29857 * @param {Roo.TabPanelItem} tab The tab being changed to
29859 "beforetabchange" : true
29862 Roo.EventManager.onWindowResize(this.onResize, this);
29863 this.cpad = this.el.getPadding("lr");
29864 this.hiddenCount = 0;
29867 // toolbar on the tabbar support...
29868 if (this.toolbar) {
29869 var tcfg = this.toolbar;
29870 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
29871 this.toolbar = new Roo.Toolbar(tcfg);
29872 if (Roo.isSafari) {
29873 var tbl = tcfg.container.child('table', true);
29874 tbl.setAttribute('width', '100%');
29881 Roo.TabPanel.superclass.constructor.call(this);
29884 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
29886 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
29888 tabPosition : "top",
29890 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
29892 currentTabWidth : 0,
29894 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
29898 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
29902 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
29904 preferredTabWidth : 175,
29906 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
29908 resizeTabs : false,
29910 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
29912 monitorResize : true,
29914 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
29919 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
29920 * @param {String} id The id of the div to use <b>or create</b>
29921 * @param {String} text The text for the tab
29922 * @param {String} content (optional) Content to put in the TabPanelItem body
29923 * @param {Boolean} closable (optional) True to create a close icon on the tab
29924 * @return {Roo.TabPanelItem} The created TabPanelItem
29926 addTab : function(id, text, content, closable){
29927 var item = new Roo.TabPanelItem(this, id, text, closable);
29928 this.addTabItem(item);
29930 item.setContent(content);
29936 * Returns the {@link Roo.TabPanelItem} with the specified id/index
29937 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
29938 * @return {Roo.TabPanelItem}
29940 getTab : function(id){
29941 return this.items[id];
29945 * Hides the {@link Roo.TabPanelItem} with the specified id/index
29946 * @param {String/Number} id The id or index of the TabPanelItem to hide.
29948 hideTab : function(id){
29949 var t = this.items[id];
29952 this.hiddenCount++;
29953 this.autoSizeTabs();
29958 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
29959 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
29961 unhideTab : function(id){
29962 var t = this.items[id];
29964 t.setHidden(false);
29965 this.hiddenCount--;
29966 this.autoSizeTabs();
29971 * Adds an existing {@link Roo.TabPanelItem}.
29972 * @param {Roo.TabPanelItem} item The TabPanelItem to add
29974 addTabItem : function(item){
29975 this.items[item.id] = item;
29976 this.items.push(item);
29977 if(this.resizeTabs){
29978 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
29979 this.autoSizeTabs();
29986 * Removes a {@link Roo.TabPanelItem}.
29987 * @param {String/Number} id The id or index of the TabPanelItem to remove.
29989 removeTab : function(id){
29990 var items = this.items;
29991 var tab = items[id];
29992 if(!tab) { return; }
29993 var index = items.indexOf(tab);
29994 if(this.active == tab && items.length > 1){
29995 var newTab = this.getNextAvailable(index);
30000 this.stripEl.dom.removeChild(tab.pnode.dom);
30001 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
30002 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
30004 items.splice(index, 1);
30005 delete this.items[tab.id];
30006 tab.fireEvent("close", tab);
30007 tab.purgeListeners();
30008 this.autoSizeTabs();
30011 getNextAvailable : function(start){
30012 var items = this.items;
30014 // look for a next tab that will slide over to
30015 // replace the one being removed
30016 while(index < items.length){
30017 var item = items[++index];
30018 if(item && !item.isHidden()){
30022 // if one isn't found select the previous tab (on the left)
30025 var item = items[--index];
30026 if(item && !item.isHidden()){
30034 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
30035 * @param {String/Number} id The id or index of the TabPanelItem to disable.
30037 disableTab : function(id){
30038 var tab = this.items[id];
30039 if(tab && this.active != tab){
30045 * Enables a {@link Roo.TabPanelItem} that is disabled.
30046 * @param {String/Number} id The id or index of the TabPanelItem to enable.
30048 enableTab : function(id){
30049 var tab = this.items[id];
30054 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
30055 * @param {String/Number} id The id or index of the TabPanelItem to activate.
30056 * @return {Roo.TabPanelItem} The TabPanelItem.
30058 activate : function(id){
30059 var tab = this.items[id];
30063 if(tab == this.active || tab.disabled){
30067 this.fireEvent("beforetabchange", this, e, tab);
30068 if(e.cancel !== true && !tab.disabled){
30070 this.active.hide();
30072 this.active = this.items[id];
30073 this.active.show();
30074 this.fireEvent("tabchange", this, this.active);
30080 * Gets the active {@link Roo.TabPanelItem}.
30081 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
30083 getActiveTab : function(){
30084 return this.active;
30088 * Updates the tab body element to fit the height of the container element
30089 * for overflow scrolling
30090 * @param {Number} targetHeight (optional) Override the starting height from the elements height
30092 syncHeight : function(targetHeight){
30093 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
30094 var bm = this.bodyEl.getMargins();
30095 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
30096 this.bodyEl.setHeight(newHeight);
30100 onResize : function(){
30101 if(this.monitorResize){
30102 this.autoSizeTabs();
30107 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
30109 beginUpdate : function(){
30110 this.updating = true;
30114 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
30116 endUpdate : function(){
30117 this.updating = false;
30118 this.autoSizeTabs();
30122 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
30124 autoSizeTabs : function(){
30125 var count = this.items.length;
30126 var vcount = count - this.hiddenCount;
30127 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
30130 var w = Math.max(this.el.getWidth() - this.cpad, 10);
30131 var availWidth = Math.floor(w / vcount);
30132 var b = this.stripBody;
30133 if(b.getWidth() > w){
30134 var tabs = this.items;
30135 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
30136 if(availWidth < this.minTabWidth){
30137 /*if(!this.sleft){ // incomplete scrolling code
30138 this.createScrollButtons();
30141 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
30144 if(this.currentTabWidth < this.preferredTabWidth){
30145 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
30151 * Returns the number of tabs in this TabPanel.
30154 getCount : function(){
30155 return this.items.length;
30159 * Resizes all the tabs to the passed width
30160 * @param {Number} The new width
30162 setTabWidth : function(width){
30163 this.currentTabWidth = width;
30164 for(var i = 0, len = this.items.length; i < len; i++) {
30165 if(!this.items[i].isHidden()) {
30166 this.items[i].setWidth(width);
30172 * Destroys this TabPanel
30173 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
30175 destroy : function(removeEl){
30176 Roo.EventManager.removeResizeListener(this.onResize, this);
30177 for(var i = 0, len = this.items.length; i < len; i++){
30178 this.items[i].purgeListeners();
30180 if(removeEl === true){
30181 this.el.update("");
30188 * @class Roo.TabPanelItem
30189 * @extends Roo.util.Observable
30190 * Represents an individual item (tab plus body) in a TabPanel.
30191 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
30192 * @param {String} id The id of this TabPanelItem
30193 * @param {String} text The text for the tab of this TabPanelItem
30194 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
30196 Roo.TabPanelItem = function(tabPanel, id, text, closable){
30198 * The {@link Roo.TabPanel} this TabPanelItem belongs to
30199 * @type Roo.TabPanel
30201 this.tabPanel = tabPanel;
30203 * The id for this TabPanelItem
30208 this.disabled = false;
30212 this.loaded = false;
30213 this.closable = closable;
30216 * The body element for this TabPanelItem.
30217 * @type Roo.Element
30219 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
30220 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
30221 this.bodyEl.setStyle("display", "block");
30222 this.bodyEl.setStyle("zoom", "1");
30225 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
30227 this.el = Roo.get(els.el, true);
30228 this.inner = Roo.get(els.inner, true);
30229 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
30230 this.pnode = Roo.get(els.el.parentNode, true);
30231 this.el.on("mousedown", this.onTabMouseDown, this);
30232 this.el.on("click", this.onTabClick, this);
30235 var c = Roo.get(els.close, true);
30236 c.dom.title = this.closeText;
30237 c.addClassOnOver("close-over");
30238 c.on("click", this.closeClick, this);
30244 * Fires when this tab becomes the active tab.
30245 * @param {Roo.TabPanel} tabPanel The parent TabPanel
30246 * @param {Roo.TabPanelItem} this
30250 * @event beforeclose
30251 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
30252 * @param {Roo.TabPanelItem} this
30253 * @param {Object} e Set cancel to true on this object to cancel the close.
30255 "beforeclose": true,
30258 * Fires when this tab is closed.
30259 * @param {Roo.TabPanelItem} this
30263 * @event deactivate
30264 * Fires when this tab is no longer the active tab.
30265 * @param {Roo.TabPanel} tabPanel The parent TabPanel
30266 * @param {Roo.TabPanelItem} this
30268 "deactivate" : true
30270 this.hidden = false;
30272 Roo.TabPanelItem.superclass.constructor.call(this);
30275 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
30276 purgeListeners : function(){
30277 Roo.util.Observable.prototype.purgeListeners.call(this);
30278 this.el.removeAllListeners();
30281 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
30284 this.pnode.addClass("on");
30287 this.tabPanel.stripWrap.repaint();
30289 this.fireEvent("activate", this.tabPanel, this);
30293 * Returns true if this tab is the active tab.
30294 * @return {Boolean}
30296 isActive : function(){
30297 return this.tabPanel.getActiveTab() == this;
30301 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
30304 this.pnode.removeClass("on");
30306 this.fireEvent("deactivate", this.tabPanel, this);
30309 hideAction : function(){
30310 this.bodyEl.hide();
30311 this.bodyEl.setStyle("position", "absolute");
30312 this.bodyEl.setLeft("-20000px");
30313 this.bodyEl.setTop("-20000px");
30316 showAction : function(){
30317 this.bodyEl.setStyle("position", "relative");
30318 this.bodyEl.setTop("");
30319 this.bodyEl.setLeft("");
30320 this.bodyEl.show();
30324 * Set the tooltip for the tab.
30325 * @param {String} tooltip The tab's tooltip
30327 setTooltip : function(text){
30328 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
30329 this.textEl.dom.qtip = text;
30330 this.textEl.dom.removeAttribute('title');
30332 this.textEl.dom.title = text;
30336 onTabClick : function(e){
30337 e.preventDefault();
30338 this.tabPanel.activate(this.id);
30341 onTabMouseDown : function(e){
30342 e.preventDefault();
30343 this.tabPanel.activate(this.id);
30346 getWidth : function(){
30347 return this.inner.getWidth();
30350 setWidth : function(width){
30351 var iwidth = width - this.pnode.getPadding("lr");
30352 this.inner.setWidth(iwidth);
30353 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
30354 this.pnode.setWidth(width);
30358 * Show or hide the tab
30359 * @param {Boolean} hidden True to hide or false to show.
30361 setHidden : function(hidden){
30362 this.hidden = hidden;
30363 this.pnode.setStyle("display", hidden ? "none" : "");
30367 * Returns true if this tab is "hidden"
30368 * @return {Boolean}
30370 isHidden : function(){
30371 return this.hidden;
30375 * Returns the text for this tab
30378 getText : function(){
30382 autoSize : function(){
30383 //this.el.beginMeasure();
30384 this.textEl.setWidth(1);
30386 * #2804 [new] Tabs in Roojs
30387 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
30389 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
30390 //this.el.endMeasure();
30394 * Sets the text for the tab (Note: this also sets the tooltip text)
30395 * @param {String} text The tab's text and tooltip
30397 setText : function(text){
30399 this.textEl.update(text);
30400 this.setTooltip(text);
30401 if(!this.tabPanel.resizeTabs){
30406 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
30408 activate : function(){
30409 this.tabPanel.activate(this.id);
30413 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
30415 disable : function(){
30416 if(this.tabPanel.active != this){
30417 this.disabled = true;
30418 this.pnode.addClass("disabled");
30423 * Enables this TabPanelItem if it was previously disabled.
30425 enable : function(){
30426 this.disabled = false;
30427 this.pnode.removeClass("disabled");
30431 * Sets the content for this TabPanelItem.
30432 * @param {String} content The content
30433 * @param {Boolean} loadScripts true to look for and load scripts
30435 setContent : function(content, loadScripts){
30436 this.bodyEl.update(content, loadScripts);
30440 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
30441 * @return {Roo.UpdateManager} The UpdateManager
30443 getUpdateManager : function(){
30444 return this.bodyEl.getUpdateManager();
30448 * Set a URL to be used to load the content for this TabPanelItem.
30449 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
30450 * @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)
30451 * @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)
30452 * @return {Roo.UpdateManager} The UpdateManager
30454 setUrl : function(url, params, loadOnce){
30455 if(this.refreshDelegate){
30456 this.un('activate', this.refreshDelegate);
30458 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
30459 this.on("activate", this.refreshDelegate);
30460 return this.bodyEl.getUpdateManager();
30464 _handleRefresh : function(url, params, loadOnce){
30465 if(!loadOnce || !this.loaded){
30466 var updater = this.bodyEl.getUpdateManager();
30467 updater.update(url, params, this._setLoaded.createDelegate(this));
30472 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
30473 * Will fail silently if the setUrl method has not been called.
30474 * This does not activate the panel, just updates its content.
30476 refresh : function(){
30477 if(this.refreshDelegate){
30478 this.loaded = false;
30479 this.refreshDelegate();
30484 _setLoaded : function(){
30485 this.loaded = true;
30489 closeClick : function(e){
30492 this.fireEvent("beforeclose", this, o);
30493 if(o.cancel !== true){
30494 this.tabPanel.removeTab(this.id);
30498 * The text displayed in the tooltip for the close icon.
30501 closeText : "Close this tab"
30505 Roo.TabPanel.prototype.createStrip = function(container){
30506 var strip = document.createElement("div");
30507 strip.className = "x-tabs-wrap";
30508 container.appendChild(strip);
30512 Roo.TabPanel.prototype.createStripList = function(strip){
30513 // div wrapper for retard IE
30514 // returns the "tr" element.
30515 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
30516 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
30517 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
30518 return strip.firstChild.firstChild.firstChild.firstChild;
30521 Roo.TabPanel.prototype.createBody = function(container){
30522 var body = document.createElement("div");
30523 Roo.id(body, "tab-body");
30524 Roo.fly(body).addClass("x-tabs-body");
30525 container.appendChild(body);
30529 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
30530 var body = Roo.getDom(id);
30532 body = document.createElement("div");
30535 Roo.fly(body).addClass("x-tabs-item-body");
30536 bodyEl.insertBefore(body, bodyEl.firstChild);
30540 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
30541 var td = document.createElement("td");
30542 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
30543 //stripEl.appendChild(td);
30545 td.className = "x-tabs-closable";
30546 if(!this.closeTpl){
30547 this.closeTpl = new Roo.Template(
30548 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
30549 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
30550 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
30553 var el = this.closeTpl.overwrite(td, {"text": text});
30554 var close = el.getElementsByTagName("div")[0];
30555 var inner = el.getElementsByTagName("em")[0];
30556 return {"el": el, "close": close, "inner": inner};
30559 this.tabTpl = new Roo.Template(
30560 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
30561 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
30564 var el = this.tabTpl.overwrite(td, {"text": text});
30565 var inner = el.getElementsByTagName("em")[0];
30566 return {"el": el, "inner": inner};
30570 * Ext JS Library 1.1.1
30571 * Copyright(c) 2006-2007, Ext JS, LLC.
30573 * Originally Released Under LGPL - original licence link has changed is not relivant.
30576 * <script type="text/javascript">
30580 * @class Roo.Button
30581 * @extends Roo.util.Observable
30582 * Simple Button class
30583 * @cfg {String} text The button text
30584 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
30585 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
30586 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
30587 * @cfg {Object} scope The scope of the handler
30588 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
30589 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
30590 * @cfg {Boolean} hidden True to start hidden (defaults to false)
30591 * @cfg {Boolean} disabled True to start disabled (defaults to false)
30592 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
30593 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
30594 applies if enableToggle = true)
30595 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
30596 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
30597 an {@link Roo.util.ClickRepeater} config object (defaults to false).
30599 * Create a new button
30600 * @param {Object} config The config object
30602 Roo.Button = function(renderTo, config)
30606 renderTo = config.renderTo || false;
30609 Roo.apply(this, config);
30613 * Fires when this button is clicked
30614 * @param {Button} this
30615 * @param {EventObject} e The click event
30620 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
30621 * @param {Button} this
30622 * @param {Boolean} pressed
30627 * Fires when the mouse hovers over the button
30628 * @param {Button} this
30629 * @param {Event} e The event object
30631 'mouseover' : true,
30634 * Fires when the mouse exits the button
30635 * @param {Button} this
30636 * @param {Event} e The event object
30641 * Fires when the button is rendered
30642 * @param {Button} this
30647 this.menu = Roo.menu.MenuMgr.get(this.menu);
30649 // register listeners first!! - so render can be captured..
30650 Roo.util.Observable.call(this);
30652 this.render(renderTo);
30658 Roo.extend(Roo.Button, Roo.util.Observable, {
30664 * Read-only. True if this button is hidden
30669 * Read-only. True if this button is disabled
30674 * Read-only. True if this button is pressed (only if enableToggle = true)
30680 * @cfg {Number} tabIndex
30681 * The DOM tabIndex for this button (defaults to undefined)
30683 tabIndex : undefined,
30686 * @cfg {Boolean} enableToggle
30687 * True to enable pressed/not pressed toggling (defaults to false)
30689 enableToggle: false,
30691 * @cfg {Roo.menu.Menu} menu
30692 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
30696 * @cfg {String} menuAlign
30697 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
30699 menuAlign : "tl-bl?",
30702 * @cfg {String} iconCls
30703 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
30705 iconCls : undefined,
30707 * @cfg {String} type
30708 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
30713 menuClassTarget: 'tr',
30716 * @cfg {String} clickEvent
30717 * The type of event to map to the button's event handler (defaults to 'click')
30719 clickEvent : 'click',
30722 * @cfg {Boolean} handleMouseEvents
30723 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
30725 handleMouseEvents : true,
30728 * @cfg {String} tooltipType
30729 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
30731 tooltipType : 'qtip',
30734 * @cfg {String} cls
30735 * A CSS class to apply to the button's main element.
30739 * @cfg {Roo.Template} template (Optional)
30740 * An {@link Roo.Template} with which to create the Button's main element. This Template must
30741 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
30742 * require code modifications if required elements (e.g. a button) aren't present.
30746 render : function(renderTo){
30748 if(this.hideParent){
30749 this.parentEl = Roo.get(renderTo);
30751 if(!this.dhconfig){
30752 if(!this.template){
30753 if(!Roo.Button.buttonTemplate){
30754 // hideous table template
30755 Roo.Button.buttonTemplate = new Roo.Template(
30756 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
30757 '<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>',
30758 "</tr></tbody></table>");
30760 this.template = Roo.Button.buttonTemplate;
30762 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
30763 var btnEl = btn.child("button:first");
30764 btnEl.on('focus', this.onFocus, this);
30765 btnEl.on('blur', this.onBlur, this);
30767 btn.addClass(this.cls);
30770 btnEl.setStyle('background-image', 'url(' +this.icon +')');
30773 btnEl.addClass(this.iconCls);
30775 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
30778 if(this.tabIndex !== undefined){
30779 btnEl.dom.tabIndex = this.tabIndex;
30782 if(typeof this.tooltip == 'object'){
30783 Roo.QuickTips.tips(Roo.apply({
30787 btnEl.dom[this.tooltipType] = this.tooltip;
30791 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
30795 this.el.dom.id = this.el.id = this.id;
30798 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
30799 this.menu.on("show", this.onMenuShow, this);
30800 this.menu.on("hide", this.onMenuHide, this);
30802 btn.addClass("x-btn");
30803 if(Roo.isIE && !Roo.isIE7){
30804 this.autoWidth.defer(1, this);
30808 if(this.handleMouseEvents){
30809 btn.on("mouseover", this.onMouseOver, this);
30810 btn.on("mouseout", this.onMouseOut, this);
30811 btn.on("mousedown", this.onMouseDown, this);
30813 btn.on(this.clickEvent, this.onClick, this);
30814 //btn.on("mouseup", this.onMouseUp, this);
30821 Roo.ButtonToggleMgr.register(this);
30823 this.el.addClass("x-btn-pressed");
30826 var repeater = new Roo.util.ClickRepeater(btn,
30827 typeof this.repeat == "object" ? this.repeat : {}
30829 repeater.on("click", this.onClick, this);
30832 this.fireEvent('render', this);
30836 * Returns the button's underlying element
30837 * @return {Roo.Element} The element
30839 getEl : function(){
30844 * Destroys this Button and removes any listeners.
30846 destroy : function(){
30847 Roo.ButtonToggleMgr.unregister(this);
30848 this.el.removeAllListeners();
30849 this.purgeListeners();
30854 autoWidth : function(){
30856 this.el.setWidth("auto");
30857 if(Roo.isIE7 && Roo.isStrict){
30858 var ib = this.el.child('button');
30859 if(ib && ib.getWidth() > 20){
30861 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
30866 this.el.beginMeasure();
30868 if(this.el.getWidth() < this.minWidth){
30869 this.el.setWidth(this.minWidth);
30872 this.el.endMeasure();
30879 * Assigns this button's click handler
30880 * @param {Function} handler The function to call when the button is clicked
30881 * @param {Object} scope (optional) Scope for the function passed in
30883 setHandler : function(handler, scope){
30884 this.handler = handler;
30885 this.scope = scope;
30889 * Sets this button's text
30890 * @param {String} text The button text
30892 setText : function(text){
30895 this.el.child("td.x-btn-center button.x-btn-text").update(text);
30901 * Gets the text for this button
30902 * @return {String} The button text
30904 getText : function(){
30912 this.hidden = false;
30914 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
30922 this.hidden = true;
30924 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
30929 * Convenience function for boolean show/hide
30930 * @param {Boolean} visible True to show, false to hide
30932 setVisible: function(visible){
30941 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
30942 * @param {Boolean} state (optional) Force a particular state
30944 toggle : function(state){
30945 state = state === undefined ? !this.pressed : state;
30946 if(state != this.pressed){
30948 this.el.addClass("x-btn-pressed");
30949 this.pressed = true;
30950 this.fireEvent("toggle", this, true);
30952 this.el.removeClass("x-btn-pressed");
30953 this.pressed = false;
30954 this.fireEvent("toggle", this, false);
30956 if(this.toggleHandler){
30957 this.toggleHandler.call(this.scope || this, this, state);
30965 focus : function(){
30966 this.el.child('button:first').focus();
30970 * Disable this button
30972 disable : function(){
30974 this.el.addClass("x-btn-disabled");
30976 this.disabled = true;
30980 * Enable this button
30982 enable : function(){
30984 this.el.removeClass("x-btn-disabled");
30986 this.disabled = false;
30990 * Convenience function for boolean enable/disable
30991 * @param {Boolean} enabled True to enable, false to disable
30993 setDisabled : function(v){
30994 this[v !== true ? "enable" : "disable"]();
30998 onClick : function(e)
31001 e.preventDefault();
31006 if(!this.disabled){
31007 if(this.enableToggle){
31010 if(this.menu && !this.menu.isVisible()){
31011 this.menu.show(this.el, this.menuAlign);
31013 this.fireEvent("click", this, e);
31015 this.el.removeClass("x-btn-over");
31016 this.handler.call(this.scope || this, this, e);
31021 onMouseOver : function(e){
31022 if(!this.disabled){
31023 this.el.addClass("x-btn-over");
31024 this.fireEvent('mouseover', this, e);
31028 onMouseOut : function(e){
31029 if(!e.within(this.el, true)){
31030 this.el.removeClass("x-btn-over");
31031 this.fireEvent('mouseout', this, e);
31035 onFocus : function(e){
31036 if(!this.disabled){
31037 this.el.addClass("x-btn-focus");
31041 onBlur : function(e){
31042 this.el.removeClass("x-btn-focus");
31045 onMouseDown : function(e){
31046 if(!this.disabled && e.button == 0){
31047 this.el.addClass("x-btn-click");
31048 Roo.get(document).on('mouseup', this.onMouseUp, this);
31052 onMouseUp : function(e){
31054 this.el.removeClass("x-btn-click");
31055 Roo.get(document).un('mouseup', this.onMouseUp, this);
31059 onMenuShow : function(e){
31060 this.el.addClass("x-btn-menu-active");
31063 onMenuHide : function(e){
31064 this.el.removeClass("x-btn-menu-active");
31068 // Private utility class used by Button
31069 Roo.ButtonToggleMgr = function(){
31072 function toggleGroup(btn, state){
31074 var g = groups[btn.toggleGroup];
31075 for(var i = 0, l = g.length; i < l; i++){
31077 g[i].toggle(false);
31084 register : function(btn){
31085 if(!btn.toggleGroup){
31088 var g = groups[btn.toggleGroup];
31090 g = groups[btn.toggleGroup] = [];
31093 btn.on("toggle", toggleGroup);
31096 unregister : function(btn){
31097 if(!btn.toggleGroup){
31100 var g = groups[btn.toggleGroup];
31103 btn.un("toggle", toggleGroup);
31109 * Ext JS Library 1.1.1
31110 * Copyright(c) 2006-2007, Ext JS, LLC.
31112 * Originally Released Under LGPL - original licence link has changed is not relivant.
31115 * <script type="text/javascript">
31119 * @class Roo.SplitButton
31120 * @extends Roo.Button
31121 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
31122 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
31123 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
31124 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
31125 * @cfg {String} arrowTooltip The title attribute of the arrow
31127 * Create a new menu button
31128 * @param {String/HTMLElement/Element} renderTo The element to append the button to
31129 * @param {Object} config The config object
31131 Roo.SplitButton = function(renderTo, config){
31132 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
31134 * @event arrowclick
31135 * Fires when this button's arrow is clicked
31136 * @param {SplitButton} this
31137 * @param {EventObject} e The click event
31139 this.addEvents({"arrowclick":true});
31142 Roo.extend(Roo.SplitButton, Roo.Button, {
31143 render : function(renderTo){
31144 // this is one sweet looking template!
31145 var tpl = new Roo.Template(
31146 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
31147 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
31148 '<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>',
31149 "</tbody></table></td><td>",
31150 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
31151 '<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>',
31152 "</tbody></table></td></tr></table>"
31154 var btn = tpl.append(renderTo, [this.text, this.type], true);
31155 var btnEl = btn.child("button");
31157 btn.addClass(this.cls);
31160 btnEl.setStyle('background-image', 'url(' +this.icon +')');
31163 btnEl.addClass(this.iconCls);
31165 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
31169 if(this.handleMouseEvents){
31170 btn.on("mouseover", this.onMouseOver, this);
31171 btn.on("mouseout", this.onMouseOut, this);
31172 btn.on("mousedown", this.onMouseDown, this);
31173 btn.on("mouseup", this.onMouseUp, this);
31175 btn.on(this.clickEvent, this.onClick, this);
31177 if(typeof this.tooltip == 'object'){
31178 Roo.QuickTips.tips(Roo.apply({
31182 btnEl.dom[this.tooltipType] = this.tooltip;
31185 if(this.arrowTooltip){
31186 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
31195 this.el.addClass("x-btn-pressed");
31197 if(Roo.isIE && !Roo.isIE7){
31198 this.autoWidth.defer(1, this);
31203 this.menu.on("show", this.onMenuShow, this);
31204 this.menu.on("hide", this.onMenuHide, this);
31206 this.fireEvent('render', this);
31210 autoWidth : function(){
31212 var tbl = this.el.child("table:first");
31213 var tbl2 = this.el.child("table:last");
31214 this.el.setWidth("auto");
31215 tbl.setWidth("auto");
31216 if(Roo.isIE7 && Roo.isStrict){
31217 var ib = this.el.child('button:first');
31218 if(ib && ib.getWidth() > 20){
31220 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
31225 this.el.beginMeasure();
31227 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
31228 tbl.setWidth(this.minWidth-tbl2.getWidth());
31231 this.el.endMeasure();
31234 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
31238 * Sets this button's click handler
31239 * @param {Function} handler The function to call when the button is clicked
31240 * @param {Object} scope (optional) Scope for the function passed above
31242 setHandler : function(handler, scope){
31243 this.handler = handler;
31244 this.scope = scope;
31248 * Sets this button's arrow click handler
31249 * @param {Function} handler The function to call when the arrow is clicked
31250 * @param {Object} scope (optional) Scope for the function passed above
31252 setArrowHandler : function(handler, scope){
31253 this.arrowHandler = handler;
31254 this.scope = scope;
31260 focus : function(){
31262 this.el.child("button:first").focus();
31267 onClick : function(e){
31268 e.preventDefault();
31269 if(!this.disabled){
31270 if(e.getTarget(".x-btn-menu-arrow-wrap")){
31271 if(this.menu && !this.menu.isVisible()){
31272 this.menu.show(this.el, this.menuAlign);
31274 this.fireEvent("arrowclick", this, e);
31275 if(this.arrowHandler){
31276 this.arrowHandler.call(this.scope || this, this, e);
31279 this.fireEvent("click", this, e);
31281 this.handler.call(this.scope || this, this, e);
31287 onMouseDown : function(e){
31288 if(!this.disabled){
31289 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
31293 onMouseUp : function(e){
31294 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
31299 // backwards compat
31300 Roo.MenuButton = Roo.SplitButton;/*
31302 * Ext JS Library 1.1.1
31303 * Copyright(c) 2006-2007, Ext JS, LLC.
31305 * Originally Released Under LGPL - original licence link has changed is not relivant.
31308 * <script type="text/javascript">
31312 * @class Roo.Toolbar
31313 * @children Roo.Toolbar.Item Roo.Toolbar.Button Roo.Toolbar.SplitButton Roo.form.Field
31314 * Basic Toolbar class.
31316 * Creates a new Toolbar
31317 * @param {Object} container The config object
31319 Roo.Toolbar = function(container, buttons, config)
31321 /// old consturctor format still supported..
31322 if(container instanceof Array){ // omit the container for later rendering
31323 buttons = container;
31327 if (typeof(container) == 'object' && container.xtype) {
31328 config = container;
31329 container = config.container;
31330 buttons = config.buttons || []; // not really - use items!!
31333 if (config && config.items) {
31334 xitems = config.items;
31335 delete config.items;
31337 Roo.apply(this, config);
31338 this.buttons = buttons;
31341 this.render(container);
31343 this.xitems = xitems;
31344 Roo.each(xitems, function(b) {
31350 Roo.Toolbar.prototype = {
31352 * @cfg {Array} items
31353 * array of button configs or elements to add (will be converted to a MixedCollection)
31357 * @cfg {String/HTMLElement/Element} container
31358 * The id or element that will contain the toolbar
31361 render : function(ct){
31362 this.el = Roo.get(ct);
31364 this.el.addClass(this.cls);
31366 // using a table allows for vertical alignment
31367 // 100% width is needed by Safari...
31368 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
31369 this.tr = this.el.child("tr", true);
31371 this.items = new Roo.util.MixedCollection(false, function(o){
31372 return o.id || ("item" + (++autoId));
31375 this.add.apply(this, this.buttons);
31376 delete this.buttons;
31381 * Adds element(s) to the toolbar -- this function takes a variable number of
31382 * arguments of mixed type and adds them to the toolbar.
31383 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
31385 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
31386 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
31387 * <li>Field: Any form field (equivalent to {@link #addField})</li>
31388 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
31389 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
31390 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
31391 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
31392 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
31393 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
31395 * @param {Mixed} arg2
31396 * @param {Mixed} etc.
31399 var a = arguments, l = a.length;
31400 for(var i = 0; i < l; i++){
31405 _add : function(el) {
31408 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
31411 if (el.applyTo){ // some kind of form field
31412 return this.addField(el);
31414 if (el.render){ // some kind of Toolbar.Item
31415 return this.addItem(el);
31417 if (typeof el == "string"){ // string
31418 if(el == "separator" || el == "-"){
31419 return this.addSeparator();
31422 return this.addSpacer();
31425 return this.addFill();
31427 return this.addText(el);
31430 if(el.tagName){ // element
31431 return this.addElement(el);
31433 if(typeof el == "object"){ // must be button config?
31434 return this.addButton(el);
31436 // and now what?!?!
31442 * Add an Xtype element
31443 * @param {Object} xtype Xtype Object
31444 * @return {Object} created Object
31446 addxtype : function(e){
31447 return this.add(e);
31451 * Returns the Element for this toolbar.
31452 * @return {Roo.Element}
31454 getEl : function(){
31460 * @return {Roo.Toolbar.Item} The separator item
31462 addSeparator : function(){
31463 return this.addItem(new Roo.Toolbar.Separator());
31467 * Adds a spacer element
31468 * @return {Roo.Toolbar.Spacer} The spacer item
31470 addSpacer : function(){
31471 return this.addItem(new Roo.Toolbar.Spacer());
31475 * Adds a fill element that forces subsequent additions to the right side of the toolbar
31476 * @return {Roo.Toolbar.Fill} The fill item
31478 addFill : function(){
31479 return this.addItem(new Roo.Toolbar.Fill());
31483 * Adds any standard HTML element to the toolbar
31484 * @param {String/HTMLElement/Element} el The element or id of the element to add
31485 * @return {Roo.Toolbar.Item} The element's item
31487 addElement : function(el){
31488 return this.addItem(new Roo.Toolbar.Item(el));
31491 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
31492 * @type Roo.util.MixedCollection
31497 * Adds any Toolbar.Item or subclass
31498 * @param {Roo.Toolbar.Item} item
31499 * @return {Roo.Toolbar.Item} The item
31501 addItem : function(item){
31502 var td = this.nextBlock();
31504 this.items.add(item);
31509 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
31510 * @param {Object/Array} config A button config or array of configs
31511 * @return {Roo.Toolbar.Button/Array}
31513 addButton : function(config){
31514 if(config instanceof Array){
31516 for(var i = 0, len = config.length; i < len; i++) {
31517 buttons.push(this.addButton(config[i]));
31522 if(!(config instanceof Roo.Toolbar.Button)){
31524 new Roo.Toolbar.SplitButton(config) :
31525 new Roo.Toolbar.Button(config);
31527 var td = this.nextBlock();
31534 * Adds text to the toolbar
31535 * @param {String} text The text to add
31536 * @return {Roo.Toolbar.Item} The element's item
31538 addText : function(text){
31539 return this.addItem(new Roo.Toolbar.TextItem(text));
31543 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
31544 * @param {Number} index The index where the item is to be inserted
31545 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
31546 * @return {Roo.Toolbar.Button/Item}
31548 insertButton : function(index, item){
31549 if(item instanceof Array){
31551 for(var i = 0, len = item.length; i < len; i++) {
31552 buttons.push(this.insertButton(index + i, item[i]));
31556 if (!(item instanceof Roo.Toolbar.Button)){
31557 item = new Roo.Toolbar.Button(item);
31559 var td = document.createElement("td");
31560 this.tr.insertBefore(td, this.tr.childNodes[index]);
31562 this.items.insert(index, item);
31567 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
31568 * @param {Object} config
31569 * @return {Roo.Toolbar.Item} The element's item
31571 addDom : function(config, returnEl){
31572 var td = this.nextBlock();
31573 Roo.DomHelper.overwrite(td, config);
31574 var ti = new Roo.Toolbar.Item(td.firstChild);
31576 this.items.add(ti);
31581 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
31582 * @type Roo.util.MixedCollection
31587 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
31588 * Note: the field should not have been rendered yet. For a field that has already been
31589 * rendered, use {@link #addElement}.
31590 * @param {Roo.form.Field} field
31591 * @return {Roo.ToolbarItem}
31595 addField : function(field) {
31596 if (!this.fields) {
31598 this.fields = new Roo.util.MixedCollection(false, function(o){
31599 return o.id || ("item" + (++autoId));
31604 var td = this.nextBlock();
31606 var ti = new Roo.Toolbar.Item(td.firstChild);
31608 this.items.add(ti);
31609 this.fields.add(field);
31620 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
31621 this.el.child('div').hide();
31629 this.el.child('div').show();
31633 nextBlock : function(){
31634 var td = document.createElement("td");
31635 this.tr.appendChild(td);
31640 destroy : function(){
31641 if(this.items){ // rendered?
31642 Roo.destroy.apply(Roo, this.items.items);
31644 if(this.fields){ // rendered?
31645 Roo.destroy.apply(Roo, this.fields.items);
31647 Roo.Element.uncache(this.el, this.tr);
31652 * @class Roo.Toolbar.Item
31653 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
31655 * Creates a new Item
31656 * @param {HTMLElement} el
31658 Roo.Toolbar.Item = function(el){
31660 if (typeof (el.xtype) != 'undefined') {
31665 this.el = Roo.getDom(el);
31666 this.id = Roo.id(this.el);
31667 this.hidden = false;
31672 * Fires when the button is rendered
31673 * @param {Button} this
31677 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
31679 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
31680 //Roo.Toolbar.Item.prototype = {
31683 * Get this item's HTML Element
31684 * @return {HTMLElement}
31686 getEl : function(){
31691 render : function(td){
31694 td.appendChild(this.el);
31696 this.fireEvent('render', this);
31700 * Removes and destroys this item.
31702 destroy : function(){
31703 this.td.parentNode.removeChild(this.td);
31710 this.hidden = false;
31711 this.td.style.display = "";
31718 this.hidden = true;
31719 this.td.style.display = "none";
31723 * Convenience function for boolean show/hide.
31724 * @param {Boolean} visible true to show/false to hide
31726 setVisible: function(visible){
31735 * Try to focus this item.
31737 focus : function(){
31738 Roo.fly(this.el).focus();
31742 * Disables this item.
31744 disable : function(){
31745 Roo.fly(this.td).addClass("x-item-disabled");
31746 this.disabled = true;
31747 this.el.disabled = true;
31751 * Enables this item.
31753 enable : function(){
31754 Roo.fly(this.td).removeClass("x-item-disabled");
31755 this.disabled = false;
31756 this.el.disabled = false;
31762 * @class Roo.Toolbar.Separator
31763 * @extends Roo.Toolbar.Item
31764 * A simple toolbar separator class
31766 * Creates a new Separator
31768 Roo.Toolbar.Separator = function(cfg){
31770 var s = document.createElement("span");
31771 s.className = "ytb-sep";
31776 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
31778 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
31779 enable:Roo.emptyFn,
31780 disable:Roo.emptyFn,
31785 * @class Roo.Toolbar.Spacer
31786 * @extends Roo.Toolbar.Item
31787 * A simple element that adds extra horizontal space to a toolbar.
31789 * Creates a new Spacer
31791 Roo.Toolbar.Spacer = function(cfg){
31792 var s = document.createElement("div");
31793 s.className = "ytb-spacer";
31797 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
31799 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
31800 enable:Roo.emptyFn,
31801 disable:Roo.emptyFn,
31806 * @class Roo.Toolbar.Fill
31807 * @extends Roo.Toolbar.Spacer
31808 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
31810 * Creates a new Spacer
31812 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
31814 render : function(td){
31815 td.style.width = '100%';
31816 Roo.Toolbar.Fill.superclass.render.call(this, td);
31821 * @class Roo.Toolbar.TextItem
31822 * @extends Roo.Toolbar.Item
31823 * A simple class that renders text directly into a toolbar.
31825 * Creates a new TextItem
31826 * @cfg {string} text
31828 Roo.Toolbar.TextItem = function(cfg){
31829 var text = cfg || "";
31830 if (typeof(cfg) == 'object') {
31831 text = cfg.text || "";
31835 var s = document.createElement("span");
31836 s.className = "ytb-text";
31837 s.innerHTML = text;
31842 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
31844 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
31847 enable:Roo.emptyFn,
31848 disable:Roo.emptyFn,
31851 * Shows this button
31854 this.hidden = false;
31855 this.el.style.display = "";
31859 * Hides this button
31862 this.hidden = true;
31863 this.el.style.display = "none";
31869 * @class Roo.Toolbar.Button
31870 * @extends Roo.Button
31871 * A button that renders into a toolbar.
31873 * Creates a new Button
31874 * @param {Object} config A standard {@link Roo.Button} config object
31876 Roo.Toolbar.Button = function(config){
31877 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
31879 Roo.extend(Roo.Toolbar.Button, Roo.Button,
31883 render : function(td){
31885 Roo.Toolbar.Button.superclass.render.call(this, td);
31889 * Removes and destroys this button
31891 destroy : function(){
31892 Roo.Toolbar.Button.superclass.destroy.call(this);
31893 this.td.parentNode.removeChild(this.td);
31897 * Shows this button
31900 this.hidden = false;
31901 this.td.style.display = "";
31905 * Hides this button
31908 this.hidden = true;
31909 this.td.style.display = "none";
31913 * Disables this item
31915 disable : function(){
31916 Roo.fly(this.td).addClass("x-item-disabled");
31917 this.disabled = true;
31921 * Enables this item
31923 enable : function(){
31924 Roo.fly(this.td).removeClass("x-item-disabled");
31925 this.disabled = false;
31928 // backwards compat
31929 Roo.ToolbarButton = Roo.Toolbar.Button;
31932 * @class Roo.Toolbar.SplitButton
31933 * @extends Roo.SplitButton
31934 * A menu button that renders into a toolbar.
31936 * Creates a new SplitButton
31937 * @param {Object} config A standard {@link Roo.SplitButton} config object
31939 Roo.Toolbar.SplitButton = function(config){
31940 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
31942 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
31943 render : function(td){
31945 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
31949 * Removes and destroys this button
31951 destroy : function(){
31952 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
31953 this.td.parentNode.removeChild(this.td);
31957 * Shows this button
31960 this.hidden = false;
31961 this.td.style.display = "";
31965 * Hides this button
31968 this.hidden = true;
31969 this.td.style.display = "none";
31973 // backwards compat
31974 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
31976 * Ext JS Library 1.1.1
31977 * Copyright(c) 2006-2007, Ext JS, LLC.
31979 * Originally Released Under LGPL - original licence link has changed is not relivant.
31982 * <script type="text/javascript">
31986 * @class Roo.PagingToolbar
31987 * @extends Roo.Toolbar
31988 * @children Roo.Toolbar.Item Roo.Toolbar.Button Roo.Toolbar.SplitButton Roo.form.Field
31989 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
31991 * Create a new PagingToolbar
31992 * @param {Object} config The config object
31994 Roo.PagingToolbar = function(el, ds, config)
31996 // old args format still supported... - xtype is prefered..
31997 if (typeof(el) == 'object' && el.xtype) {
31998 // created from xtype...
32000 ds = el.dataSource;
32001 el = config.container;
32004 if (config.items) {
32005 items = config.items;
32009 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
32012 this.renderButtons(this.el);
32015 // supprot items array.
32017 Roo.each(items, function(e) {
32018 this.add(Roo.factory(e));
32023 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
32026 * @cfg {String/HTMLElement/Element} container
32027 * container The id or element that will contain the toolbar
32030 * @cfg {Boolean} displayInfo
32031 * True to display the displayMsg (defaults to false)
32036 * @cfg {Number} pageSize
32037 * The number of records to display per page (defaults to 20)
32041 * @cfg {String} displayMsg
32042 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
32044 displayMsg : 'Displaying {0} - {1} of {2}',
32046 * @cfg {String} emptyMsg
32047 * The message to display when no records are found (defaults to "No data to display")
32049 emptyMsg : 'No data to display',
32051 * Customizable piece of the default paging text (defaults to "Page")
32054 beforePageText : "Page",
32056 * Customizable piece of the default paging text (defaults to "of %0")
32059 afterPageText : "of {0}",
32061 * Customizable piece of the default paging text (defaults to "First Page")
32064 firstText : "First Page",
32066 * Customizable piece of the default paging text (defaults to "Previous Page")
32069 prevText : "Previous Page",
32071 * Customizable piece of the default paging text (defaults to "Next Page")
32074 nextText : "Next Page",
32076 * Customizable piece of the default paging text (defaults to "Last Page")
32079 lastText : "Last Page",
32081 * Customizable piece of the default paging text (defaults to "Refresh")
32084 refreshText : "Refresh",
32087 renderButtons : function(el){
32088 Roo.PagingToolbar.superclass.render.call(this, el);
32089 this.first = this.addButton({
32090 tooltip: this.firstText,
32091 cls: "x-btn-icon x-grid-page-first",
32093 handler: this.onClick.createDelegate(this, ["first"])
32095 this.prev = this.addButton({
32096 tooltip: this.prevText,
32097 cls: "x-btn-icon x-grid-page-prev",
32099 handler: this.onClick.createDelegate(this, ["prev"])
32101 //this.addSeparator();
32102 this.add(this.beforePageText);
32103 this.field = Roo.get(this.addDom({
32108 cls: "x-grid-page-number"
32110 this.field.on("keydown", this.onPagingKeydown, this);
32111 this.field.on("focus", function(){this.dom.select();});
32112 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
32113 this.field.setHeight(18);
32114 //this.addSeparator();
32115 this.next = this.addButton({
32116 tooltip: this.nextText,
32117 cls: "x-btn-icon x-grid-page-next",
32119 handler: this.onClick.createDelegate(this, ["next"])
32121 this.last = this.addButton({
32122 tooltip: this.lastText,
32123 cls: "x-btn-icon x-grid-page-last",
32125 handler: this.onClick.createDelegate(this, ["last"])
32127 //this.addSeparator();
32128 this.loading = this.addButton({
32129 tooltip: this.refreshText,
32130 cls: "x-btn-icon x-grid-loading",
32131 handler: this.onClick.createDelegate(this, ["refresh"])
32134 if(this.displayInfo){
32135 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
32140 updateInfo : function(){
32141 if(this.displayEl){
32142 var count = this.ds.getCount();
32143 var msg = count == 0 ?
32147 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
32149 this.displayEl.update(msg);
32154 onLoad : function(ds, r, o){
32155 this.cursor = o.params ? o.params.start : 0;
32156 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
32158 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
32159 this.field.dom.value = ap;
32160 this.first.setDisabled(ap == 1);
32161 this.prev.setDisabled(ap == 1);
32162 this.next.setDisabled(ap == ps);
32163 this.last.setDisabled(ap == ps);
32164 this.loading.enable();
32169 getPageData : function(){
32170 var total = this.ds.getTotalCount();
32173 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
32174 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
32179 onLoadError : function(){
32180 this.loading.enable();
32184 onPagingKeydown : function(e){
32185 var k = e.getKey();
32186 var d = this.getPageData();
32188 var v = this.field.dom.value, pageNum;
32189 if(!v || isNaN(pageNum = parseInt(v, 10))){
32190 this.field.dom.value = d.activePage;
32193 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
32194 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
32197 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))
32199 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
32200 this.field.dom.value = pageNum;
32201 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
32204 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
32206 var v = this.field.dom.value, pageNum;
32207 var increment = (e.shiftKey) ? 10 : 1;
32208 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
32211 if(!v || isNaN(pageNum = parseInt(v, 10))) {
32212 this.field.dom.value = d.activePage;
32215 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
32217 this.field.dom.value = parseInt(v, 10) + increment;
32218 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
32219 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
32226 beforeLoad : function(){
32228 this.loading.disable();
32233 onClick : function(which){
32237 ds.load({params:{start: 0, limit: this.pageSize}});
32240 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
32243 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
32246 var total = ds.getTotalCount();
32247 var extra = total % this.pageSize;
32248 var lastStart = extra ? (total - extra) : total-this.pageSize;
32249 ds.load({params:{start: lastStart, limit: this.pageSize}});
32252 ds.load({params:{start: this.cursor, limit: this.pageSize}});
32258 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
32259 * @param {Roo.data.Store} store The data store to unbind
32261 unbind : function(ds){
32262 ds.un("beforeload", this.beforeLoad, this);
32263 ds.un("load", this.onLoad, this);
32264 ds.un("loadexception", this.onLoadError, this);
32265 ds.un("remove", this.updateInfo, this);
32266 ds.un("add", this.updateInfo, this);
32267 this.ds = undefined;
32271 * Binds the paging toolbar to the specified {@link Roo.data.Store}
32272 * @param {Roo.data.Store} store The data store to bind
32274 bind : function(ds){
32275 ds.on("beforeload", this.beforeLoad, this);
32276 ds.on("load", this.onLoad, this);
32277 ds.on("loadexception", this.onLoadError, this);
32278 ds.on("remove", this.updateInfo, this);
32279 ds.on("add", this.updateInfo, this);
32284 * Ext JS Library 1.1.1
32285 * Copyright(c) 2006-2007, Ext JS, LLC.
32287 * Originally Released Under LGPL - original licence link has changed is not relivant.
32290 * <script type="text/javascript">
32294 * @class Roo.Resizable
32295 * @extends Roo.util.Observable
32296 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
32297 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
32298 * 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
32299 * the element will be wrapped for you automatically.</p>
32300 * <p>Here is the list of valid resize handles:</p>
32303 ------ -------------------
32312 'hd' horizontal drag
32315 * <p>Here's an example showing the creation of a typical Resizable:</p>
32317 var resizer = new Roo.Resizable("element-id", {
32325 resizer.on("resize", myHandler);
32327 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
32328 * resizer.east.setDisplayed(false);</p>
32329 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
32330 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
32331 * resize operation's new size (defaults to [0, 0])
32332 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
32333 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
32334 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
32335 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
32336 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
32337 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
32338 * @cfg {Number} width The width of the element in pixels (defaults to null)
32339 * @cfg {Number} height The height of the element in pixels (defaults to null)
32340 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
32341 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
32342 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
32343 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
32344 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
32345 * in favor of the handles config option (defaults to false)
32346 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
32347 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
32348 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
32349 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
32350 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
32351 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
32352 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
32353 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
32354 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
32355 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
32356 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
32358 * Create a new resizable component
32359 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
32360 * @param {Object} config configuration options
32362 Roo.Resizable = function(el, config)
32364 this.el = Roo.get(el);
32366 if(config && config.wrap){
32367 config.resizeChild = this.el;
32368 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
32369 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
32370 this.el.setStyle("overflow", "hidden");
32371 this.el.setPositioning(config.resizeChild.getPositioning());
32372 config.resizeChild.clearPositioning();
32373 if(!config.width || !config.height){
32374 var csize = config.resizeChild.getSize();
32375 this.el.setSize(csize.width, csize.height);
32377 if(config.pinned && !config.adjustments){
32378 config.adjustments = "auto";
32382 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
32383 this.proxy.unselectable();
32384 this.proxy.enableDisplayMode('block');
32386 Roo.apply(this, config);
32389 this.disableTrackOver = true;
32390 this.el.addClass("x-resizable-pinned");
32392 // if the element isn't positioned, make it relative
32393 var position = this.el.getStyle("position");
32394 if(position != "absolute" && position != "fixed"){
32395 this.el.setStyle("position", "relative");
32397 if(!this.handles){ // no handles passed, must be legacy style
32398 this.handles = 's,e,se';
32399 if(this.multiDirectional){
32400 this.handles += ',n,w';
32403 if(this.handles == "all"){
32404 this.handles = "n s e w ne nw se sw";
32406 var hs = this.handles.split(/\s*?[,;]\s*?| /);
32407 var ps = Roo.Resizable.positions;
32408 for(var i = 0, len = hs.length; i < len; i++){
32409 if(hs[i] && ps[hs[i]]){
32410 var pos = ps[hs[i]];
32411 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
32415 this.corner = this.southeast;
32417 // updateBox = the box can move..
32418 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
32419 this.updateBox = true;
32422 this.activeHandle = null;
32424 if(this.resizeChild){
32425 if(typeof this.resizeChild == "boolean"){
32426 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
32428 this.resizeChild = Roo.get(this.resizeChild, true);
32432 if(this.adjustments == "auto"){
32433 var rc = this.resizeChild;
32434 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
32435 if(rc && (hw || hn)){
32436 rc.position("relative");
32437 rc.setLeft(hw ? hw.el.getWidth() : 0);
32438 rc.setTop(hn ? hn.el.getHeight() : 0);
32440 this.adjustments = [
32441 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
32442 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
32446 if(this.draggable){
32447 this.dd = this.dynamic ?
32448 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
32449 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
32455 * @event beforeresize
32456 * Fired before resize is allowed. Set enabled to false to cancel resize.
32457 * @param {Roo.Resizable} this
32458 * @param {Roo.EventObject} e The mousedown event
32460 "beforeresize" : true,
32463 * Fired a resizing.
32464 * @param {Roo.Resizable} this
32465 * @param {Number} x The new x position
32466 * @param {Number} y The new y position
32467 * @param {Number} w The new w width
32468 * @param {Number} h The new h hight
32469 * @param {Roo.EventObject} e The mouseup event
32474 * Fired after a resize.
32475 * @param {Roo.Resizable} this
32476 * @param {Number} width The new width
32477 * @param {Number} height The new height
32478 * @param {Roo.EventObject} e The mouseup event
32483 if(this.width !== null && this.height !== null){
32484 this.resizeTo(this.width, this.height);
32486 this.updateChildSize();
32489 this.el.dom.style.zoom = 1;
32491 Roo.Resizable.superclass.constructor.call(this);
32494 Roo.extend(Roo.Resizable, Roo.util.Observable, {
32495 resizeChild : false,
32496 adjustments : [0, 0],
32506 multiDirectional : false,
32507 disableTrackOver : false,
32508 easing : 'easeOutStrong',
32509 widthIncrement : 0,
32510 heightIncrement : 0,
32514 preserveRatio : false,
32515 transparent: false,
32521 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
32523 constrainTo: undefined,
32525 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
32527 resizeRegion: undefined,
32531 * Perform a manual resize
32532 * @param {Number} width
32533 * @param {Number} height
32535 resizeTo : function(width, height){
32536 this.el.setSize(width, height);
32537 this.updateChildSize();
32538 this.fireEvent("resize", this, width, height, null);
32542 startSizing : function(e, handle){
32543 this.fireEvent("beforeresize", this, e);
32544 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
32547 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
32548 this.overlay.unselectable();
32549 this.overlay.enableDisplayMode("block");
32550 this.overlay.on("mousemove", this.onMouseMove, this);
32551 this.overlay.on("mouseup", this.onMouseUp, this);
32553 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
32555 this.resizing = true;
32556 this.startBox = this.el.getBox();
32557 this.startPoint = e.getXY();
32558 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
32559 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
32561 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32562 this.overlay.show();
32564 if(this.constrainTo) {
32565 var ct = Roo.get(this.constrainTo);
32566 this.resizeRegion = ct.getRegion().adjust(
32567 ct.getFrameWidth('t'),
32568 ct.getFrameWidth('l'),
32569 -ct.getFrameWidth('b'),
32570 -ct.getFrameWidth('r')
32574 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
32576 this.proxy.setBox(this.startBox);
32578 this.proxy.setStyle('visibility', 'visible');
32584 onMouseDown : function(handle, e){
32587 this.activeHandle = handle;
32588 this.startSizing(e, handle);
32593 onMouseUp : function(e){
32594 var size = this.resizeElement();
32595 this.resizing = false;
32597 this.overlay.hide();
32599 this.fireEvent("resize", this, size.width, size.height, e);
32603 updateChildSize : function(){
32605 if(this.resizeChild){
32607 var child = this.resizeChild;
32608 var adj = this.adjustments;
32609 if(el.dom.offsetWidth){
32610 var b = el.getSize(true);
32611 child.setSize(b.width+adj[0], b.height+adj[1]);
32613 // Second call here for IE
32614 // The first call enables instant resizing and
32615 // the second call corrects scroll bars if they
32618 setTimeout(function(){
32619 if(el.dom.offsetWidth){
32620 var b = el.getSize(true);
32621 child.setSize(b.width+adj[0], b.height+adj[1]);
32629 snap : function(value, inc, min){
32630 if(!inc || !value) {
32633 var newValue = value;
32634 var m = value % inc;
32637 newValue = value + (inc-m);
32639 newValue = value - m;
32642 return Math.max(min, newValue);
32646 resizeElement : function(){
32647 var box = this.proxy.getBox();
32648 if(this.updateBox){
32649 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
32651 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
32653 this.updateChildSize();
32661 constrain : function(v, diff, m, mx){
32664 }else if(v - diff > mx){
32671 onMouseMove : function(e){
32674 try{// try catch so if something goes wrong the user doesn't get hung
32676 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
32680 //var curXY = this.startPoint;
32681 var curSize = this.curSize || this.startBox;
32682 var x = this.startBox.x, y = this.startBox.y;
32683 var ox = x, oy = y;
32684 var w = curSize.width, h = curSize.height;
32685 var ow = w, oh = h;
32686 var mw = this.minWidth, mh = this.minHeight;
32687 var mxw = this.maxWidth, mxh = this.maxHeight;
32688 var wi = this.widthIncrement;
32689 var hi = this.heightIncrement;
32691 var eventXY = e.getXY();
32692 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
32693 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
32695 var pos = this.activeHandle.position;
32700 w = Math.min(Math.max(mw, w), mxw);
32705 h = Math.min(Math.max(mh, h), mxh);
32710 w = Math.min(Math.max(mw, w), mxw);
32711 h = Math.min(Math.max(mh, h), mxh);
32714 diffY = this.constrain(h, diffY, mh, mxh);
32721 var adiffX = Math.abs(diffX);
32722 var sub = (adiffX % wi); // how much
32723 if (sub > (wi/2)) { // far enough to snap
32724 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
32726 // remove difference..
32727 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
32731 x = Math.max(this.minX, x);
32734 diffX = this.constrain(w, diffX, mw, mxw);
32740 w = Math.min(Math.max(mw, w), mxw);
32741 diffY = this.constrain(h, diffY, mh, mxh);
32746 diffX = this.constrain(w, diffX, mw, mxw);
32747 diffY = this.constrain(h, diffY, mh, mxh);
32754 diffX = this.constrain(w, diffX, mw, mxw);
32756 h = Math.min(Math.max(mh, h), mxh);
32762 var sw = this.snap(w, wi, mw);
32763 var sh = this.snap(h, hi, mh);
32764 if(sw != w || sh != h){
32787 if(this.preserveRatio){
32792 h = Math.min(Math.max(mh, h), mxh);
32797 w = Math.min(Math.max(mw, w), mxw);
32802 w = Math.min(Math.max(mw, w), mxw);
32808 w = Math.min(Math.max(mw, w), mxw);
32814 h = Math.min(Math.max(mh, h), mxh);
32822 h = Math.min(Math.max(mh, h), mxh);
32832 h = Math.min(Math.max(mh, h), mxh);
32840 if (pos == 'hdrag') {
32843 this.proxy.setBounds(x, y, w, h);
32845 this.resizeElement();
32849 this.fireEvent("resizing", this, x, y, w, h, e);
32853 handleOver : function(){
32855 this.el.addClass("x-resizable-over");
32860 handleOut : function(){
32861 if(!this.resizing){
32862 this.el.removeClass("x-resizable-over");
32867 * Returns the element this component is bound to.
32868 * @return {Roo.Element}
32870 getEl : function(){
32875 * Returns the resizeChild element (or null).
32876 * @return {Roo.Element}
32878 getResizeChild : function(){
32879 return this.resizeChild;
32881 groupHandler : function()
32886 * Destroys this resizable. If the element was wrapped and
32887 * removeEl is not true then the element remains.
32888 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32890 destroy : function(removeEl){
32891 this.proxy.remove();
32893 this.overlay.removeAllListeners();
32894 this.overlay.remove();
32896 var ps = Roo.Resizable.positions;
32898 if(typeof ps[k] != "function" && this[ps[k]]){
32899 var h = this[ps[k]];
32900 h.el.removeAllListeners();
32905 this.el.update("");
32912 // hash to map config positions to true positions
32913 Roo.Resizable.positions = {
32914 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
32919 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
32921 // only initialize the template if resizable is used
32922 var tpl = Roo.DomHelper.createTemplate(
32923 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
32926 Roo.Resizable.Handle.prototype.tpl = tpl;
32928 this.position = pos;
32930 // show north drag fro topdra
32931 var handlepos = pos == 'hdrag' ? 'north' : pos;
32933 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
32934 if (pos == 'hdrag') {
32935 this.el.setStyle('cursor', 'pointer');
32937 this.el.unselectable();
32939 this.el.setOpacity(0);
32941 this.el.on("mousedown", this.onMouseDown, this);
32942 if(!disableTrackOver){
32943 this.el.on("mouseover", this.onMouseOver, this);
32944 this.el.on("mouseout", this.onMouseOut, this);
32949 Roo.Resizable.Handle.prototype = {
32950 afterResize : function(rz){
32955 onMouseDown : function(e){
32956 this.rz.onMouseDown(this, e);
32959 onMouseOver : function(e){
32960 this.rz.handleOver(this, e);
32963 onMouseOut : function(e){
32964 this.rz.handleOut(this, e);
32968 * Ext JS Library 1.1.1
32969 * Copyright(c) 2006-2007, Ext JS, LLC.
32971 * Originally Released Under LGPL - original licence link has changed is not relivant.
32974 * <script type="text/javascript">
32978 * @class Roo.Editor
32979 * @extends Roo.Component
32980 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
32982 * Create a new Editor
32983 * @param {Roo.form.Field} field The Field object (or descendant)
32984 * @param {Object} config The config object
32986 Roo.Editor = function(field, config){
32987 Roo.Editor.superclass.constructor.call(this, config);
32988 this.field = field;
32991 * @event beforestartedit
32992 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
32993 * false from the handler of this event.
32994 * @param {Editor} this
32995 * @param {Roo.Element} boundEl The underlying element bound to this editor
32996 * @param {Mixed} value The field value being set
32998 "beforestartedit" : true,
33001 * Fires when this editor is displayed
33002 * @param {Roo.Element} boundEl The underlying element bound to this editor
33003 * @param {Mixed} value The starting field value
33005 "startedit" : true,
33007 * @event beforecomplete
33008 * Fires after a change has been made to the field, but before the change is reflected in the underlying
33009 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
33010 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
33011 * event will not fire since no edit actually occurred.
33012 * @param {Editor} this
33013 * @param {Mixed} value The current field value
33014 * @param {Mixed} startValue The original field value
33016 "beforecomplete" : true,
33019 * Fires after editing is complete and any changed value has been written to the underlying field.
33020 * @param {Editor} this
33021 * @param {Mixed} value The current field value
33022 * @param {Mixed} startValue The original field value
33026 * @event specialkey
33027 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
33028 * {@link Roo.EventObject#getKey} to determine which key was pressed.
33029 * @param {Roo.form.Field} this
33030 * @param {Roo.EventObject} e The event object
33032 "specialkey" : true
33036 Roo.extend(Roo.Editor, Roo.Component, {
33038 * @cfg {Boolean/String} autosize
33039 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
33040 * or "height" to adopt the height only (defaults to false)
33043 * @cfg {Boolean} revertInvalid
33044 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
33045 * validation fails (defaults to true)
33048 * @cfg {Boolean} ignoreNoChange
33049 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
33050 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
33051 * will never be ignored.
33054 * @cfg {Boolean} hideEl
33055 * False to keep the bound element visible while the editor is displayed (defaults to true)
33058 * @cfg {Mixed} value
33059 * The data value of the underlying field (defaults to "")
33063 * @cfg {String} alignment
33064 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
33068 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
33069 * for bottom-right shadow (defaults to "frame")
33073 * @cfg {Boolean} constrain True to constrain the editor to the viewport
33077 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
33079 completeOnEnter : false,
33081 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
33083 cancelOnEsc : false,
33085 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
33090 onRender : function(ct, position){
33091 this.el = new Roo.Layer({
33092 shadow: this.shadow,
33098 constrain: this.constrain
33100 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
33101 if(this.field.msgTarget != 'title'){
33102 this.field.msgTarget = 'qtip';
33104 this.field.render(this.el);
33106 this.field.el.dom.setAttribute('autocomplete', 'off');
33108 this.field.on("specialkey", this.onSpecialKey, this);
33109 if(this.swallowKeys){
33110 this.field.el.swallowEvent(['keydown','keypress']);
33113 this.field.on("blur", this.onBlur, this);
33114 if(this.field.grow){
33115 this.field.on("autosize", this.el.sync, this.el, {delay:1});
33119 onSpecialKey : function(field, e)
33121 //Roo.log('editor onSpecialKey');
33122 if(this.completeOnEnter && e.getKey() == e.ENTER){
33124 this.completeEdit();
33127 // do not fire special key otherwise it might hide close the editor...
33128 if(e.getKey() == e.ENTER){
33131 if(this.cancelOnEsc && e.getKey() == e.ESC){
33135 this.fireEvent('specialkey', field, e);
33140 * Starts the editing process and shows the editor.
33141 * @param {String/HTMLElement/Element} el The element to edit
33142 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
33143 * to the innerHTML of el.
33145 startEdit : function(el, value){
33147 this.completeEdit();
33149 this.boundEl = Roo.get(el);
33150 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
33151 if(!this.rendered){
33152 this.render(this.parentEl || document.body);
33154 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
33157 this.startValue = v;
33158 this.field.setValue(v);
33160 var sz = this.boundEl.getSize();
33161 switch(this.autoSize){
33163 this.setSize(sz.width, "");
33166 this.setSize("", sz.height);
33169 this.setSize(sz.width, sz.height);
33172 this.el.alignTo(this.boundEl, this.alignment);
33173 this.editing = true;
33175 Roo.QuickTips.disable();
33181 * Sets the height and width of this editor.
33182 * @param {Number} width The new width
33183 * @param {Number} height The new height
33185 setSize : function(w, h){
33186 this.field.setSize(w, h);
33193 * Realigns the editor to the bound field based on the current alignment config value.
33195 realign : function(){
33196 this.el.alignTo(this.boundEl, this.alignment);
33200 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
33201 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
33203 completeEdit : function(remainVisible){
33207 var v = this.getValue();
33208 if(this.revertInvalid !== false && !this.field.isValid()){
33209 v = this.startValue;
33210 this.cancelEdit(true);
33212 if(String(v) === String(this.startValue) && this.ignoreNoChange){
33213 this.editing = false;
33217 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
33218 this.editing = false;
33219 if(this.updateEl && this.boundEl){
33220 this.boundEl.update(v);
33222 if(remainVisible !== true){
33225 this.fireEvent("complete", this, v, this.startValue);
33230 onShow : function(){
33232 if(this.hideEl !== false){
33233 this.boundEl.hide();
33236 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
33237 this.fixIEFocus = true;
33238 this.deferredFocus.defer(50, this);
33240 this.field.focus();
33242 this.fireEvent("startedit", this.boundEl, this.startValue);
33245 deferredFocus : function(){
33247 this.field.focus();
33252 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
33253 * reverted to the original starting value.
33254 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
33255 * cancel (defaults to false)
33257 cancelEdit : function(remainVisible){
33259 this.setValue(this.startValue);
33260 if(remainVisible !== true){
33267 onBlur : function(){
33268 if(this.allowBlur !== true && this.editing){
33269 this.completeEdit();
33274 onHide : function(){
33276 this.completeEdit();
33280 if(this.field.collapse){
33281 this.field.collapse();
33284 if(this.hideEl !== false){
33285 this.boundEl.show();
33288 Roo.QuickTips.enable();
33293 * Sets the data value of the editor
33294 * @param {Mixed} value Any valid value supported by the underlying field
33296 setValue : function(v){
33297 this.field.setValue(v);
33301 * Gets the data value of the editor
33302 * @return {Mixed} The data value
33304 getValue : function(){
33305 return this.field.getValue();
33309 * Ext JS Library 1.1.1
33310 * Copyright(c) 2006-2007, Ext JS, LLC.
33312 * Originally Released Under LGPL - original licence link has changed is not relivant.
33315 * <script type="text/javascript">
33319 * @class Roo.BasicDialog
33320 * @extends Roo.util.Observable
33321 * @parent none builder
33322 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
33324 var dlg = new Roo.BasicDialog("my-dlg", {
33333 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
33334 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
33335 dlg.addButton('Cancel', dlg.hide, dlg);
33338 <b>A Dialog should always be a direct child of the body element.</b>
33339 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
33340 * @cfg {String} title Default text to display in the title bar (defaults to null)
33341 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
33342 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
33343 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
33344 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
33345 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
33346 * (defaults to null with no animation)
33347 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
33348 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
33349 * property for valid values (defaults to 'all')
33350 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
33351 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
33352 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
33353 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
33354 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
33355 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
33356 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
33357 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
33358 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
33359 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
33360 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
33361 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
33362 * draggable = true (defaults to false)
33363 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
33364 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
33365 * shadow (defaults to false)
33366 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
33367 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
33368 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
33369 * @cfg {Array} buttons Array of buttons
33370 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
33372 * Create a new BasicDialog.
33373 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
33374 * @param {Object} config Configuration options
33376 Roo.BasicDialog = function(el, config){
33377 this.el = Roo.get(el);
33378 var dh = Roo.DomHelper;
33379 if(!this.el && config && config.autoCreate){
33380 if(typeof config.autoCreate == "object"){
33381 if(!config.autoCreate.id){
33382 config.autoCreate.id = el;
33384 this.el = dh.append(document.body,
33385 config.autoCreate, true);
33387 this.el = dh.append(document.body,
33388 {tag: "div", id: el, style:'visibility:hidden;'}, true);
33392 el.setDisplayed(true);
33393 el.hide = this.hideAction;
33395 el.addClass("x-dlg");
33397 Roo.apply(this, config);
33399 this.proxy = el.createProxy("x-dlg-proxy");
33400 this.proxy.hide = this.hideAction;
33401 this.proxy.setOpacity(.5);
33405 el.setWidth(config.width);
33408 el.setHeight(config.height);
33410 this.size = el.getSize();
33411 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
33412 this.xy = [config.x,config.y];
33414 this.xy = el.getCenterXY(true);
33416 /** The header element @type Roo.Element */
33417 this.header = el.child("> .x-dlg-hd");
33418 /** The body element @type Roo.Element */
33419 this.body = el.child("> .x-dlg-bd");
33420 /** The footer element @type Roo.Element */
33421 this.footer = el.child("> .x-dlg-ft");
33424 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
33427 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
33430 this.header.unselectable();
33432 this.header.update(this.title);
33434 // this element allows the dialog to be focused for keyboard event
33435 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
33436 this.focusEl.swallowEvent("click", true);
33438 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
33440 // wrap the body and footer for special rendering
33441 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
33443 this.bwrap.dom.appendChild(this.footer.dom);
33446 this.bg = this.el.createChild({
33447 tag: "div", cls:"x-dlg-bg",
33448 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
33450 this.centerBg = this.bg.child("div.x-dlg-bg-center");
33453 if(this.autoScroll !== false && !this.autoTabs){
33454 this.body.setStyle("overflow", "auto");
33457 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
33459 if(this.closable !== false){
33460 this.el.addClass("x-dlg-closable");
33461 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
33462 this.close.on("click", this.closeClick, this);
33463 this.close.addClassOnOver("x-dlg-close-over");
33465 if(this.collapsible !== false){
33466 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
33467 this.collapseBtn.on("click", this.collapseClick, this);
33468 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
33469 this.header.on("dblclick", this.collapseClick, this);
33471 if(this.resizable !== false){
33472 this.el.addClass("x-dlg-resizable");
33473 this.resizer = new Roo.Resizable(el, {
33474 minWidth: this.minWidth || 80,
33475 minHeight:this.minHeight || 80,
33476 handles: this.resizeHandles || "all",
33479 this.resizer.on("beforeresize", this.beforeResize, this);
33480 this.resizer.on("resize", this.onResize, this);
33482 if(this.draggable !== false){
33483 el.addClass("x-dlg-draggable");
33484 if (!this.proxyDrag) {
33485 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
33488 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
33490 dd.setHandleElId(this.header.id);
33491 dd.endDrag = this.endMove.createDelegate(this);
33492 dd.startDrag = this.startMove.createDelegate(this);
33493 dd.onDrag = this.onDrag.createDelegate(this);
33498 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
33499 this.mask.enableDisplayMode("block");
33501 this.el.addClass("x-dlg-modal");
33504 this.shadow = new Roo.Shadow({
33505 mode : typeof this.shadow == "string" ? this.shadow : "sides",
33506 offset : this.shadowOffset
33509 this.shadowOffset = 0;
33511 if(Roo.useShims && this.shim !== false){
33512 this.shim = this.el.createShim();
33513 this.shim.hide = this.hideAction;
33521 if (this.buttons) {
33522 var bts= this.buttons;
33524 Roo.each(bts, function(b) {
33533 * Fires when a key is pressed
33534 * @param {Roo.BasicDialog} this
33535 * @param {Roo.EventObject} e
33540 * Fires when this dialog is moved by the user.
33541 * @param {Roo.BasicDialog} this
33542 * @param {Number} x The new page X
33543 * @param {Number} y The new page Y
33548 * Fires when this dialog is resized by the user.
33549 * @param {Roo.BasicDialog} this
33550 * @param {Number} width The new width
33551 * @param {Number} height The new height
33555 * @event beforehide
33556 * Fires before this dialog is hidden.
33557 * @param {Roo.BasicDialog} this
33559 "beforehide" : true,
33562 * Fires when this dialog is hidden.
33563 * @param {Roo.BasicDialog} this
33567 * @event beforeshow
33568 * Fires before this dialog is shown.
33569 * @param {Roo.BasicDialog} this
33571 "beforeshow" : true,
33574 * Fires when this dialog is shown.
33575 * @param {Roo.BasicDialog} this
33579 el.on("keydown", this.onKeyDown, this);
33580 el.on("mousedown", this.toFront, this);
33581 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
33583 Roo.DialogManager.register(this);
33584 Roo.BasicDialog.superclass.constructor.call(this);
33587 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
33588 shadowOffset: Roo.isIE ? 6 : 5,
33591 minButtonWidth: 75,
33592 defaultButton: null,
33593 buttonAlign: "right",
33598 * Sets the dialog title text
33599 * @param {String} text The title text to display
33600 * @return {Roo.BasicDialog} this
33602 setTitle : function(text){
33603 this.header.update(text);
33608 closeClick : function(){
33613 collapseClick : function(){
33614 this[this.collapsed ? "expand" : "collapse"]();
33618 * Collapses the dialog to its minimized state (only the title bar is visible).
33619 * Equivalent to the user clicking the collapse dialog button.
33621 collapse : function(){
33622 if(!this.collapsed){
33623 this.collapsed = true;
33624 this.el.addClass("x-dlg-collapsed");
33625 this.restoreHeight = this.el.getHeight();
33626 this.resizeTo(this.el.getWidth(), this.header.getHeight());
33631 * Expands a collapsed dialog back to its normal state. Equivalent to the user
33632 * clicking the expand dialog button.
33634 expand : function(){
33635 if(this.collapsed){
33636 this.collapsed = false;
33637 this.el.removeClass("x-dlg-collapsed");
33638 this.resizeTo(this.el.getWidth(), this.restoreHeight);
33643 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
33644 * @return {Roo.TabPanel} The tabs component
33646 initTabs : function(){
33647 var tabs = this.getTabs();
33648 while(tabs.getTab(0)){
33651 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
33653 tabs.addTab(Roo.id(dom), dom.title);
33661 beforeResize : function(){
33662 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
33666 onResize : function(){
33667 this.refreshSize();
33668 this.syncBodyHeight();
33669 this.adjustAssets();
33671 this.fireEvent("resize", this, this.size.width, this.size.height);
33675 onKeyDown : function(e){
33676 if(this.isVisible()){
33677 this.fireEvent("keydown", this, e);
33682 * Resizes the dialog.
33683 * @param {Number} width
33684 * @param {Number} height
33685 * @return {Roo.BasicDialog} this
33687 resizeTo : function(width, height){
33688 this.el.setSize(width, height);
33689 this.size = {width: width, height: height};
33690 this.syncBodyHeight();
33691 if(this.fixedcenter){
33694 if(this.isVisible()){
33695 this.constrainXY();
33696 this.adjustAssets();
33698 this.fireEvent("resize", this, width, height);
33704 * Resizes the dialog to fit the specified content size.
33705 * @param {Number} width
33706 * @param {Number} height
33707 * @return {Roo.BasicDialog} this
33709 setContentSize : function(w, h){
33710 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
33711 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
33712 //if(!this.el.isBorderBox()){
33713 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
33714 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
33717 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
33718 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
33720 this.resizeTo(w, h);
33725 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
33726 * executed in response to a particular key being pressed while the dialog is active.
33727 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
33728 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
33729 * @param {Function} fn The function to call
33730 * @param {Object} scope (optional) The scope of the function
33731 * @return {Roo.BasicDialog} this
33733 addKeyListener : function(key, fn, scope){
33734 var keyCode, shift, ctrl, alt;
33735 if(typeof key == "object" && !(key instanceof Array)){
33736 keyCode = key["key"];
33737 shift = key["shift"];
33738 ctrl = key["ctrl"];
33743 var handler = function(dlg, e){
33744 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
33745 var k = e.getKey();
33746 if(keyCode instanceof Array){
33747 for(var i = 0, len = keyCode.length; i < len; i++){
33748 if(keyCode[i] == k){
33749 fn.call(scope || window, dlg, k, e);
33755 fn.call(scope || window, dlg, k, e);
33760 this.on("keydown", handler);
33765 * Returns the TabPanel component (creates it if it doesn't exist).
33766 * Note: If you wish to simply check for the existence of tabs without creating them,
33767 * check for a null 'tabs' property.
33768 * @return {Roo.TabPanel} The tabs component
33770 getTabs : function(){
33772 this.el.addClass("x-dlg-auto-tabs");
33773 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
33774 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
33780 * Adds a button to the footer section of the dialog.
33781 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
33782 * object or a valid Roo.DomHelper element config
33783 * @param {Function} handler The function called when the button is clicked
33784 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
33785 * @return {Roo.Button} The new button
33787 addButton : function(config, handler, scope){
33788 var dh = Roo.DomHelper;
33790 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
33792 if(!this.btnContainer){
33793 var tb = this.footer.createChild({
33795 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
33796 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
33798 this.btnContainer = tb.firstChild.firstChild.firstChild;
33803 minWidth: this.minButtonWidth,
33806 if(typeof config == "string"){
33807 bconfig.text = config;
33810 bconfig.dhconfig = config;
33812 Roo.apply(bconfig, config);
33816 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
33817 bconfig.position = Math.max(0, bconfig.position);
33818 fc = this.btnContainer.childNodes[bconfig.position];
33821 var btn = new Roo.Button(
33823 this.btnContainer.insertBefore(document.createElement("td"),fc)
33824 : this.btnContainer.appendChild(document.createElement("td")),
33825 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
33828 this.syncBodyHeight();
33831 * Array of all the buttons that have been added to this dialog via addButton
33836 this.buttons.push(btn);
33841 * Sets the default button to be focused when the dialog is displayed.
33842 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
33843 * @return {Roo.BasicDialog} this
33845 setDefaultButton : function(btn){
33846 this.defaultButton = btn;
33851 getHeaderFooterHeight : function(safe){
33854 height += this.header.getHeight();
33857 var fm = this.footer.getMargins();
33858 height += (this.footer.getHeight()+fm.top+fm.bottom);
33860 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
33861 height += this.centerBg.getPadding("tb");
33866 syncBodyHeight : function()
33868 var bd = this.body, // the text
33869 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
33871 var height = this.size.height - this.getHeaderFooterHeight(false);
33872 bd.setHeight(height-bd.getMargins("tb"));
33873 var hh = this.header.getHeight();
33874 var h = this.size.height-hh;
33877 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
33878 bw.setHeight(h-cb.getPadding("tb"));
33880 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
33881 bd.setWidth(bw.getWidth(true));
33883 this.tabs.syncHeight();
33885 this.tabs.el.repaint();
33891 * Restores the previous state of the dialog if Roo.state is configured.
33892 * @return {Roo.BasicDialog} this
33894 restoreState : function(){
33895 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
33896 if(box && box.width){
33897 this.xy = [box.x, box.y];
33898 this.resizeTo(box.width, box.height);
33904 beforeShow : function(){
33906 if(this.fixedcenter){
33907 this.xy = this.el.getCenterXY(true);
33910 Roo.get(document.body).addClass("x-body-masked");
33911 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
33914 this.constrainXY();
33918 animShow : function(){
33919 var b = Roo.get(this.animateTarget).getBox();
33920 this.proxy.setSize(b.width, b.height);
33921 this.proxy.setLocation(b.x, b.y);
33923 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
33924 true, .35, this.showEl.createDelegate(this));
33928 * Shows the dialog.
33929 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
33930 * @return {Roo.BasicDialog} this
33932 show : function(animateTarget){
33933 if (this.fireEvent("beforeshow", this) === false){
33936 if(this.syncHeightBeforeShow){
33937 this.syncBodyHeight();
33938 }else if(this.firstShow){
33939 this.firstShow = false;
33940 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
33942 this.animateTarget = animateTarget || this.animateTarget;
33943 if(!this.el.isVisible()){
33945 if(this.animateTarget && Roo.get(this.animateTarget)){
33955 showEl : function(){
33957 this.el.setXY(this.xy);
33959 this.adjustAssets(true);
33962 // IE peekaboo bug - fix found by Dave Fenwick
33966 this.fireEvent("show", this);
33970 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
33971 * dialog itself will receive focus.
33973 focus : function(){
33974 if(this.defaultButton){
33975 this.defaultButton.focus();
33977 this.focusEl.focus();
33982 constrainXY : function(){
33983 if(this.constraintoviewport !== false){
33984 if(!this.viewSize){
33985 if(this.container){
33986 var s = this.container.getSize();
33987 this.viewSize = [s.width, s.height];
33989 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
33992 var s = Roo.get(this.container||document).getScroll();
33994 var x = this.xy[0], y = this.xy[1];
33995 var w = this.size.width, h = this.size.height;
33996 var vw = this.viewSize[0], vh = this.viewSize[1];
33997 // only move it if it needs it
33999 // first validate right/bottom
34000 if(x + w > vw+s.left){
34004 if(y + h > vh+s.top){
34008 // then make sure top/left isn't negative
34020 if(this.isVisible()){
34021 this.el.setLocation(x, y);
34022 this.adjustAssets();
34029 onDrag : function(){
34030 if(!this.proxyDrag){
34031 this.xy = this.el.getXY();
34032 this.adjustAssets();
34037 adjustAssets : function(doShow){
34038 var x = this.xy[0], y = this.xy[1];
34039 var w = this.size.width, h = this.size.height;
34040 if(doShow === true){
34042 this.shadow.show(this.el);
34048 if(this.shadow && this.shadow.isVisible()){
34049 this.shadow.show(this.el);
34051 if(this.shim && this.shim.isVisible()){
34052 this.shim.setBounds(x, y, w, h);
34057 adjustViewport : function(w, h){
34059 w = Roo.lib.Dom.getViewWidth();
34060 h = Roo.lib.Dom.getViewHeight();
34063 this.viewSize = [w, h];
34064 if(this.modal && this.mask.isVisible()){
34065 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
34066 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34068 if(this.isVisible()){
34069 this.constrainXY();
34074 * Destroys this dialog and all its supporting elements (including any tabs, shim,
34075 * shadow, proxy, mask, etc.) Also removes all event listeners.
34076 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
34078 destroy : function(removeEl){
34079 if(this.isVisible()){
34080 this.animateTarget = null;
34083 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
34085 this.tabs.destroy(removeEl);
34098 for(var i = 0, len = this.buttons.length; i < len; i++){
34099 this.buttons[i].destroy();
34102 this.el.removeAllListeners();
34103 if(removeEl === true){
34104 this.el.update("");
34107 Roo.DialogManager.unregister(this);
34111 startMove : function(){
34112 if(this.proxyDrag){
34115 if(this.constraintoviewport !== false){
34116 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
34121 endMove : function(){
34122 if(!this.proxyDrag){
34123 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
34125 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
34128 this.refreshSize();
34129 this.adjustAssets();
34131 this.fireEvent("move", this, this.xy[0], this.xy[1]);
34135 * Brings this dialog to the front of any other visible dialogs
34136 * @return {Roo.BasicDialog} this
34138 toFront : function(){
34139 Roo.DialogManager.bringToFront(this);
34144 * Sends this dialog to the back (under) of any other visible dialogs
34145 * @return {Roo.BasicDialog} this
34147 toBack : function(){
34148 Roo.DialogManager.sendToBack(this);
34153 * Centers this dialog in the viewport
34154 * @return {Roo.BasicDialog} this
34156 center : function(){
34157 var xy = this.el.getCenterXY(true);
34158 this.moveTo(xy[0], xy[1]);
34163 * Moves the dialog's top-left corner to the specified point
34164 * @param {Number} x
34165 * @param {Number} y
34166 * @return {Roo.BasicDialog} this
34168 moveTo : function(x, y){
34170 if(this.isVisible()){
34171 this.el.setXY(this.xy);
34172 this.adjustAssets();
34178 * Aligns the dialog to the specified element
34179 * @param {String/HTMLElement/Roo.Element} element The element to align to.
34180 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
34181 * @param {Array} offsets (optional) Offset the positioning by [x, y]
34182 * @return {Roo.BasicDialog} this
34184 alignTo : function(element, position, offsets){
34185 this.xy = this.el.getAlignToXY(element, position, offsets);
34186 if(this.isVisible()){
34187 this.el.setXY(this.xy);
34188 this.adjustAssets();
34194 * Anchors an element to another element and realigns it when the window is resized.
34195 * @param {String/HTMLElement/Roo.Element} element The element to align to.
34196 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
34197 * @param {Array} offsets (optional) Offset the positioning by [x, y]
34198 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
34199 * is a number, it is used as the buffer delay (defaults to 50ms).
34200 * @return {Roo.BasicDialog} this
34202 anchorTo : function(el, alignment, offsets, monitorScroll){
34203 var action = function(){
34204 this.alignTo(el, alignment, offsets);
34206 Roo.EventManager.onWindowResize(action, this);
34207 var tm = typeof monitorScroll;
34208 if(tm != 'undefined'){
34209 Roo.EventManager.on(window, 'scroll', action, this,
34210 {buffer: tm == 'number' ? monitorScroll : 50});
34217 * Returns true if the dialog is visible
34218 * @return {Boolean}
34220 isVisible : function(){
34221 return this.el.isVisible();
34225 animHide : function(callback){
34226 var b = Roo.get(this.animateTarget).getBox();
34228 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
34230 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
34231 this.hideEl.createDelegate(this, [callback]));
34235 * Hides the dialog.
34236 * @param {Function} callback (optional) Function to call when the dialog is hidden
34237 * @return {Roo.BasicDialog} this
34239 hide : function(callback){
34240 if (this.fireEvent("beforehide", this) === false){
34244 this.shadow.hide();
34249 // sometimes animateTarget seems to get set.. causing problems...
34250 // this just double checks..
34251 if(this.animateTarget && Roo.get(this.animateTarget)) {
34252 this.animHide(callback);
34255 this.hideEl(callback);
34261 hideEl : function(callback){
34265 Roo.get(document.body).removeClass("x-body-masked");
34267 this.fireEvent("hide", this);
34268 if(typeof callback == "function"){
34274 hideAction : function(){
34275 this.setLeft("-10000px");
34276 this.setTop("-10000px");
34277 this.setStyle("visibility", "hidden");
34281 refreshSize : function(){
34282 this.size = this.el.getSize();
34283 this.xy = this.el.getXY();
34284 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
34288 // z-index is managed by the DialogManager and may be overwritten at any time
34289 setZIndex : function(index){
34291 this.mask.setStyle("z-index", index);
34294 this.shim.setStyle("z-index", ++index);
34297 this.shadow.setZIndex(++index);
34299 this.el.setStyle("z-index", ++index);
34301 this.proxy.setStyle("z-index", ++index);
34304 this.resizer.proxy.setStyle("z-index", ++index);
34307 this.lastZIndex = index;
34311 * Returns the element for this dialog
34312 * @return {Roo.Element} The underlying dialog Element
34314 getEl : function(){
34320 * @class Roo.DialogManager
34321 * Provides global access to BasicDialogs that have been created and
34322 * support for z-indexing (layering) multiple open dialogs.
34324 Roo.DialogManager = function(){
34326 var accessList = [];
34330 var sortDialogs = function(d1, d2){
34331 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
34335 var orderDialogs = function(){
34336 accessList.sort(sortDialogs);
34337 var seed = Roo.DialogManager.zseed;
34338 for(var i = 0, len = accessList.length; i < len; i++){
34339 var dlg = accessList[i];
34341 dlg.setZIndex(seed + (i*10));
34348 * The starting z-index for BasicDialogs (defaults to 9000)
34349 * @type Number The z-index value
34354 register : function(dlg){
34355 list[dlg.id] = dlg;
34356 accessList.push(dlg);
34360 unregister : function(dlg){
34361 delete list[dlg.id];
34364 if(!accessList.indexOf){
34365 for( i = 0, len = accessList.length; i < len; i++){
34366 if(accessList[i] == dlg){
34367 accessList.splice(i, 1);
34372 i = accessList.indexOf(dlg);
34374 accessList.splice(i, 1);
34380 * Gets a registered dialog by id
34381 * @param {String/Object} id The id of the dialog or a dialog
34382 * @return {Roo.BasicDialog} this
34384 get : function(id){
34385 return typeof id == "object" ? id : list[id];
34389 * Brings the specified dialog to the front
34390 * @param {String/Object} dlg The id of the dialog or a dialog
34391 * @return {Roo.BasicDialog} this
34393 bringToFront : function(dlg){
34394 dlg = this.get(dlg);
34397 dlg._lastAccess = new Date().getTime();
34404 * Sends the specified dialog to the back
34405 * @param {String/Object} dlg The id of the dialog or a dialog
34406 * @return {Roo.BasicDialog} this
34408 sendToBack : function(dlg){
34409 dlg = this.get(dlg);
34410 dlg._lastAccess = -(new Date().getTime());
34416 * Hides all dialogs
34418 hideAll : function(){
34419 for(var id in list){
34420 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
34429 * @class Roo.LayoutDialog
34430 * @extends Roo.BasicDialog
34431 * @children Roo.ContentPanel
34432 * @parent builder none
34433 * Dialog which provides adjustments for working with a layout in a Dialog.
34434 * Add your necessary layout config options to the dialog's config.<br>
34435 * Example usage (including a nested layout):
34438 dialog = new Roo.LayoutDialog("download-dlg", {
34447 // layout config merges with the dialog config
34449 tabPosition: "top",
34450 alwaysShowTabs: true
34453 dialog.addKeyListener(27, dialog.hide, dialog);
34454 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
34455 dialog.addButton("Build It!", this.getDownload, this);
34457 // we can even add nested layouts
34458 var innerLayout = new Roo.BorderLayout("dl-inner", {
34468 innerLayout.beginUpdate();
34469 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
34470 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
34471 innerLayout.endUpdate(true);
34473 var layout = dialog.getLayout();
34474 layout.beginUpdate();
34475 layout.add("center", new Roo.ContentPanel("standard-panel",
34476 {title: "Download the Source", fitToFrame:true}));
34477 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
34478 {title: "Build your own roo.js"}));
34479 layout.getRegion("center").showPanel(sp);
34480 layout.endUpdate();
34484 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
34485 * @param {Object} config configuration options
34487 Roo.LayoutDialog = function(el, cfg){
34490 if (typeof(cfg) == 'undefined') {
34491 config = Roo.apply({}, el);
34492 // not sure why we use documentElement here.. - it should always be body.
34493 // IE7 borks horribly if we use documentElement.
34494 // webkit also does not like documentElement - it creates a body element...
34495 el = Roo.get( document.body || document.documentElement ).createChild();
34496 //config.autoCreate = true;
34500 config.autoTabs = false;
34501 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
34502 this.body.setStyle({overflow:"hidden", position:"relative"});
34503 this.layout = new Roo.BorderLayout(this.body.dom, config);
34504 this.layout.monitorWindowResize = false;
34505 this.el.addClass("x-dlg-auto-layout");
34506 // fix case when center region overwrites center function
34507 this.center = Roo.BasicDialog.prototype.center;
34508 this.on("show", this.layout.layout, this.layout, true);
34509 if (config.items) {
34510 var xitems = config.items;
34511 delete config.items;
34512 Roo.each(xitems, this.addxtype, this);
34517 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
34521 * @cfg {Roo.LayoutRegion} east
34524 * @cfg {Roo.LayoutRegion} west
34527 * @cfg {Roo.LayoutRegion} south
34530 * @cfg {Roo.LayoutRegion} north
34533 * @cfg {Roo.LayoutRegion} center
34536 * @cfg {Roo.Button} buttons[] Bottom buttons..
34541 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
34544 endUpdate : function(){
34545 this.layout.endUpdate();
34549 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
34552 beginUpdate : function(){
34553 this.layout.beginUpdate();
34557 * Get the BorderLayout for this dialog
34558 * @return {Roo.BorderLayout}
34560 getLayout : function(){
34561 return this.layout;
34564 showEl : function(){
34565 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
34567 this.layout.layout();
34572 // Use the syncHeightBeforeShow config option to control this automatically
34573 syncBodyHeight : function(){
34574 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
34575 if(this.layout){this.layout.layout();}
34579 * Add an xtype element (actually adds to the layout.)
34580 * @return {Object} xdata xtype object data.
34583 addxtype : function(c) {
34584 return this.layout.addxtype(c);
34588 * Ext JS Library 1.1.1
34589 * Copyright(c) 2006-2007, Ext JS, LLC.
34591 * Originally Released Under LGPL - original licence link has changed is not relivant.
34594 * <script type="text/javascript">
34598 * @class Roo.MessageBox
34599 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
34603 Roo.Msg.alert('Status', 'Changes saved successfully.');
34605 // Prompt for user data:
34606 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
34608 // process text value...
34612 // Show a dialog using config options:
34614 title:'Save Changes?',
34615 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
34616 buttons: Roo.Msg.YESNOCANCEL,
34623 Roo.MessageBox = function(){
34624 var dlg, opt, mask, waitTimer;
34625 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
34626 var buttons, activeTextEl, bwidth;
34629 var handleButton = function(button){
34631 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
34635 var handleHide = function(){
34636 if(opt && opt.cls){
34637 dlg.el.removeClass(opt.cls);
34640 Roo.TaskMgr.stop(waitTimer);
34646 var updateButtons = function(b){
34649 buttons["ok"].hide();
34650 buttons["cancel"].hide();
34651 buttons["yes"].hide();
34652 buttons["no"].hide();
34653 dlg.footer.dom.style.display = 'none';
34656 dlg.footer.dom.style.display = '';
34657 for(var k in buttons){
34658 if(typeof buttons[k] != "function"){
34661 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
34662 width += buttons[k].el.getWidth()+15;
34672 var handleEsc = function(d, k, e){
34673 if(opt && opt.closable !== false){
34683 * Returns a reference to the underlying {@link Roo.BasicDialog} element
34684 * @return {Roo.BasicDialog} The BasicDialog element
34686 getDialog : function(){
34688 dlg = new Roo.BasicDialog("x-msg-box", {
34693 constraintoviewport:false,
34695 collapsible : false,
34698 width:400, height:100,
34699 buttonAlign:"center",
34700 closeClick : function(){
34701 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
34702 handleButton("no");
34704 handleButton("cancel");
34708 dlg.on("hide", handleHide);
34710 dlg.addKeyListener(27, handleEsc);
34712 var bt = this.buttonText;
34713 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
34714 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
34715 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
34716 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
34717 bodyEl = dlg.body.createChild({
34719 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>'
34721 msgEl = bodyEl.dom.firstChild;
34722 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
34723 textboxEl.enableDisplayMode();
34724 textboxEl.addKeyListener([10,13], function(){
34725 if(dlg.isVisible() && opt && opt.buttons){
34726 if(opt.buttons.ok){
34727 handleButton("ok");
34728 }else if(opt.buttons.yes){
34729 handleButton("yes");
34733 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
34734 textareaEl.enableDisplayMode();
34735 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
34736 progressEl.enableDisplayMode();
34737 var pf = progressEl.dom.firstChild;
34739 pp = Roo.get(pf.firstChild);
34740 pp.setHeight(pf.offsetHeight);
34748 * Updates the message box body text
34749 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
34750 * the XHTML-compliant non-breaking space character '&#160;')
34751 * @return {Roo.MessageBox} This message box
34753 updateText : function(text){
34754 if(!dlg.isVisible() && !opt.width){
34755 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
34757 msgEl.innerHTML = text || ' ';
34759 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
34760 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
34762 Math.min(opt.width || cw , this.maxWidth),
34763 Math.max(opt.minWidth || this.minWidth, bwidth)
34766 activeTextEl.setWidth(w);
34768 if(dlg.isVisible()){
34769 dlg.fixedcenter = false;
34771 // to big, make it scroll. = But as usual stupid IE does not support
34774 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
34775 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
34776 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
34778 bodyEl.dom.style.height = '';
34779 bodyEl.dom.style.overflowY = '';
34782 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
34784 bodyEl.dom.style.overflowX = '';
34787 dlg.setContentSize(w, bodyEl.getHeight());
34788 if(dlg.isVisible()){
34789 dlg.fixedcenter = true;
34795 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
34796 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
34797 * @param {Number} value Any number between 0 and 1 (e.g., .5)
34798 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
34799 * @return {Roo.MessageBox} This message box
34801 updateProgress : function(value, text){
34803 this.updateText(text);
34805 if (pp) { // weird bug on my firefox - for some reason this is not defined
34806 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
34812 * Returns true if the message box is currently displayed
34813 * @return {Boolean} True if the message box is visible, else false
34815 isVisible : function(){
34816 return dlg && dlg.isVisible();
34820 * Hides the message box if it is displayed
34823 if(this.isVisible()){
34829 * Displays a new message box, or reinitializes an existing message box, based on the config options
34830 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
34831 * The following config object properties are supported:
34833 Property Type Description
34834 ---------- --------------- ------------------------------------------------------------------------------------
34835 animEl String/Element An id or Element from which the message box should animate as it opens and
34836 closes (defaults to undefined)
34837 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
34838 cancel:'Bar'}), or false to not show any buttons (defaults to false)
34839 closable Boolean False to hide the top-right close button (defaults to true). Note that
34840 progress and wait dialogs will ignore this property and always hide the
34841 close button as they can only be closed programmatically.
34842 cls String A custom CSS class to apply to the message box element
34843 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
34844 displayed (defaults to 75)
34845 fn Function A callback function to execute after closing the dialog. The arguments to the
34846 function will be btn (the name of the button that was clicked, if applicable,
34847 e.g. "ok"), and text (the value of the active text field, if applicable).
34848 Progress and wait dialogs will ignore this option since they do not respond to
34849 user actions and can only be closed programmatically, so any required function
34850 should be called by the same code after it closes the dialog.
34851 icon String A CSS class that provides a background image to be used as an icon for
34852 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
34853 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
34854 minWidth Number The minimum width in pixels of the message box (defaults to 100)
34855 modal Boolean False to allow user interaction with the page while the message box is
34856 displayed (defaults to true)
34857 msg String A string that will replace the existing message box body text (defaults
34858 to the XHTML-compliant non-breaking space character ' ')
34859 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
34860 progress Boolean True to display a progress bar (defaults to false)
34861 progressText String The text to display inside the progress bar if progress = true (defaults to '')
34862 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
34863 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
34864 title String The title text
34865 value String The string value to set into the active textbox element if displayed
34866 wait Boolean True to display a progress bar (defaults to false)
34867 width Number The width of the dialog in pixels
34874 msg: 'Please enter your address:',
34876 buttons: Roo.MessageBox.OKCANCEL,
34879 animEl: 'addAddressBtn'
34882 * @param {Object} config Configuration options
34883 * @return {Roo.MessageBox} This message box
34885 show : function(options)
34888 // this causes nightmares if you show one dialog after another
34889 // especially on callbacks..
34891 if(this.isVisible()){
34894 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
34895 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
34896 Roo.log("New Dialog Message:" + options.msg )
34897 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
34898 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
34901 var d = this.getDialog();
34903 d.setTitle(opt.title || " ");
34904 d.close.setDisplayed(opt.closable !== false);
34905 activeTextEl = textboxEl;
34906 opt.prompt = opt.prompt || (opt.multiline ? true : false);
34911 textareaEl.setHeight(typeof opt.multiline == "number" ?
34912 opt.multiline : this.defaultTextHeight);
34913 activeTextEl = textareaEl;
34922 progressEl.setDisplayed(opt.progress === true);
34923 this.updateProgress(0);
34924 activeTextEl.dom.value = opt.value || "";
34926 dlg.setDefaultButton(activeTextEl);
34928 var bs = opt.buttons;
34931 db = buttons["ok"];
34932 }else if(bs && bs.yes){
34933 db = buttons["yes"];
34935 dlg.setDefaultButton(db);
34937 bwidth = updateButtons(opt.buttons);
34938 this.updateText(opt.msg);
34940 d.el.addClass(opt.cls);
34942 d.proxyDrag = opt.proxyDrag === true;
34943 d.modal = opt.modal !== false;
34944 d.mask = opt.modal !== false ? mask : false;
34945 if(!d.isVisible()){
34946 // force it to the end of the z-index stack so it gets a cursor in FF
34947 document.body.appendChild(dlg.el.dom);
34948 d.animateTarget = null;
34949 d.show(options.animEl);
34955 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
34956 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
34957 * and closing the message box when the process is complete.
34958 * @param {String} title The title bar text
34959 * @param {String} msg The message box body text
34960 * @return {Roo.MessageBox} This message box
34962 progress : function(title, msg){
34969 minWidth: this.minProgressWidth,
34976 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
34977 * If a callback function is passed it will be called after the user clicks the button, and the
34978 * id of the button that was clicked will be passed as the only parameter to the callback
34979 * (could also be the top-right close button).
34980 * @param {String} title The title bar text
34981 * @param {String} msg The message box body text
34982 * @param {Function} fn (optional) The callback function invoked after the message box is closed
34983 * @param {Object} scope (optional) The scope of the callback function
34984 * @return {Roo.MessageBox} This message box
34986 alert : function(title, msg, fn, scope){
34999 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
35000 * interaction while waiting for a long-running process to complete that does not have defined intervals.
35001 * You are responsible for closing the message box when the process is complete.
35002 * @param {String} msg The message box body text
35003 * @param {String} title (optional) The title bar text
35004 * @return {Roo.MessageBox} This message box
35006 wait : function(msg, title){
35017 waitTimer = Roo.TaskMgr.start({
35019 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
35027 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
35028 * If a callback function is passed it will be called after the user clicks either button, and the id of the
35029 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
35030 * @param {String} title The title bar text
35031 * @param {String} msg The message box body text
35032 * @param {Function} fn (optional) The callback function invoked after the message box is closed
35033 * @param {Object} scope (optional) The scope of the callback function
35034 * @return {Roo.MessageBox} This message box
35036 confirm : function(title, msg, fn, scope){
35040 buttons: this.YESNO,
35049 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
35050 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
35051 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
35052 * (could also be the top-right close button) and the text that was entered will be passed as the two
35053 * parameters to the callback.
35054 * @param {String} title The title bar text
35055 * @param {String} msg The message box body text
35056 * @param {Function} fn (optional) The callback function invoked after the message box is closed
35057 * @param {Object} scope (optional) The scope of the callback function
35058 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
35059 * property, or the height in pixels to create the textbox (defaults to false / single-line)
35060 * @return {Roo.MessageBox} This message box
35062 prompt : function(title, msg, fn, scope, multiline){
35066 buttons: this.OKCANCEL,
35071 multiline: multiline,
35078 * Button config that displays a single OK button
35083 * Button config that displays Yes and No buttons
35086 YESNO : {yes:true, no:true},
35088 * Button config that displays OK and Cancel buttons
35091 OKCANCEL : {ok:true, cancel:true},
35093 * Button config that displays Yes, No and Cancel buttons
35096 YESNOCANCEL : {yes:true, no:true, cancel:true},
35099 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
35102 defaultTextHeight : 75,
35104 * The maximum width in pixels of the message box (defaults to 600)
35109 * The minimum width in pixels of the message box (defaults to 100)
35114 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
35115 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
35118 minProgressWidth : 250,
35120 * An object containing the default button text strings that can be overriden for localized language support.
35121 * Supported properties are: ok, cancel, yes and no.
35122 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
35135 * Shorthand for {@link Roo.MessageBox}
35137 Roo.Msg = Roo.MessageBox;/*
35139 * Ext JS Library 1.1.1
35140 * Copyright(c) 2006-2007, Ext JS, LLC.
35142 * Originally Released Under LGPL - original licence link has changed is not relivant.
35145 * <script type="text/javascript">
35148 * @class Roo.QuickTips
35149 * Provides attractive and customizable tooltips for any element.
35152 Roo.QuickTips = function(){
35153 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
35154 var ce, bd, xy, dd;
35155 var visible = false, disabled = true, inited = false;
35156 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
35158 var onOver = function(e){
35162 var t = e.getTarget();
35163 if(!t || t.nodeType !== 1 || t == document || t == document.body){
35166 if(ce && t == ce.el){
35167 clearTimeout(hideProc);
35170 if(t && tagEls[t.id]){
35171 tagEls[t.id].el = t;
35172 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
35175 var ttp, et = Roo.fly(t);
35176 var ns = cfg.namespace;
35177 if(tm.interceptTitles && t.title){
35180 t.removeAttribute("title");
35181 e.preventDefault();
35183 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
35186 showProc = show.defer(tm.showDelay, tm, [{
35188 text: ttp.replace(/\\n/g,'<br/>'),
35189 width: et.getAttributeNS(ns, cfg.width),
35190 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
35191 title: et.getAttributeNS(ns, cfg.title),
35192 cls: et.getAttributeNS(ns, cfg.cls)
35197 var onOut = function(e){
35198 clearTimeout(showProc);
35199 var t = e.getTarget();
35200 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
35201 hideProc = setTimeout(hide, tm.hideDelay);
35205 var onMove = function(e){
35211 if(tm.trackMouse && ce){
35216 var onDown = function(e){
35217 clearTimeout(showProc);
35218 clearTimeout(hideProc);
35220 if(tm.hideOnClick){
35223 tm.enable.defer(100, tm);
35228 var getPad = function(){
35229 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
35232 var show = function(o){
35236 clearTimeout(dismissProc);
35238 if(removeCls){ // in case manually hidden
35239 el.removeClass(removeCls);
35243 el.addClass(ce.cls);
35244 removeCls = ce.cls;
35247 tipTitle.update(ce.title);
35250 tipTitle.update('');
35253 el.dom.style.width = tm.maxWidth+'px';
35254 //tipBody.dom.style.width = '';
35255 tipBodyText.update(o.text);
35256 var p = getPad(), w = ce.width;
35258 var td = tipBodyText.dom;
35259 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
35260 if(aw > tm.maxWidth){
35262 }else if(aw < tm.minWidth){
35268 //tipBody.setWidth(w);
35269 el.setWidth(parseInt(w, 10) + p);
35270 if(ce.autoHide === false){
35271 close.setDisplayed(true);
35276 close.setDisplayed(false);
35282 el.avoidY = xy[1]-18;
35287 el.setStyle("visibility", "visible");
35288 el.fadeIn({callback: afterShow});
35294 var afterShow = function(){
35298 if(tm.autoDismiss && ce.autoHide !== false){
35299 dismissProc = setTimeout(hide, tm.autoDismissDelay);
35304 var hide = function(noanim){
35305 clearTimeout(dismissProc);
35306 clearTimeout(hideProc);
35308 if(el.isVisible()){
35310 if(noanim !== true && tm.animate){
35311 el.fadeOut({callback: afterHide});
35318 var afterHide = function(){
35321 el.removeClass(removeCls);
35328 * @cfg {Number} minWidth
35329 * The minimum width of the quick tip (defaults to 40)
35333 * @cfg {Number} maxWidth
35334 * The maximum width of the quick tip (defaults to 300)
35338 * @cfg {Boolean} interceptTitles
35339 * True to automatically use the element's DOM title value if available (defaults to false)
35341 interceptTitles : false,
35343 * @cfg {Boolean} trackMouse
35344 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
35346 trackMouse : false,
35348 * @cfg {Boolean} hideOnClick
35349 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
35351 hideOnClick : true,
35353 * @cfg {Number} showDelay
35354 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
35358 * @cfg {Number} hideDelay
35359 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
35363 * @cfg {Boolean} autoHide
35364 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
35365 * Used in conjunction with hideDelay.
35370 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
35371 * (defaults to true). Used in conjunction with autoDismissDelay.
35373 autoDismiss : true,
35376 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
35378 autoDismissDelay : 5000,
35380 * @cfg {Boolean} animate
35381 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
35386 * @cfg {String} title
35387 * Title text to display (defaults to ''). This can be any valid HTML markup.
35391 * @cfg {String} text
35392 * Body text to display (defaults to ''). This can be any valid HTML markup.
35396 * @cfg {String} cls
35397 * A CSS class to apply to the base quick tip element (defaults to '').
35401 * @cfg {Number} width
35402 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
35403 * minWidth or maxWidth.
35408 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
35409 * or display QuickTips in a page.
35412 tm = Roo.QuickTips;
35413 cfg = tm.tagConfig;
35415 if(!Roo.isReady){ // allow calling of init() before onReady
35416 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
35419 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
35420 el.fxDefaults = {stopFx: true};
35421 // maximum custom styling
35422 //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>');
35423 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>');
35424 tipTitle = el.child('h3');
35425 tipTitle.enableDisplayMode("block");
35426 tipBody = el.child('div.x-tip-bd');
35427 tipBodyText = el.child('div.x-tip-bd-inner');
35428 //bdLeft = el.child('div.x-tip-bd-left');
35429 //bdRight = el.child('div.x-tip-bd-right');
35430 close = el.child('div.x-tip-close');
35431 close.enableDisplayMode("block");
35432 close.on("click", hide);
35433 var d = Roo.get(document);
35434 d.on("mousedown", onDown);
35435 d.on("mouseover", onOver);
35436 d.on("mouseout", onOut);
35437 d.on("mousemove", onMove);
35438 esc = d.addKeyListener(27, hide);
35441 dd = el.initDD("default", null, {
35442 onDrag : function(){
35446 dd.setHandleElId(tipTitle.id);
35455 * Configures a new quick tip instance and assigns it to a target element. The following config options
35458 Property Type Description
35459 ---------- --------------------- ------------------------------------------------------------------------
35460 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
35462 * @param {Object} config The config object
35464 register : function(config){
35465 var cs = config instanceof Array ? config : arguments;
35466 for(var i = 0, len = cs.length; i < len; i++) {
35468 var target = c.target;
35470 if(target instanceof Array){
35471 for(var j = 0, jlen = target.length; j < jlen; j++){
35472 tagEls[target[j]] = c;
35475 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
35482 * Removes this quick tip from its element and destroys it.
35483 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
35485 unregister : function(el){
35486 delete tagEls[Roo.id(el)];
35490 * Enable this quick tip.
35492 enable : function(){
35493 if(inited && disabled){
35495 if(locks.length < 1){
35502 * Disable this quick tip.
35504 disable : function(){
35506 clearTimeout(showProc);
35507 clearTimeout(hideProc);
35508 clearTimeout(dismissProc);
35516 * Returns true if the quick tip is enabled, else false.
35518 isEnabled : function(){
35524 namespace : "roo", // was ext?? this may break..
35525 alt_namespace : "ext",
35526 attribute : "qtip",
35536 // backwards compat
35537 Roo.QuickTips.tips = Roo.QuickTips.register;/*
35539 * Ext JS Library 1.1.1
35540 * Copyright(c) 2006-2007, Ext JS, LLC.
35542 * Originally Released Under LGPL - original licence link has changed is not relivant.
35545 * <script type="text/javascript">
35550 * @class Roo.tree.TreePanel
35551 * @extends Roo.data.Tree
35552 * @cfg {Roo.tree.TreeNode} root The root node
35553 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
35554 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
35555 * @cfg {Boolean} enableDD true to enable drag and drop
35556 * @cfg {Boolean} enableDrag true to enable just drag
35557 * @cfg {Boolean} enableDrop true to enable just drop
35558 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
35559 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
35560 * @cfg {String} ddGroup The DD group this TreePanel belongs to
35561 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
35562 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
35563 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
35564 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
35565 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
35566 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
35567 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
35568 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
35569 * @cfg {Roo.tree.TreeLoader} loader A TreeLoader for use with this TreePanel
35570 * @cfg {Roo.tree.TreeEditor} editor The TreeEditor to display when clicked.
35571 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
35572 * @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>
35573 * @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>
35576 * @param {String/HTMLElement/Element} el The container element
35577 * @param {Object} config
35579 Roo.tree.TreePanel = function(el, config){
35581 var loader = false;
35583 root = config.root;
35584 delete config.root;
35586 if (config.loader) {
35587 loader = config.loader;
35588 delete config.loader;
35591 Roo.apply(this, config);
35592 Roo.tree.TreePanel.superclass.constructor.call(this);
35593 this.el = Roo.get(el);
35594 this.el.addClass('x-tree');
35595 //console.log(root);
35597 this.setRootNode( Roo.factory(root, Roo.tree));
35600 this.loader = Roo.factory(loader, Roo.tree);
35603 * Read-only. The id of the container element becomes this TreePanel's id.
35605 this.id = this.el.id;
35608 * @event beforeload
35609 * Fires before a node is loaded, return false to cancel
35610 * @param {Node} node The node being loaded
35612 "beforeload" : true,
35615 * Fires when a node is loaded
35616 * @param {Node} node The node that was loaded
35620 * @event textchange
35621 * Fires when the text for a node is changed
35622 * @param {Node} node The node
35623 * @param {String} text The new text
35624 * @param {String} oldText The old text
35626 "textchange" : true,
35628 * @event beforeexpand
35629 * Fires before a node is expanded, return false to cancel.
35630 * @param {Node} node The node
35631 * @param {Boolean} deep
35632 * @param {Boolean} anim
35634 "beforeexpand" : true,
35636 * @event beforecollapse
35637 * Fires before a node is collapsed, return false to cancel.
35638 * @param {Node} node The node
35639 * @param {Boolean} deep
35640 * @param {Boolean} anim
35642 "beforecollapse" : true,
35645 * Fires when a node is expanded
35646 * @param {Node} node The node
35650 * @event disabledchange
35651 * Fires when the disabled status of a node changes
35652 * @param {Node} node The node
35653 * @param {Boolean} disabled
35655 "disabledchange" : true,
35658 * Fires when a node is collapsed
35659 * @param {Node} node The node
35663 * @event beforeclick
35664 * Fires before click processing on a node. Return false to cancel the default action.
35665 * @param {Node} node The node
35666 * @param {Roo.EventObject} e The event object
35668 "beforeclick":true,
35670 * @event checkchange
35671 * Fires when a node with a checkbox's checked property changes
35672 * @param {Node} this This node
35673 * @param {Boolean} checked
35675 "checkchange":true,
35678 * Fires when a node is clicked
35679 * @param {Node} node The node
35680 * @param {Roo.EventObject} e The event object
35685 * Fires when a node is double clicked
35686 * @param {Node} node The node
35687 * @param {Roo.EventObject} e The event object
35691 * @event contextmenu
35692 * Fires when a node is right clicked
35693 * @param {Node} node The node
35694 * @param {Roo.EventObject} e The event object
35696 "contextmenu":true,
35698 * @event beforechildrenrendered
35699 * Fires right before the child nodes for a node are rendered
35700 * @param {Node} node The node
35702 "beforechildrenrendered":true,
35705 * Fires when a node starts being dragged
35706 * @param {Roo.tree.TreePanel} this
35707 * @param {Roo.tree.TreeNode} node
35708 * @param {event} e The raw browser event
35710 "startdrag" : true,
35713 * Fires when a drag operation is complete
35714 * @param {Roo.tree.TreePanel} this
35715 * @param {Roo.tree.TreeNode} node
35716 * @param {event} e The raw browser event
35721 * Fires when a dragged node is dropped on a valid DD target
35722 * @param {Roo.tree.TreePanel} this
35723 * @param {Roo.tree.TreeNode} node
35724 * @param {DD} dd The dd it was dropped on
35725 * @param {event} e The raw browser event
35729 * @event beforenodedrop
35730 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
35731 * passed to handlers has the following properties:<br />
35732 * <ul style="padding:5px;padding-left:16px;">
35733 * <li>tree - The TreePanel</li>
35734 * <li>target - The node being targeted for the drop</li>
35735 * <li>data - The drag data from the drag source</li>
35736 * <li>point - The point of the drop - append, above or below</li>
35737 * <li>source - The drag source</li>
35738 * <li>rawEvent - Raw mouse event</li>
35739 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
35740 * to be inserted by setting them on this object.</li>
35741 * <li>cancel - Set this to true to cancel the drop.</li>
35743 * @param {Object} dropEvent
35745 "beforenodedrop" : true,
35748 * Fires after a DD object is dropped on a node in this tree. The dropEvent
35749 * passed to handlers has the following properties:<br />
35750 * <ul style="padding:5px;padding-left:16px;">
35751 * <li>tree - The TreePanel</li>
35752 * <li>target - The node being targeted for the drop</li>
35753 * <li>data - The drag data from the drag source</li>
35754 * <li>point - The point of the drop - append, above or below</li>
35755 * <li>source - The drag source</li>
35756 * <li>rawEvent - Raw mouse event</li>
35757 * <li>dropNode - Dropped node(s).</li>
35759 * @param {Object} dropEvent
35763 * @event nodedragover
35764 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
35765 * passed to handlers has the following properties:<br />
35766 * <ul style="padding:5px;padding-left:16px;">
35767 * <li>tree - The TreePanel</li>
35768 * <li>target - The node being targeted for the drop</li>
35769 * <li>data - The drag data from the drag source</li>
35770 * <li>point - The point of the drop - append, above or below</li>
35771 * <li>source - The drag source</li>
35772 * <li>rawEvent - Raw mouse event</li>
35773 * <li>dropNode - Drop node(s) provided by the source.</li>
35774 * <li>cancel - Set this to true to signal drop not allowed.</li>
35776 * @param {Object} dragOverEvent
35778 "nodedragover" : true,
35780 * @event appendnode
35781 * Fires when append node to the tree
35782 * @param {Roo.tree.TreePanel} this
35783 * @param {Roo.tree.TreeNode} node
35784 * @param {Number} index The index of the newly appended node
35786 "appendnode" : true
35789 if(this.singleExpand){
35790 this.on("beforeexpand", this.restrictExpand, this);
35793 this.editor.tree = this;
35794 this.editor = Roo.factory(this.editor, Roo.tree);
35797 if (this.selModel) {
35798 this.selModel = Roo.factory(this.selModel, Roo.tree);
35802 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
35803 rootVisible : true,
35804 animate: Roo.enableFx,
35807 hlDrop : Roo.enableFx,
35811 rendererTip: false,
35813 restrictExpand : function(node){
35814 var p = node.parentNode;
35816 if(p.expandedChild && p.expandedChild.parentNode == p){
35817 p.expandedChild.collapse();
35819 p.expandedChild = node;
35823 // private override
35824 setRootNode : function(node){
35825 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
35826 if(!this.rootVisible){
35827 node.ui = new Roo.tree.RootTreeNodeUI(node);
35833 * Returns the container element for this TreePanel
35835 getEl : function(){
35840 * Returns the default TreeLoader for this TreePanel
35842 getLoader : function(){
35843 return this.loader;
35849 expandAll : function(){
35850 this.root.expand(true);
35854 * Collapse all nodes
35856 collapseAll : function(){
35857 this.root.collapse(true);
35861 * Returns the selection model used by this TreePanel
35863 getSelectionModel : function(){
35864 if(!this.selModel){
35865 this.selModel = new Roo.tree.DefaultSelectionModel();
35867 return this.selModel;
35871 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
35872 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
35873 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
35876 getChecked : function(a, startNode){
35877 startNode = startNode || this.root;
35879 var f = function(){
35880 if(this.attributes.checked){
35881 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
35884 startNode.cascade(f);
35889 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
35890 * @param {String} path
35891 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
35892 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
35893 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
35895 expandPath : function(path, attr, callback){
35896 attr = attr || "id";
35897 var keys = path.split(this.pathSeparator);
35898 var curNode = this.root;
35899 if(curNode.attributes[attr] != keys[1]){ // invalid root
35901 callback(false, null);
35906 var f = function(){
35907 if(++index == keys.length){
35909 callback(true, curNode);
35913 var c = curNode.findChild(attr, keys[index]);
35916 callback(false, curNode);
35921 c.expand(false, false, f);
35923 curNode.expand(false, false, f);
35927 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
35928 * @param {String} path
35929 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
35930 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
35931 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
35933 selectPath : function(path, attr, callback){
35934 attr = attr || "id";
35935 var keys = path.split(this.pathSeparator);
35936 var v = keys.pop();
35937 if(keys.length > 0){
35938 var f = function(success, node){
35939 if(success && node){
35940 var n = node.findChild(attr, v);
35946 }else if(callback){
35947 callback(false, n);
35951 callback(false, n);
35955 this.expandPath(keys.join(this.pathSeparator), attr, f);
35957 this.root.select();
35959 callback(true, this.root);
35964 getTreeEl : function(){
35969 * Trigger rendering of this TreePanel
35971 render : function(){
35972 if (this.innerCt) {
35973 return this; // stop it rendering more than once!!
35976 this.innerCt = this.el.createChild({tag:"ul",
35977 cls:"x-tree-root-ct " +
35978 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
35980 if(this.containerScroll){
35981 Roo.dd.ScrollManager.register(this.el);
35983 if((this.enableDD || this.enableDrop) && !this.dropZone){
35985 * The dropZone used by this tree if drop is enabled
35986 * @type Roo.tree.TreeDropZone
35988 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
35989 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
35992 if((this.enableDD || this.enableDrag) && !this.dragZone){
35994 * The dragZone used by this tree if drag is enabled
35995 * @type Roo.tree.TreeDragZone
35997 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
35998 ddGroup: this.ddGroup || "TreeDD",
35999 scroll: this.ddScroll
36002 this.getSelectionModel().init(this);
36004 Roo.log("ROOT not set in tree");
36007 this.root.render();
36008 if(!this.rootVisible){
36009 this.root.renderChildren();
36015 * Ext JS Library 1.1.1
36016 * Copyright(c) 2006-2007, Ext JS, LLC.
36018 * Originally Released Under LGPL - original licence link has changed is not relivant.
36021 * <script type="text/javascript">
36026 * @class Roo.tree.DefaultSelectionModel
36027 * @extends Roo.util.Observable
36028 * The default single selection for a TreePanel.
36029 * @param {Object} cfg Configuration
36031 Roo.tree.DefaultSelectionModel = function(cfg){
36032 this.selNode = null;
36038 * @event selectionchange
36039 * Fires when the selected node changes
36040 * @param {DefaultSelectionModel} this
36041 * @param {TreeNode} node the new selection
36043 "selectionchange" : true,
36046 * @event beforeselect
36047 * Fires before the selected node changes, return false to cancel the change
36048 * @param {DefaultSelectionModel} this
36049 * @param {TreeNode} node the new selection
36050 * @param {TreeNode} node the old selection
36052 "beforeselect" : true
36055 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
36058 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
36059 init : function(tree){
36061 tree.getTreeEl().on("keydown", this.onKeyDown, this);
36062 tree.on("click", this.onNodeClick, this);
36065 onNodeClick : function(node, e){
36066 if (e.ctrlKey && this.selNode == node) {
36067 this.unselect(node);
36075 * @param {TreeNode} node The node to select
36076 * @return {TreeNode} The selected node
36078 select : function(node){
36079 var last = this.selNode;
36080 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
36082 last.ui.onSelectedChange(false);
36084 this.selNode = node;
36085 node.ui.onSelectedChange(true);
36086 this.fireEvent("selectionchange", this, node, last);
36093 * @param {TreeNode} node The node to unselect
36095 unselect : function(node){
36096 if(this.selNode == node){
36097 this.clearSelections();
36102 * Clear all selections
36104 clearSelections : function(){
36105 var n = this.selNode;
36107 n.ui.onSelectedChange(false);
36108 this.selNode = null;
36109 this.fireEvent("selectionchange", this, null);
36115 * Get the selected node
36116 * @return {TreeNode} The selected node
36118 getSelectedNode : function(){
36119 return this.selNode;
36123 * Returns true if the node is selected
36124 * @param {TreeNode} node The node to check
36125 * @return {Boolean}
36127 isSelected : function(node){
36128 return this.selNode == node;
36132 * Selects the node above the selected node in the tree, intelligently walking the nodes
36133 * @return TreeNode The new selection
36135 selectPrevious : function(){
36136 var s = this.selNode || this.lastSelNode;
36140 var ps = s.previousSibling;
36142 if(!ps.isExpanded() || ps.childNodes.length < 1){
36143 return this.select(ps);
36145 var lc = ps.lastChild;
36146 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
36149 return this.select(lc);
36151 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
36152 return this.select(s.parentNode);
36158 * Selects the node above the selected node in the tree, intelligently walking the nodes
36159 * @return TreeNode The new selection
36161 selectNext : function(){
36162 var s = this.selNode || this.lastSelNode;
36166 if(s.firstChild && s.isExpanded()){
36167 return this.select(s.firstChild);
36168 }else if(s.nextSibling){
36169 return this.select(s.nextSibling);
36170 }else if(s.parentNode){
36172 s.parentNode.bubble(function(){
36173 if(this.nextSibling){
36174 newS = this.getOwnerTree().selModel.select(this.nextSibling);
36183 onKeyDown : function(e){
36184 var s = this.selNode || this.lastSelNode;
36185 // undesirable, but required
36190 var k = e.getKey();
36198 this.selectPrevious();
36201 e.preventDefault();
36202 if(s.hasChildNodes()){
36203 if(!s.isExpanded()){
36205 }else if(s.firstChild){
36206 this.select(s.firstChild, e);
36211 e.preventDefault();
36212 if(s.hasChildNodes() && s.isExpanded()){
36214 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
36215 this.select(s.parentNode, e);
36223 * @class Roo.tree.MultiSelectionModel
36224 * @extends Roo.util.Observable
36225 * Multi selection for a TreePanel.
36226 * @param {Object} cfg Configuration
36228 Roo.tree.MultiSelectionModel = function(){
36229 this.selNodes = [];
36233 * @event selectionchange
36234 * Fires when the selected nodes change
36235 * @param {MultiSelectionModel} this
36236 * @param {Array} nodes Array of the selected nodes
36238 "selectionchange" : true
36240 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
36244 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
36245 init : function(tree){
36247 tree.getTreeEl().on("keydown", this.onKeyDown, this);
36248 tree.on("click", this.onNodeClick, this);
36251 onNodeClick : function(node, e){
36252 this.select(node, e, e.ctrlKey);
36257 * @param {TreeNode} node The node to select
36258 * @param {EventObject} e (optional) An event associated with the selection
36259 * @param {Boolean} keepExisting True to retain existing selections
36260 * @return {TreeNode} The selected node
36262 select : function(node, e, keepExisting){
36263 if(keepExisting !== true){
36264 this.clearSelections(true);
36266 if(this.isSelected(node)){
36267 this.lastSelNode = node;
36270 this.selNodes.push(node);
36271 this.selMap[node.id] = node;
36272 this.lastSelNode = node;
36273 node.ui.onSelectedChange(true);
36274 this.fireEvent("selectionchange", this, this.selNodes);
36280 * @param {TreeNode} node The node to unselect
36282 unselect : function(node){
36283 if(this.selMap[node.id]){
36284 node.ui.onSelectedChange(false);
36285 var sn = this.selNodes;
36288 index = sn.indexOf(node);
36290 for(var i = 0, len = sn.length; i < len; i++){
36298 this.selNodes.splice(index, 1);
36300 delete this.selMap[node.id];
36301 this.fireEvent("selectionchange", this, this.selNodes);
36306 * Clear all selections
36308 clearSelections : function(suppressEvent){
36309 var sn = this.selNodes;
36311 for(var i = 0, len = sn.length; i < len; i++){
36312 sn[i].ui.onSelectedChange(false);
36314 this.selNodes = [];
36316 if(suppressEvent !== true){
36317 this.fireEvent("selectionchange", this, this.selNodes);
36323 * Returns true if the node is selected
36324 * @param {TreeNode} node The node to check
36325 * @return {Boolean}
36327 isSelected : function(node){
36328 return this.selMap[node.id] ? true : false;
36332 * Returns an array of the selected nodes
36335 getSelectedNodes : function(){
36336 return this.selNodes;
36339 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
36341 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
36343 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
36346 * Ext JS Library 1.1.1
36347 * Copyright(c) 2006-2007, Ext JS, LLC.
36349 * Originally Released Under LGPL - original licence link has changed is not relivant.
36352 * <script type="text/javascript">
36356 * @class Roo.tree.TreeNode
36357 * @extends Roo.data.Node
36358 * @cfg {String} text The text for this node
36359 * @cfg {Boolean} expanded true to start the node expanded
36360 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
36361 * @cfg {Boolean} allowDrop false if this node cannot be drop on
36362 * @cfg {Boolean} disabled true to start the node disabled
36363 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
36364 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
36365 * @cfg {String} cls A css class to be added to the node
36366 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
36367 * @cfg {String} href URL of the link used for the node (defaults to #)
36368 * @cfg {String} hrefTarget target frame for the link
36369 * @cfg {String} qtip An Ext QuickTip for the node
36370 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
36371 * @cfg {Boolean} singleClickExpand True for single click expand on this node
36372 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
36373 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
36374 * (defaults to undefined with no checkbox rendered)
36376 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
36378 Roo.tree.TreeNode = function(attributes){
36379 attributes = attributes || {};
36380 if(typeof attributes == "string"){
36381 attributes = {text: attributes};
36383 this.childrenRendered = false;
36384 this.rendered = false;
36385 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
36386 this.expanded = attributes.expanded === true;
36387 this.isTarget = attributes.isTarget !== false;
36388 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
36389 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
36392 * Read-only. The text for this node. To change it use setText().
36395 this.text = attributes.text;
36397 * True if this node is disabled.
36400 this.disabled = attributes.disabled === true;
36404 * @event textchange
36405 * Fires when the text for this node is changed
36406 * @param {Node} this This node
36407 * @param {String} text The new text
36408 * @param {String} oldText The old text
36410 "textchange" : true,
36412 * @event beforeexpand
36413 * Fires before this node is expanded, return false to cancel.
36414 * @param {Node} this This node
36415 * @param {Boolean} deep
36416 * @param {Boolean} anim
36418 "beforeexpand" : true,
36420 * @event beforecollapse
36421 * Fires before this node is collapsed, return false to cancel.
36422 * @param {Node} this This node
36423 * @param {Boolean} deep
36424 * @param {Boolean} anim
36426 "beforecollapse" : true,
36429 * Fires when this node is expanded
36430 * @param {Node} this This node
36434 * @event disabledchange
36435 * Fires when the disabled status of this node changes
36436 * @param {Node} this This node
36437 * @param {Boolean} disabled
36439 "disabledchange" : true,
36442 * Fires when this node is collapsed
36443 * @param {Node} this This node
36447 * @event beforeclick
36448 * Fires before click processing. Return false to cancel the default action.
36449 * @param {Node} this This node
36450 * @param {Roo.EventObject} e The event object
36452 "beforeclick":true,
36454 * @event checkchange
36455 * Fires when a node with a checkbox's checked property changes
36456 * @param {Node} this This node
36457 * @param {Boolean} checked
36459 "checkchange":true,
36462 * Fires when this node is clicked
36463 * @param {Node} this This node
36464 * @param {Roo.EventObject} e The event object
36469 * Fires when this node is double clicked
36470 * @param {Node} this This node
36471 * @param {Roo.EventObject} e The event object
36475 * @event contextmenu
36476 * Fires when this node is right clicked
36477 * @param {Node} this This node
36478 * @param {Roo.EventObject} e The event object
36480 "contextmenu":true,
36482 * @event beforechildrenrendered
36483 * Fires right before the child nodes for this node are rendered
36484 * @param {Node} this This node
36486 "beforechildrenrendered":true
36489 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
36492 * Read-only. The UI for this node
36495 this.ui = new uiClass(this);
36497 // finally support items[]
36498 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
36503 Roo.each(this.attributes.items, function(c) {
36504 this.appendChild(Roo.factory(c,Roo.Tree));
36506 delete this.attributes.items;
36511 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
36512 preventHScroll: true,
36514 * Returns true if this node is expanded
36515 * @return {Boolean}
36517 isExpanded : function(){
36518 return this.expanded;
36522 * Returns the UI object for this node
36523 * @return {TreeNodeUI}
36525 getUI : function(){
36529 // private override
36530 setFirstChild : function(node){
36531 var of = this.firstChild;
36532 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
36533 if(this.childrenRendered && of && node != of){
36534 of.renderIndent(true, true);
36537 this.renderIndent(true, true);
36541 // private override
36542 setLastChild : function(node){
36543 var ol = this.lastChild;
36544 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
36545 if(this.childrenRendered && ol && node != ol){
36546 ol.renderIndent(true, true);
36549 this.renderIndent(true, true);
36553 // these methods are overridden to provide lazy rendering support
36554 // private override
36555 appendChild : function()
36557 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
36558 if(node && this.childrenRendered){
36561 this.ui.updateExpandIcon();
36565 // private override
36566 removeChild : function(node){
36567 this.ownerTree.getSelectionModel().unselect(node);
36568 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
36569 // if it's been rendered remove dom node
36570 if(this.childrenRendered){
36573 if(this.childNodes.length < 1){
36574 this.collapse(false, false);
36576 this.ui.updateExpandIcon();
36578 if(!this.firstChild) {
36579 this.childrenRendered = false;
36584 // private override
36585 insertBefore : function(node, refNode){
36586 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
36587 if(newNode && refNode && this.childrenRendered){
36590 this.ui.updateExpandIcon();
36595 * Sets the text for this node
36596 * @param {String} text
36598 setText : function(text){
36599 var oldText = this.text;
36601 this.attributes.text = text;
36602 if(this.rendered){ // event without subscribing
36603 this.ui.onTextChange(this, text, oldText);
36605 this.fireEvent("textchange", this, text, oldText);
36609 * Triggers selection of this node
36611 select : function(){
36612 this.getOwnerTree().getSelectionModel().select(this);
36616 * Triggers deselection of this node
36618 unselect : function(){
36619 this.getOwnerTree().getSelectionModel().unselect(this);
36623 * Returns true if this node is selected
36624 * @return {Boolean}
36626 isSelected : function(){
36627 return this.getOwnerTree().getSelectionModel().isSelected(this);
36631 * Expand this node.
36632 * @param {Boolean} deep (optional) True to expand all children as well
36633 * @param {Boolean} anim (optional) false to cancel the default animation
36634 * @param {Function} callback (optional) A callback to be called when
36635 * expanding this node completes (does not wait for deep expand to complete).
36636 * Called with 1 parameter, this node.
36638 expand : function(deep, anim, callback){
36639 if(!this.expanded){
36640 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
36643 if(!this.childrenRendered){
36644 this.renderChildren();
36646 this.expanded = true;
36648 if(!this.isHiddenRoot() && (this.getOwnerTree() && this.getOwnerTree().animate && anim !== false) || anim){
36649 this.ui.animExpand(function(){
36650 this.fireEvent("expand", this);
36651 if(typeof callback == "function"){
36655 this.expandChildNodes(true);
36657 }.createDelegate(this));
36661 this.fireEvent("expand", this);
36662 if(typeof callback == "function"){
36667 if(typeof callback == "function"){
36672 this.expandChildNodes(true);
36676 isHiddenRoot : function(){
36677 return this.isRoot && !this.getOwnerTree().rootVisible;
36681 * Collapse this node.
36682 * @param {Boolean} deep (optional) True to collapse all children as well
36683 * @param {Boolean} anim (optional) false to cancel the default animation
36685 collapse : function(deep, anim){
36686 if(this.expanded && !this.isHiddenRoot()){
36687 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
36690 this.expanded = false;
36691 if((this.getOwnerTree().animate && anim !== false) || anim){
36692 this.ui.animCollapse(function(){
36693 this.fireEvent("collapse", this);
36695 this.collapseChildNodes(true);
36697 }.createDelegate(this));
36700 this.ui.collapse();
36701 this.fireEvent("collapse", this);
36705 var cs = this.childNodes;
36706 for(var i = 0, len = cs.length; i < len; i++) {
36707 cs[i].collapse(true, false);
36713 delayedExpand : function(delay){
36714 if(!this.expandProcId){
36715 this.expandProcId = this.expand.defer(delay, this);
36720 cancelExpand : function(){
36721 if(this.expandProcId){
36722 clearTimeout(this.expandProcId);
36724 this.expandProcId = false;
36728 * Toggles expanded/collapsed state of the node
36730 toggle : function(){
36739 * Ensures all parent nodes are expanded
36741 ensureVisible : function(callback){
36742 var tree = this.getOwnerTree();
36743 tree.expandPath(this.parentNode.getPath(), false, function(){
36744 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
36745 Roo.callback(callback);
36746 }.createDelegate(this));
36750 * Expand all child nodes
36751 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
36753 expandChildNodes : function(deep){
36754 var cs = this.childNodes;
36755 for(var i = 0, len = cs.length; i < len; i++) {
36756 cs[i].expand(deep);
36761 * Collapse all child nodes
36762 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
36764 collapseChildNodes : function(deep){
36765 var cs = this.childNodes;
36766 for(var i = 0, len = cs.length; i < len; i++) {
36767 cs[i].collapse(deep);
36772 * Disables this node
36774 disable : function(){
36775 this.disabled = true;
36777 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
36778 this.ui.onDisableChange(this, true);
36780 this.fireEvent("disabledchange", this, true);
36784 * Enables this node
36786 enable : function(){
36787 this.disabled = false;
36788 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
36789 this.ui.onDisableChange(this, false);
36791 this.fireEvent("disabledchange", this, false);
36795 renderChildren : function(suppressEvent){
36796 if(suppressEvent !== false){
36797 this.fireEvent("beforechildrenrendered", this);
36799 var cs = this.childNodes;
36800 for(var i = 0, len = cs.length; i < len; i++){
36801 cs[i].render(true);
36803 this.childrenRendered = true;
36807 sort : function(fn, scope){
36808 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
36809 if(this.childrenRendered){
36810 var cs = this.childNodes;
36811 for(var i = 0, len = cs.length; i < len; i++){
36812 cs[i].render(true);
36818 render : function(bulkRender){
36819 this.ui.render(bulkRender);
36820 if(!this.rendered){
36821 this.rendered = true;
36823 this.expanded = false;
36824 this.expand(false, false);
36830 renderIndent : function(deep, refresh){
36832 this.ui.childIndent = null;
36834 this.ui.renderIndent();
36835 if(deep === true && this.childrenRendered){
36836 var cs = this.childNodes;
36837 for(var i = 0, len = cs.length; i < len; i++){
36838 cs[i].renderIndent(true, refresh);
36844 * Ext JS Library 1.1.1
36845 * Copyright(c) 2006-2007, Ext JS, LLC.
36847 * Originally Released Under LGPL - original licence link has changed is not relivant.
36850 * <script type="text/javascript">
36854 * @class Roo.tree.AsyncTreeNode
36855 * @extends Roo.tree.TreeNode
36856 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
36858 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
36860 Roo.tree.AsyncTreeNode = function(config){
36861 this.loaded = false;
36862 this.loading = false;
36863 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
36865 * @event beforeload
36866 * Fires before this node is loaded, return false to cancel
36867 * @param {Node} this This node
36869 this.addEvents({'beforeload':true, 'load': true});
36872 * Fires when this node is loaded
36873 * @param {Node} this This node
36876 * The loader used by this node (defaults to using the tree's defined loader)
36881 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
36882 expand : function(deep, anim, callback){
36883 if(this.loading){ // if an async load is already running, waiting til it's done
36885 var f = function(){
36886 if(!this.loading){ // done loading
36887 clearInterval(timer);
36888 this.expand(deep, anim, callback);
36890 }.createDelegate(this);
36891 timer = setInterval(f, 200);
36895 if(this.fireEvent("beforeload", this) === false){
36898 this.loading = true;
36899 this.ui.beforeLoad(this);
36900 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
36902 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
36906 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
36910 * Returns true if this node is currently loading
36911 * @return {Boolean}
36913 isLoading : function(){
36914 return this.loading;
36917 loadComplete : function(deep, anim, callback){
36918 this.loading = false;
36919 this.loaded = true;
36920 this.ui.afterLoad(this);
36921 this.fireEvent("load", this);
36922 this.expand(deep, anim, callback);
36926 * Returns true if this node has been loaded
36927 * @return {Boolean}
36929 isLoaded : function(){
36930 return this.loaded;
36933 hasChildNodes : function(){
36934 if(!this.isLeaf() && !this.loaded){
36937 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
36942 * Trigger a reload for this node
36943 * @param {Function} callback
36945 reload : function(callback){
36946 this.collapse(false, false);
36947 while(this.firstChild){
36948 this.removeChild(this.firstChild);
36950 this.childrenRendered = false;
36951 this.loaded = false;
36952 if(this.isHiddenRoot()){
36953 this.expanded = false;
36955 this.expand(false, false, callback);
36959 * Ext JS Library 1.1.1
36960 * Copyright(c) 2006-2007, Ext JS, LLC.
36962 * Originally Released Under LGPL - original licence link has changed is not relivant.
36965 * <script type="text/javascript">
36969 * @class Roo.tree.TreeNodeUI
36971 * @param {Object} node The node to render
36972 * The TreeNode UI implementation is separate from the
36973 * tree implementation. Unless you are customizing the tree UI,
36974 * you should never have to use this directly.
36976 Roo.tree.TreeNodeUI = function(node){
36978 this.rendered = false;
36979 this.animating = false;
36980 this.emptyIcon = Roo.BLANK_IMAGE_URL;
36983 Roo.tree.TreeNodeUI.prototype = {
36984 removeChild : function(node){
36986 this.ctNode.removeChild(node.ui.getEl());
36990 beforeLoad : function(){
36991 this.addClass("x-tree-node-loading");
36994 afterLoad : function(){
36995 this.removeClass("x-tree-node-loading");
36998 onTextChange : function(node, text, oldText){
37000 this.textNode.innerHTML = text;
37004 onDisableChange : function(node, state){
37005 this.disabled = state;
37007 this.addClass("x-tree-node-disabled");
37009 this.removeClass("x-tree-node-disabled");
37013 onSelectedChange : function(state){
37016 this.addClass("x-tree-selected");
37019 this.removeClass("x-tree-selected");
37023 onMove : function(tree, node, oldParent, newParent, index, refNode){
37024 this.childIndent = null;
37026 var targetNode = newParent.ui.getContainer();
37027 if(!targetNode){//target not rendered
37028 this.holder = document.createElement("div");
37029 this.holder.appendChild(this.wrap);
37032 var insertBefore = refNode ? refNode.ui.getEl() : null;
37034 targetNode.insertBefore(this.wrap, insertBefore);
37036 targetNode.appendChild(this.wrap);
37038 this.node.renderIndent(true);
37042 addClass : function(cls){
37044 Roo.fly(this.elNode).addClass(cls);
37048 removeClass : function(cls){
37050 Roo.fly(this.elNode).removeClass(cls);
37054 remove : function(){
37056 this.holder = document.createElement("div");
37057 this.holder.appendChild(this.wrap);
37061 fireEvent : function(){
37062 return this.node.fireEvent.apply(this.node, arguments);
37065 initEvents : function(){
37066 this.node.on("move", this.onMove, this);
37067 var E = Roo.EventManager;
37068 var a = this.anchor;
37070 var el = Roo.fly(a, '_treeui');
37072 if(Roo.isOpera){ // opera render bug ignores the CSS
37073 el.setStyle("text-decoration", "none");
37076 el.on("click", this.onClick, this);
37077 el.on("dblclick", this.onDblClick, this);
37080 Roo.EventManager.on(this.checkbox,
37081 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
37084 el.on("contextmenu", this.onContextMenu, this);
37086 var icon = Roo.fly(this.iconNode);
37087 icon.on("click", this.onClick, this);
37088 icon.on("dblclick", this.onDblClick, this);
37089 icon.on("contextmenu", this.onContextMenu, this);
37090 E.on(this.ecNode, "click", this.ecClick, this, true);
37092 if(this.node.disabled){
37093 this.addClass("x-tree-node-disabled");
37095 if(this.node.hidden){
37096 this.addClass("x-tree-node-disabled");
37098 var ot = this.node.getOwnerTree();
37099 var dd = ot ? (ot.enableDD || ot.enableDrag || ot.enableDrop) : false;
37100 if(dd && (!this.node.isRoot || ot.rootVisible)){
37101 Roo.dd.Registry.register(this.elNode, {
37103 handles: this.getDDHandles(),
37109 getDDHandles : function(){
37110 return [this.iconNode, this.textNode];
37115 this.wrap.style.display = "none";
37121 this.wrap.style.display = "";
37125 onContextMenu : function(e){
37126 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
37127 e.preventDefault();
37129 this.fireEvent("contextmenu", this.node, e);
37133 onClick : function(e){
37138 if(this.fireEvent("beforeclick", this.node, e) !== false){
37139 if(!this.disabled && this.node.attributes.href){
37140 this.fireEvent("click", this.node, e);
37143 e.preventDefault();
37148 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
37149 this.node.toggle();
37152 this.fireEvent("click", this.node, e);
37158 onDblClick : function(e){
37159 e.preventDefault();
37164 this.toggleCheck();
37166 if(!this.animating && this.node.hasChildNodes()){
37167 this.node.toggle();
37169 this.fireEvent("dblclick", this.node, e);
37172 onCheckChange : function(){
37173 var checked = this.checkbox.checked;
37174 this.node.attributes.checked = checked;
37175 this.fireEvent('checkchange', this.node, checked);
37178 ecClick : function(e){
37179 if(!this.animating && this.node.hasChildNodes()){
37180 this.node.toggle();
37184 startDrop : function(){
37185 this.dropping = true;
37188 // delayed drop so the click event doesn't get fired on a drop
37189 endDrop : function(){
37190 setTimeout(function(){
37191 this.dropping = false;
37192 }.createDelegate(this), 50);
37195 expand : function(){
37196 this.updateExpandIcon();
37197 this.ctNode.style.display = "";
37200 focus : function(){
37201 if(!this.node.preventHScroll){
37202 try{this.anchor.focus();
37204 }else if(!Roo.isIE){
37206 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
37207 var l = noscroll.scrollLeft;
37208 this.anchor.focus();
37209 noscroll.scrollLeft = l;
37214 toggleCheck : function(value){
37215 var cb = this.checkbox;
37217 cb.checked = (value === undefined ? !cb.checked : value);
37223 this.anchor.blur();
37227 animExpand : function(callback){
37228 var ct = Roo.get(this.ctNode);
37230 if(!this.node.hasChildNodes()){
37231 this.updateExpandIcon();
37232 this.ctNode.style.display = "";
37233 Roo.callback(callback);
37236 this.animating = true;
37237 this.updateExpandIcon();
37240 callback : function(){
37241 this.animating = false;
37242 Roo.callback(callback);
37245 duration: this.node.ownerTree.duration || .25
37249 highlight : function(){
37250 var tree = this.node.getOwnerTree();
37251 Roo.fly(this.wrap).highlight(
37252 tree.hlColor || "C3DAF9",
37253 {endColor: tree.hlBaseColor}
37257 collapse : function(){
37258 this.updateExpandIcon();
37259 this.ctNode.style.display = "none";
37262 animCollapse : function(callback){
37263 var ct = Roo.get(this.ctNode);
37264 ct.enableDisplayMode('block');
37267 this.animating = true;
37268 this.updateExpandIcon();
37271 callback : function(){
37272 this.animating = false;
37273 Roo.callback(callback);
37276 duration: this.node.ownerTree.duration || .25
37280 getContainer : function(){
37281 return this.ctNode;
37284 getEl : function(){
37288 appendDDGhost : function(ghostNode){
37289 ghostNode.appendChild(this.elNode.cloneNode(true));
37292 getDDRepairXY : function(){
37293 return Roo.lib.Dom.getXY(this.iconNode);
37296 onRender : function(){
37300 render : function(bulkRender){
37301 var n = this.node, a = n.attributes;
37302 var targetNode = n.parentNode ?
37303 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
37305 if(!this.rendered){
37306 this.rendered = true;
37308 this.renderElements(n, a, targetNode, bulkRender);
37311 if(this.textNode.setAttributeNS){
37312 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
37314 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
37317 this.textNode.setAttribute("ext:qtip", a.qtip);
37319 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
37322 }else if(a.qtipCfg){
37323 a.qtipCfg.target = Roo.id(this.textNode);
37324 Roo.QuickTips.register(a.qtipCfg);
37327 if(!this.node.expanded){
37328 this.updateExpandIcon();
37331 if(bulkRender === true) {
37332 targetNode.appendChild(this.wrap);
37337 renderElements : function(n, a, targetNode, bulkRender)
37339 // add some indent caching, this helps performance when rendering a large tree
37340 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
37341 var t = n.getOwnerTree();
37342 var txt = t && t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
37343 if (typeof(n.attributes.html) != 'undefined') {
37344 txt = n.attributes.html;
37346 var tip = t && t.rendererTip ? t.rendererTip(n.attributes) : txt;
37347 var cb = typeof a.checked == 'boolean';
37348 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
37349 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
37350 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
37351 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
37352 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
37353 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
37354 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
37355 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
37356 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
37357 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
37360 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
37361 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
37362 n.nextSibling.ui.getEl(), buf.join(""));
37364 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
37367 this.elNode = this.wrap.childNodes[0];
37368 this.ctNode = this.wrap.childNodes[1];
37369 var cs = this.elNode.childNodes;
37370 this.indentNode = cs[0];
37371 this.ecNode = cs[1];
37372 this.iconNode = cs[2];
37375 this.checkbox = cs[3];
37378 this.anchor = cs[index];
37379 this.textNode = cs[index].firstChild;
37382 getAnchor : function(){
37383 return this.anchor;
37386 getTextEl : function(){
37387 return this.textNode;
37390 getIconEl : function(){
37391 return this.iconNode;
37394 isChecked : function(){
37395 return this.checkbox ? this.checkbox.checked : false;
37398 updateExpandIcon : function(){
37400 var n = this.node, c1, c2;
37401 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
37402 var hasChild = n.hasChildNodes();
37406 c1 = "x-tree-node-collapsed";
37407 c2 = "x-tree-node-expanded";
37410 c1 = "x-tree-node-expanded";
37411 c2 = "x-tree-node-collapsed";
37414 this.removeClass("x-tree-node-leaf");
37415 this.wasLeaf = false;
37417 if(this.c1 != c1 || this.c2 != c2){
37418 Roo.fly(this.elNode).replaceClass(c1, c2);
37419 this.c1 = c1; this.c2 = c2;
37422 // this changes non-leafs into leafs if they have no children.
37423 // it's not very rational behaviour..
37425 if(!this.wasLeaf && this.node.leaf){
37426 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
37429 this.wasLeaf = true;
37432 var ecc = "x-tree-ec-icon "+cls;
37433 if(this.ecc != ecc){
37434 this.ecNode.className = ecc;
37440 getChildIndent : function(){
37441 if(!this.childIndent){
37445 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
37447 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
37449 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
37454 this.childIndent = buf.join("");
37456 return this.childIndent;
37459 renderIndent : function(){
37462 var p = this.node.parentNode;
37464 indent = p.ui.getChildIndent();
37466 if(this.indentMarkup != indent){ // don't rerender if not required
37467 this.indentNode.innerHTML = indent;
37468 this.indentMarkup = indent;
37470 this.updateExpandIcon();
37475 Roo.tree.RootTreeNodeUI = function(){
37476 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
37478 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
37479 render : function(){
37480 if(!this.rendered){
37481 var targetNode = this.node.ownerTree.innerCt.dom;
37482 this.node.expanded = true;
37483 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
37484 this.wrap = this.ctNode = targetNode.firstChild;
37487 collapse : function(){
37489 expand : function(){
37493 * Ext JS Library 1.1.1
37494 * Copyright(c) 2006-2007, Ext JS, LLC.
37496 * Originally Released Under LGPL - original licence link has changed is not relivant.
37499 * <script type="text/javascript">
37502 * @class Roo.tree.TreeLoader
37503 * @extends Roo.util.Observable
37504 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
37505 * nodes from a specified URL. The response must be a javascript Array definition
37506 * who's elements are node definition objects. eg:
37511 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
37512 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
37519 * The old style respose with just an array is still supported, but not recommended.
37522 * A server request is sent, and child nodes are loaded only when a node is expanded.
37523 * The loading node's id is passed to the server under the parameter name "node" to
37524 * enable the server to produce the correct child nodes.
37526 * To pass extra parameters, an event handler may be attached to the "beforeload"
37527 * event, and the parameters specified in the TreeLoader's baseParams property:
37529 myTreeLoader.on("beforeload", function(treeLoader, node) {
37530 this.baseParams.category = node.attributes.category;
37535 * This would pass an HTTP parameter called "category" to the server containing
37536 * the value of the Node's "category" attribute.
37538 * Creates a new Treeloader.
37539 * @param {Object} config A config object containing config properties.
37541 Roo.tree.TreeLoader = function(config){
37542 this.baseParams = {};
37543 this.requestMethod = "POST";
37544 Roo.apply(this, config);
37549 * @event beforeload
37550 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
37551 * @param {Object} This TreeLoader object.
37552 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
37553 * @param {Object} callback The callback function specified in the {@link #load} call.
37558 * Fires when the node has been successfuly loaded.
37559 * @param {Object} This TreeLoader object.
37560 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
37561 * @param {Object} response The response object containing the data from the server.
37565 * @event loadexception
37566 * Fires if the network request failed.
37567 * @param {Object} This TreeLoader object.
37568 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
37569 * @param {Object} response The response object containing the data from the server.
37571 loadexception : true,
37574 * Fires before a node is created, enabling you to return custom Node types
37575 * @param {Object} This TreeLoader object.
37576 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
37581 Roo.tree.TreeLoader.superclass.constructor.call(this);
37584 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
37586 * @cfg {String} dataUrl The URL from which to request a Json string which
37587 * specifies an array of node definition object representing the child nodes
37591 * @cfg {String} requestMethod either GET or POST
37592 * defaults to POST (due to BC)
37596 * @cfg {Object} baseParams (optional) An object containing properties which
37597 * specify HTTP parameters to be passed to each request for child nodes.
37600 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
37601 * created by this loader. If the attributes sent by the server have an attribute in this object,
37602 * they take priority.
37605 * @cfg {Object} uiProviders (optional) An object containing properties which
37607 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
37608 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
37609 * <i>uiProvider</i> attribute of a returned child node is a string rather
37610 * than a reference to a TreeNodeUI implementation, this that string value
37611 * is used as a property name in the uiProviders object. You can define the provider named
37612 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
37617 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
37618 * child nodes before loading.
37620 clearOnLoad : true,
37623 * @cfg {String} root (optional) Default to false. Use this to read data from an object
37624 * property on loading, rather than expecting an array. (eg. more compatible to a standard
37625 * Grid query { data : [ .....] }
37630 * @cfg {String} queryParam (optional)
37631 * Name of the query as it will be passed on the querystring (defaults to 'node')
37632 * eg. the request will be ?node=[id]
37639 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
37640 * This is called automatically when a node is expanded, but may be used to reload
37641 * a node (or append new children if the {@link #clearOnLoad} option is false.)
37642 * @param {Roo.tree.TreeNode} node
37643 * @param {Function} callback
37645 load : function(node, callback){
37646 if(this.clearOnLoad){
37647 while(node.firstChild){
37648 node.removeChild(node.firstChild);
37651 if(node.attributes.children){ // preloaded json children
37652 var cs = node.attributes.children;
37653 for(var i = 0, len = cs.length; i < len; i++){
37654 node.appendChild(this.createNode(cs[i]));
37656 if(typeof callback == "function"){
37659 }else if(this.dataUrl){
37660 this.requestData(node, callback);
37664 getParams: function(node){
37665 var buf = [], bp = this.baseParams;
37666 for(var key in bp){
37667 if(typeof bp[key] != "function"){
37668 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
37671 var n = this.queryParam === false ? 'node' : this.queryParam;
37672 buf.push(n + "=", encodeURIComponent(node.id));
37673 return buf.join("");
37676 requestData : function(node, callback){
37677 if(this.fireEvent("beforeload", this, node, callback) !== false){
37678 this.transId = Roo.Ajax.request({
37679 method:this.requestMethod,
37680 url: this.dataUrl||this.url,
37681 success: this.handleResponse,
37682 failure: this.handleFailure,
37684 argument: {callback: callback, node: node},
37685 params: this.getParams(node)
37688 // if the load is cancelled, make sure we notify
37689 // the node that we are done
37690 if(typeof callback == "function"){
37696 isLoading : function(){
37697 return this.transId ? true : false;
37700 abort : function(){
37701 if(this.isLoading()){
37702 Roo.Ajax.abort(this.transId);
37707 createNode : function(attr)
37709 // apply baseAttrs, nice idea Corey!
37710 if(this.baseAttrs){
37711 Roo.applyIf(attr, this.baseAttrs);
37713 if(this.applyLoader !== false){
37714 attr.loader = this;
37716 // uiProvider = depreciated..
37718 if(typeof(attr.uiProvider) == 'string'){
37719 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
37720 /** eval:var:attr */ eval(attr.uiProvider);
37722 if(typeof(this.uiProviders['default']) != 'undefined') {
37723 attr.uiProvider = this.uiProviders['default'];
37726 this.fireEvent('create', this, attr);
37728 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
37730 new Roo.tree.TreeNode(attr) :
37731 new Roo.tree.AsyncTreeNode(attr));
37734 processResponse : function(response, node, callback)
37736 var json = response.responseText;
37739 var o = Roo.decode(json);
37741 if (this.root === false && typeof(o.success) != undefined) {
37742 this.root = 'data'; // the default behaviour for list like data..
37745 if (this.root !== false && !o.success) {
37746 // it's a failure condition.
37747 var a = response.argument;
37748 this.fireEvent("loadexception", this, a.node, response);
37749 Roo.log("Load failed - should have a handler really");
37755 if (this.root !== false) {
37759 for(var i = 0, len = o.length; i < len; i++){
37760 var n = this.createNode(o[i]);
37762 node.appendChild(n);
37765 if(typeof callback == "function"){
37766 callback(this, node);
37769 this.handleFailure(response);
37773 handleResponse : function(response){
37774 this.transId = false;
37775 var a = response.argument;
37776 this.processResponse(response, a.node, a.callback);
37777 this.fireEvent("load", this, a.node, response);
37780 handleFailure : function(response)
37782 // should handle failure better..
37783 this.transId = false;
37784 var a = response.argument;
37785 this.fireEvent("loadexception", this, a.node, response);
37786 if(typeof a.callback == "function"){
37787 a.callback(this, a.node);
37792 * Ext JS Library 1.1.1
37793 * Copyright(c) 2006-2007, Ext JS, LLC.
37795 * Originally Released Under LGPL - original licence link has changed is not relivant.
37798 * <script type="text/javascript">
37802 * @class Roo.tree.TreeFilter
37803 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
37804 * @param {TreePanel} tree
37805 * @param {Object} config (optional)
37807 Roo.tree.TreeFilter = function(tree, config){
37809 this.filtered = {};
37810 Roo.apply(this, config);
37813 Roo.tree.TreeFilter.prototype = {
37820 * Filter the data by a specific attribute.
37821 * @param {String/RegExp} value Either string that the attribute value
37822 * should start with or a RegExp to test against the attribute
37823 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
37824 * @param {TreeNode} startNode (optional) The node to start the filter at.
37826 filter : function(value, attr, startNode){
37827 attr = attr || "text";
37829 if(typeof value == "string"){
37830 var vlen = value.length;
37831 // auto clear empty filter
37832 if(vlen == 0 && this.clearBlank){
37836 value = value.toLowerCase();
37838 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
37840 }else if(value.exec){ // regex?
37842 return value.test(n.attributes[attr]);
37845 throw 'Illegal filter type, must be string or regex';
37847 this.filterBy(f, null, startNode);
37851 * Filter by a function. The passed function will be called with each
37852 * node in the tree (or from the startNode). If the function returns true, the node is kept
37853 * otherwise it is filtered. If a node is filtered, its children are also filtered.
37854 * @param {Function} fn The filter function
37855 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
37857 filterBy : function(fn, scope, startNode){
37858 startNode = startNode || this.tree.root;
37859 if(this.autoClear){
37862 var af = this.filtered, rv = this.reverse;
37863 var f = function(n){
37864 if(n == startNode){
37870 var m = fn.call(scope || n, n);
37878 startNode.cascade(f);
37881 if(typeof id != "function"){
37883 if(n && n.parentNode){
37884 n.parentNode.removeChild(n);
37892 * Clears the current filter. Note: with the "remove" option
37893 * set a filter cannot be cleared.
37895 clear : function(){
37897 var af = this.filtered;
37899 if(typeof id != "function"){
37906 this.filtered = {};
37911 * Ext JS Library 1.1.1
37912 * Copyright(c) 2006-2007, Ext JS, LLC.
37914 * Originally Released Under LGPL - original licence link has changed is not relivant.
37917 * <script type="text/javascript">
37922 * @class Roo.tree.TreeSorter
37923 * Provides sorting of nodes in a TreePanel
37925 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
37926 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
37927 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
37928 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
37929 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
37930 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
37932 * @param {TreePanel} tree
37933 * @param {Object} config
37935 Roo.tree.TreeSorter = function(tree, config){
37936 Roo.apply(this, config);
37937 tree.on("beforechildrenrendered", this.doSort, this);
37938 tree.on("append", this.updateSort, this);
37939 tree.on("insert", this.updateSort, this);
37941 var dsc = this.dir && this.dir.toLowerCase() == "desc";
37942 var p = this.property || "text";
37943 var sortType = this.sortType;
37944 var fs = this.folderSort;
37945 var cs = this.caseSensitive === true;
37946 var leafAttr = this.leafAttr || 'leaf';
37948 this.sortFn = function(n1, n2){
37950 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
37953 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
37957 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
37958 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
37960 return dsc ? +1 : -1;
37962 return dsc ? -1 : +1;
37969 Roo.tree.TreeSorter.prototype = {
37970 doSort : function(node){
37971 node.sort(this.sortFn);
37974 compareNodes : function(n1, n2){
37975 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
37978 updateSort : function(tree, node){
37979 if(node.childrenRendered){
37980 this.doSort.defer(1, this, [node]);
37985 * Ext JS Library 1.1.1
37986 * Copyright(c) 2006-2007, Ext JS, LLC.
37988 * Originally Released Under LGPL - original licence link has changed is not relivant.
37991 * <script type="text/javascript">
37994 if(Roo.dd.DropZone){
37996 Roo.tree.TreeDropZone = function(tree, config){
37997 this.allowParentInsert = false;
37998 this.allowContainerDrop = false;
37999 this.appendOnly = false;
38000 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
38002 this.lastInsertClass = "x-tree-no-status";
38003 this.dragOverData = {};
38006 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
38007 ddGroup : "TreeDD",
38010 expandDelay : 1000,
38012 expandNode : function(node){
38013 if(node.hasChildNodes() && !node.isExpanded()){
38014 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
38018 queueExpand : function(node){
38019 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
38022 cancelExpand : function(){
38023 if(this.expandProcId){
38024 clearTimeout(this.expandProcId);
38025 this.expandProcId = false;
38029 isValidDropPoint : function(n, pt, dd, e, data){
38030 if(!n || !data){ return false; }
38031 var targetNode = n.node;
38032 var dropNode = data.node;
38033 // default drop rules
38034 if(!(targetNode && targetNode.isTarget && pt)){
38037 if(pt == "append" && targetNode.allowChildren === false){
38040 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
38043 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
38046 // reuse the object
38047 var overEvent = this.dragOverData;
38048 overEvent.tree = this.tree;
38049 overEvent.target = targetNode;
38050 overEvent.data = data;
38051 overEvent.point = pt;
38052 overEvent.source = dd;
38053 overEvent.rawEvent = e;
38054 overEvent.dropNode = dropNode;
38055 overEvent.cancel = false;
38056 var result = this.tree.fireEvent("nodedragover", overEvent);
38057 return overEvent.cancel === false && result !== false;
38060 getDropPoint : function(e, n, dd)
38064 return tn.allowChildren !== false ? "append" : false; // always append for root
38066 var dragEl = n.ddel;
38067 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
38068 var y = Roo.lib.Event.getPageY(e);
38069 //var noAppend = tn.allowChildren === false || tn.isLeaf();
38071 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
38072 var noAppend = tn.allowChildren === false;
38073 if(this.appendOnly || tn.parentNode.allowChildren === false){
38074 return noAppend ? false : "append";
38076 var noBelow = false;
38077 if(!this.allowParentInsert){
38078 noBelow = tn.hasChildNodes() && tn.isExpanded();
38080 var q = (b - t) / (noAppend ? 2 : 3);
38081 if(y >= t && y < (t + q)){
38083 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
38090 onNodeEnter : function(n, dd, e, data)
38092 this.cancelExpand();
38095 onNodeOver : function(n, dd, e, data)
38098 var pt = this.getDropPoint(e, n, dd);
38101 // auto node expand check
38102 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
38103 this.queueExpand(node);
38104 }else if(pt != "append"){
38105 this.cancelExpand();
38108 // set the insert point style on the target node
38109 var returnCls = this.dropNotAllowed;
38110 if(this.isValidDropPoint(n, pt, dd, e, data)){
38115 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
38116 cls = "x-tree-drag-insert-above";
38117 }else if(pt == "below"){
38118 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
38119 cls = "x-tree-drag-insert-below";
38121 returnCls = "x-tree-drop-ok-append";
38122 cls = "x-tree-drag-append";
38124 if(this.lastInsertClass != cls){
38125 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
38126 this.lastInsertClass = cls;
38133 onNodeOut : function(n, dd, e, data){
38135 this.cancelExpand();
38136 this.removeDropIndicators(n);
38139 onNodeDrop : function(n, dd, e, data){
38140 var point = this.getDropPoint(e, n, dd);
38141 var targetNode = n.node;
38142 targetNode.ui.startDrop();
38143 if(!this.isValidDropPoint(n, point, dd, e, data)){
38144 targetNode.ui.endDrop();
38147 // first try to find the drop node
38148 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
38151 target: targetNode,
38156 dropNode: dropNode,
38159 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
38160 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
38161 targetNode.ui.endDrop();
38164 // allow target changing
38165 targetNode = dropEvent.target;
38166 if(point == "append" && !targetNode.isExpanded()){
38167 targetNode.expand(false, null, function(){
38168 this.completeDrop(dropEvent);
38169 }.createDelegate(this));
38171 this.completeDrop(dropEvent);
38176 completeDrop : function(de){
38177 var ns = de.dropNode, p = de.point, t = de.target;
38178 if(!(ns instanceof Array)){
38182 for(var i = 0, len = ns.length; i < len; i++){
38185 t.parentNode.insertBefore(n, t);
38186 }else if(p == "below"){
38187 t.parentNode.insertBefore(n, t.nextSibling);
38193 if(this.tree.hlDrop){
38197 this.tree.fireEvent("nodedrop", de);
38200 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
38201 if(this.tree.hlDrop){
38202 dropNode.ui.focus();
38203 dropNode.ui.highlight();
38205 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
38208 getTree : function(){
38212 removeDropIndicators : function(n){
38215 Roo.fly(el).removeClass([
38216 "x-tree-drag-insert-above",
38217 "x-tree-drag-insert-below",
38218 "x-tree-drag-append"]);
38219 this.lastInsertClass = "_noclass";
38223 beforeDragDrop : function(target, e, id){
38224 this.cancelExpand();
38228 afterRepair : function(data){
38229 if(data && Roo.enableFx){
38230 data.node.ui.highlight();
38240 * Ext JS Library 1.1.1
38241 * Copyright(c) 2006-2007, Ext JS, LLC.
38243 * Originally Released Under LGPL - original licence link has changed is not relivant.
38246 * <script type="text/javascript">
38250 if(Roo.dd.DragZone){
38251 Roo.tree.TreeDragZone = function(tree, config){
38252 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
38256 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
38257 ddGroup : "TreeDD",
38259 onBeforeDrag : function(data, e){
38261 return n && n.draggable && !n.disabled;
38265 onInitDrag : function(e){
38266 var data = this.dragData;
38267 this.tree.getSelectionModel().select(data.node);
38268 this.proxy.update("");
38269 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
38270 this.tree.fireEvent("startdrag", this.tree, data.node, e);
38273 getRepairXY : function(e, data){
38274 return data.node.ui.getDDRepairXY();
38277 onEndDrag : function(data, e){
38278 this.tree.fireEvent("enddrag", this.tree, data.node, e);
38283 onValidDrop : function(dd, e, id){
38284 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
38288 beforeInvalidDrop : function(e, id){
38289 // this scrolls the original position back into view
38290 var sm = this.tree.getSelectionModel();
38291 sm.clearSelections();
38292 sm.select(this.dragData.node);
38297 * Ext JS Library 1.1.1
38298 * Copyright(c) 2006-2007, Ext JS, LLC.
38300 * Originally Released Under LGPL - original licence link has changed is not relivant.
38303 * <script type="text/javascript">
38306 * @class Roo.tree.TreeEditor
38307 * @extends Roo.Editor
38308 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
38309 * as the editor field.
38311 * @param {Object} config (used to be the tree panel.)
38312 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
38314 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
38315 * @cfg {Roo.form.TextField} field [required] The field configuration
38319 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
38322 if (oldconfig) { // old style..
38323 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
38326 tree = config.tree;
38327 config.field = config.field || {};
38328 config.field.xtype = 'TextField';
38329 field = Roo.factory(config.field, Roo.form);
38331 config = config || {};
38336 * @event beforenodeedit
38337 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
38338 * false from the handler of this event.
38339 * @param {Editor} this
38340 * @param {Roo.tree.Node} node
38342 "beforenodeedit" : true
38346 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
38350 tree.on('beforeclick', this.beforeNodeClick, this);
38351 tree.getTreeEl().on('mousedown', this.hide, this);
38352 this.on('complete', this.updateNode, this);
38353 this.on('beforestartedit', this.fitToTree, this);
38354 this.on('startedit', this.bindScroll, this, {delay:10});
38355 this.on('specialkey', this.onSpecialKey, this);
38358 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
38360 * @cfg {String} alignment
38361 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
38367 * @cfg {Boolean} hideEl
38368 * True to hide the bound element while the editor is displayed (defaults to false)
38372 * @cfg {String} cls
38373 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
38375 cls: "x-small-editor x-tree-editor",
38377 * @cfg {Boolean} shim
38378 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
38384 * @cfg {Number} maxWidth
38385 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
38386 * the containing tree element's size, it will be automatically limited for you to the container width, taking
38387 * scroll and client offsets into account prior to each edit.
38394 fitToTree : function(ed, el){
38395 var td = this.tree.getTreeEl().dom, nd = el.dom;
38396 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
38397 td.scrollLeft = nd.offsetLeft;
38401 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
38402 this.setSize(w, '');
38404 return this.fireEvent('beforenodeedit', this, this.editNode);
38409 triggerEdit : function(node){
38410 this.completeEdit();
38411 this.editNode = node;
38412 this.startEdit(node.ui.textNode, node.text);
38416 bindScroll : function(){
38417 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
38421 beforeNodeClick : function(node, e){
38422 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
38423 this.lastClick = new Date();
38424 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
38426 this.triggerEdit(node);
38433 updateNode : function(ed, value){
38434 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
38435 this.editNode.setText(value);
38439 onHide : function(){
38440 Roo.tree.TreeEditor.superclass.onHide.call(this);
38442 this.editNode.ui.focus();
38447 onSpecialKey : function(field, e){
38448 var k = e.getKey();
38452 }else if(k == e.ENTER && !e.hasModifier()){
38454 this.completeEdit();
38457 });//<Script type="text/javascript">
38460 * Ext JS Library 1.1.1
38461 * Copyright(c) 2006-2007, Ext JS, LLC.
38463 * Originally Released Under LGPL - original licence link has changed is not relivant.
38466 * <script type="text/javascript">
38470 * Not documented??? - probably should be...
38473 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
38474 //focus: Roo.emptyFn, // prevent odd scrolling behavior
38476 renderElements : function(n, a, targetNode, bulkRender){
38477 //consel.log("renderElements?");
38478 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
38480 var t = n.getOwnerTree();
38481 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
38483 var cols = t.columns;
38484 var bw = t.borderWidth;
38486 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
38487 var cb = typeof a.checked == "boolean";
38488 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
38489 var colcls = 'x-t-' + tid + '-c0';
38491 '<li class="x-tree-node">',
38494 '<div class="x-tree-node-el ', a.cls,'">',
38496 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
38499 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
38500 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
38501 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
38502 (a.icon ? ' x-tree-node-inline-icon' : ''),
38503 (a.iconCls ? ' '+a.iconCls : ''),
38504 '" unselectable="on" />',
38505 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
38506 (a.checked ? 'checked="checked" />' : ' />')) : ''),
38508 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
38509 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
38510 '<span unselectable="on" qtip="' + tx + '">',
38514 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
38515 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
38517 for(var i = 1, len = cols.length; i < len; i++){
38519 colcls = 'x-t-' + tid + '-c' +i;
38520 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
38521 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
38522 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
38528 '<div class="x-clear"></div></div>',
38529 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
38532 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
38533 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
38534 n.nextSibling.ui.getEl(), buf.join(""));
38536 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
38538 var el = this.wrap.firstChild;
38540 this.elNode = el.firstChild;
38541 this.ranchor = el.childNodes[1];
38542 this.ctNode = this.wrap.childNodes[1];
38543 var cs = el.firstChild.childNodes;
38544 this.indentNode = cs[0];
38545 this.ecNode = cs[1];
38546 this.iconNode = cs[2];
38549 this.checkbox = cs[3];
38552 this.anchor = cs[index];
38554 this.textNode = cs[index].firstChild;
38556 //el.on("click", this.onClick, this);
38557 //el.on("dblclick", this.onDblClick, this);
38560 // console.log(this);
38562 initEvents : function(){
38563 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
38566 var a = this.ranchor;
38568 var el = Roo.get(a);
38570 if(Roo.isOpera){ // opera render bug ignores the CSS
38571 el.setStyle("text-decoration", "none");
38574 el.on("click", this.onClick, this);
38575 el.on("dblclick", this.onDblClick, this);
38576 el.on("contextmenu", this.onContextMenu, this);
38580 /*onSelectedChange : function(state){
38583 this.addClass("x-tree-selected");
38586 this.removeClass("x-tree-selected");
38589 addClass : function(cls){
38591 Roo.fly(this.elRow).addClass(cls);
38597 removeClass : function(cls){
38599 Roo.fly(this.elRow).removeClass(cls);
38605 });//<Script type="text/javascript">
38609 * Ext JS Library 1.1.1
38610 * Copyright(c) 2006-2007, Ext JS, LLC.
38612 * Originally Released Under LGPL - original licence link has changed is not relivant.
38615 * <script type="text/javascript">
38620 * @class Roo.tree.ColumnTree
38621 * @extends Roo.tree.TreePanel
38622 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
38623 * @cfg {int} borderWidth compined right/left border allowance
38625 * @param {String/HTMLElement/Element} el The container element
38626 * @param {Object} config
38628 Roo.tree.ColumnTree = function(el, config)
38630 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
38634 * Fire this event on a container when it resizes
38635 * @param {int} w Width
38636 * @param {int} h Height
38640 this.on('resize', this.onResize, this);
38643 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
38647 borderWidth: Roo.isBorderBox ? 0 : 2,
38650 render : function(){
38651 // add the header.....
38653 Roo.tree.ColumnTree.superclass.render.apply(this);
38655 this.el.addClass('x-column-tree');
38657 this.headers = this.el.createChild(
38658 {cls:'x-tree-headers'},this.innerCt.dom);
38660 var cols = this.columns, c;
38661 var totalWidth = 0;
38663 var len = cols.length;
38664 for(var i = 0; i < len; i++){
38666 totalWidth += c.width;
38667 this.headEls.push(this.headers.createChild({
38668 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
38670 cls:'x-tree-hd-text',
38673 style:'width:'+(c.width-this.borderWidth)+'px;'
38676 this.headers.createChild({cls:'x-clear'});
38677 // prevent floats from wrapping when clipped
38678 this.headers.setWidth(totalWidth);
38679 //this.innerCt.setWidth(totalWidth);
38680 this.innerCt.setStyle({ overflow: 'auto' });
38681 this.onResize(this.width, this.height);
38685 onResize : function(w,h)
38690 this.innerCt.setWidth(this.width);
38691 this.innerCt.setHeight(this.height-20);
38694 var cols = this.columns, c;
38695 var totalWidth = 0;
38697 var len = cols.length;
38698 for(var i = 0; i < len; i++){
38700 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
38701 // it's the expander..
38702 expEl = this.headEls[i];
38705 totalWidth += c.width;
38709 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
38711 this.headers.setWidth(w-20);
38720 * Ext JS Library 1.1.1
38721 * Copyright(c) 2006-2007, Ext JS, LLC.
38723 * Originally Released Under LGPL - original licence link has changed is not relivant.
38726 * <script type="text/javascript">
38730 * @class Roo.menu.Menu
38731 * @extends Roo.util.Observable
38732 * @children Roo.menu.Item Roo.menu.Separator Roo.menu.TextItem
38733 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
38734 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
38736 * Creates a new Menu
38737 * @param {Object} config Configuration options
38739 Roo.menu.Menu = function(config){
38741 Roo.menu.Menu.superclass.constructor.call(this, config);
38743 this.id = this.id || Roo.id();
38746 * @event beforeshow
38747 * Fires before this menu is displayed
38748 * @param {Roo.menu.Menu} this
38752 * @event beforehide
38753 * Fires before this menu is hidden
38754 * @param {Roo.menu.Menu} this
38759 * Fires after this menu is displayed
38760 * @param {Roo.menu.Menu} this
38765 * Fires after this menu is hidden
38766 * @param {Roo.menu.Menu} this
38771 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
38772 * @param {Roo.menu.Menu} this
38773 * @param {Roo.menu.Item} menuItem The menu item that was clicked
38774 * @param {Roo.EventObject} e
38779 * Fires when the mouse is hovering over this menu
38780 * @param {Roo.menu.Menu} this
38781 * @param {Roo.EventObject} e
38782 * @param {Roo.menu.Item} menuItem The menu item that was clicked
38787 * Fires when the mouse exits this menu
38788 * @param {Roo.menu.Menu} this
38789 * @param {Roo.EventObject} e
38790 * @param {Roo.menu.Item} menuItem The menu item that was clicked
38795 * Fires when a menu item contained in this menu is clicked
38796 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
38797 * @param {Roo.EventObject} e
38801 if (this.registerMenu) {
38802 Roo.menu.MenuMgr.register(this);
38805 var mis = this.items;
38806 this.items = new Roo.util.MixedCollection();
38808 this.add.apply(this, mis);
38812 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
38814 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
38818 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
38819 * for bottom-right shadow (defaults to "sides")
38823 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
38824 * this menu (defaults to "tl-tr?")
38826 subMenuAlign : "tl-tr?",
38828 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
38829 * relative to its element of origin (defaults to "tl-bl?")
38831 defaultAlign : "tl-bl?",
38833 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
38835 allowOtherMenus : false,
38837 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
38839 registerMenu : true,
38844 render : function(){
38848 var el = this.el = new Roo.Layer({
38850 shadow:this.shadow,
38852 parentEl: this.parentEl || document.body,
38856 this.keyNav = new Roo.menu.MenuNav(this);
38859 el.addClass("x-menu-plain");
38862 el.addClass(this.cls);
38864 // generic focus element
38865 this.focusEl = el.createChild({
38866 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
38868 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
38869 //disabling touch- as it's causing issues ..
38870 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
38871 ul.on('click' , this.onClick, this);
38874 ul.on("mouseover", this.onMouseOver, this);
38875 ul.on("mouseout", this.onMouseOut, this);
38876 this.items.each(function(item){
38881 var li = document.createElement("li");
38882 li.className = "x-menu-list-item";
38883 ul.dom.appendChild(li);
38884 item.render(li, this);
38891 autoWidth : function(){
38892 var el = this.el, ul = this.ul;
38896 var w = this.width;
38899 }else if(Roo.isIE){
38900 el.setWidth(this.minWidth);
38901 var t = el.dom.offsetWidth; // force recalc
38902 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
38907 delayAutoWidth : function(){
38910 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
38912 this.awTask.delay(20);
38917 findTargetItem : function(e){
38918 var t = e.getTarget(".x-menu-list-item", this.ul, true);
38919 if(t && t.menuItemId){
38920 return this.items.get(t.menuItemId);
38925 onClick : function(e){
38926 Roo.log("menu.onClick");
38927 var t = this.findTargetItem(e);
38932 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
38933 if(t == this.activeItem && t.shouldDeactivate(e)){
38934 this.activeItem.deactivate();
38935 delete this.activeItem;
38939 this.setActiveItem(t, true);
38947 this.fireEvent("click", this, t, e);
38951 setActiveItem : function(item, autoExpand){
38952 if(item != this.activeItem){
38953 if(this.activeItem){
38954 this.activeItem.deactivate();
38956 this.activeItem = item;
38957 item.activate(autoExpand);
38958 }else if(autoExpand){
38964 tryActivate : function(start, step){
38965 var items = this.items;
38966 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
38967 var item = items.get(i);
38968 if(!item.disabled && item.canActivate){
38969 this.setActiveItem(item, false);
38977 onMouseOver : function(e){
38979 if(t = this.findTargetItem(e)){
38980 if(t.canActivate && !t.disabled){
38981 this.setActiveItem(t, true);
38984 this.fireEvent("mouseover", this, e, t);
38988 onMouseOut : function(e){
38990 if(t = this.findTargetItem(e)){
38991 if(t == this.activeItem && t.shouldDeactivate(e)){
38992 this.activeItem.deactivate();
38993 delete this.activeItem;
38996 this.fireEvent("mouseout", this, e, t);
39000 * Read-only. Returns true if the menu is currently displayed, else false.
39003 isVisible : function(){
39004 return this.el && !this.hidden;
39008 * Displays this menu relative to another element
39009 * @param {String/HTMLElement/Roo.Element} element The element to align to
39010 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
39011 * the element (defaults to this.defaultAlign)
39012 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
39014 show : function(el, pos, parentMenu){
39015 this.parentMenu = parentMenu;
39019 this.fireEvent("beforeshow", this);
39020 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
39024 * Displays this menu at a specific xy position
39025 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
39026 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
39028 showAt : function(xy, parentMenu, /* private: */_e){
39029 this.parentMenu = parentMenu;
39034 this.fireEvent("beforeshow", this);
39035 xy = this.el.adjustForConstraints(xy);
39039 this.hidden = false;
39041 this.fireEvent("show", this);
39044 focus : function(){
39046 this.doFocus.defer(50, this);
39050 doFocus : function(){
39052 this.focusEl.focus();
39057 * Hides this menu and optionally all parent menus
39058 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
39060 hide : function(deep){
39061 if(this.el && this.isVisible()){
39062 this.fireEvent("beforehide", this);
39063 if(this.activeItem){
39064 this.activeItem.deactivate();
39065 this.activeItem = null;
39068 this.hidden = true;
39069 this.fireEvent("hide", this);
39071 if(deep === true && this.parentMenu){
39072 this.parentMenu.hide(true);
39077 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
39078 * Any of the following are valid:
39080 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
39081 * <li>An HTMLElement object which will be converted to a menu item</li>
39082 * <li>A menu item config object that will be created as a new menu item</li>
39083 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
39084 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
39089 var menu = new Roo.menu.Menu();
39091 // Create a menu item to add by reference
39092 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
39094 // Add a bunch of items at once using different methods.
39095 // Only the last item added will be returned.
39096 var item = menu.add(
39097 menuItem, // add existing item by ref
39098 'Dynamic Item', // new TextItem
39099 '-', // new separator
39100 { text: 'Config Item' } // new item by config
39103 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
39104 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
39107 var a = arguments, l = a.length, item;
39108 for(var i = 0; i < l; i++){
39110 if ((typeof(el) == "object") && el.xtype && el.xns) {
39111 el = Roo.factory(el, Roo.menu);
39114 if(el.render){ // some kind of Item
39115 item = this.addItem(el);
39116 }else if(typeof el == "string"){ // string
39117 if(el == "separator" || el == "-"){
39118 item = this.addSeparator();
39120 item = this.addText(el);
39122 }else if(el.tagName || el.el){ // element
39123 item = this.addElement(el);
39124 }else if(typeof el == "object"){ // must be menu item config?
39125 item = this.addMenuItem(el);
39132 * Returns this menu's underlying {@link Roo.Element} object
39133 * @return {Roo.Element} The element
39135 getEl : function(){
39143 * Adds a separator bar to the menu
39144 * @return {Roo.menu.Item} The menu item that was added
39146 addSeparator : function(){
39147 return this.addItem(new Roo.menu.Separator());
39151 * Adds an {@link Roo.Element} object to the menu
39152 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
39153 * @return {Roo.menu.Item} The menu item that was added
39155 addElement : function(el){
39156 return this.addItem(new Roo.menu.BaseItem(el));
39160 * Adds an existing object based on {@link Roo.menu.Item} to the menu
39161 * @param {Roo.menu.Item} item The menu item to add
39162 * @return {Roo.menu.Item} The menu item that was added
39164 addItem : function(item){
39165 this.items.add(item);
39167 var li = document.createElement("li");
39168 li.className = "x-menu-list-item";
39169 this.ul.dom.appendChild(li);
39170 item.render(li, this);
39171 this.delayAutoWidth();
39177 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
39178 * @param {Object} config A MenuItem config object
39179 * @return {Roo.menu.Item} The menu item that was added
39181 addMenuItem : function(config){
39182 if(!(config instanceof Roo.menu.Item)){
39183 if(typeof config.checked == "boolean"){ // must be check menu item config?
39184 config = new Roo.menu.CheckItem(config);
39186 config = new Roo.menu.Item(config);
39189 return this.addItem(config);
39193 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
39194 * @param {String} text The text to display in the menu item
39195 * @return {Roo.menu.Item} The menu item that was added
39197 addText : function(text){
39198 return this.addItem(new Roo.menu.TextItem({ text : text }));
39202 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
39203 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
39204 * @param {Roo.menu.Item} item The menu item to add
39205 * @return {Roo.menu.Item} The menu item that was added
39207 insert : function(index, item){
39208 this.items.insert(index, item);
39210 var li = document.createElement("li");
39211 li.className = "x-menu-list-item";
39212 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
39213 item.render(li, this);
39214 this.delayAutoWidth();
39220 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
39221 * @param {Roo.menu.Item} item The menu item to remove
39223 remove : function(item){
39224 this.items.removeKey(item.id);
39229 * Removes and destroys all items in the menu
39231 removeAll : function(){
39233 while(f = this.items.first()){
39239 // MenuNav is a private utility class used internally by the Menu
39240 Roo.menu.MenuNav = function(menu){
39241 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
39242 this.scope = this.menu = menu;
39245 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
39246 doRelay : function(e, h){
39247 var k = e.getKey();
39248 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
39249 this.menu.tryActivate(0, 1);
39252 return h.call(this.scope || this, e, this.menu);
39255 up : function(e, m){
39256 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
39257 m.tryActivate(m.items.length-1, -1);
39261 down : function(e, m){
39262 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
39263 m.tryActivate(0, 1);
39267 right : function(e, m){
39269 m.activeItem.expandMenu(true);
39273 left : function(e, m){
39275 if(m.parentMenu && m.parentMenu.activeItem){
39276 m.parentMenu.activeItem.activate();
39280 enter : function(e, m){
39282 e.stopPropagation();
39283 m.activeItem.onClick(e);
39284 m.fireEvent("click", this, m.activeItem);
39290 * Ext JS Library 1.1.1
39291 * Copyright(c) 2006-2007, Ext JS, LLC.
39293 * Originally Released Under LGPL - original licence link has changed is not relivant.
39296 * <script type="text/javascript">
39300 * @class Roo.menu.MenuMgr
39301 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
39304 Roo.menu.MenuMgr = function(){
39305 var menus, active, groups = {}, attached = false, lastShow = new Date();
39307 // private - called when first menu is created
39310 active = new Roo.util.MixedCollection();
39311 Roo.get(document).addKeyListener(27, function(){
39312 if(active.length > 0){
39319 function hideAll(){
39320 if(active && active.length > 0){
39321 var c = active.clone();
39322 c.each(function(m){
39329 function onHide(m){
39331 if(active.length < 1){
39332 Roo.get(document).un("mousedown", onMouseDown);
39338 function onShow(m){
39339 var last = active.last();
39340 lastShow = new Date();
39343 Roo.get(document).on("mousedown", onMouseDown);
39347 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
39348 m.parentMenu.activeChild = m;
39349 }else if(last && last.isVisible()){
39350 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
39355 function onBeforeHide(m){
39357 m.activeChild.hide();
39359 if(m.autoHideTimer){
39360 clearTimeout(m.autoHideTimer);
39361 delete m.autoHideTimer;
39366 function onBeforeShow(m){
39367 var pm = m.parentMenu;
39368 if(!pm && !m.allowOtherMenus){
39370 }else if(pm && pm.activeChild && active != m){
39371 pm.activeChild.hide();
39376 function onMouseDown(e){
39377 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
39383 function onBeforeCheck(mi, state){
39385 var g = groups[mi.group];
39386 for(var i = 0, l = g.length; i < l; i++){
39388 g[i].setChecked(false);
39397 * Hides all menus that are currently visible
39399 hideAll : function(){
39404 register : function(menu){
39408 menus[menu.id] = menu;
39409 menu.on("beforehide", onBeforeHide);
39410 menu.on("hide", onHide);
39411 menu.on("beforeshow", onBeforeShow);
39412 menu.on("show", onShow);
39413 var g = menu.group;
39414 if(g && menu.events["checkchange"]){
39418 groups[g].push(menu);
39419 menu.on("checkchange", onCheck);
39424 * Returns a {@link Roo.menu.Menu} object
39425 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
39426 * be used to generate and return a new Menu instance.
39428 get : function(menu){
39429 if(typeof menu == "string"){ // menu id
39430 return menus[menu];
39431 }else if(menu.events){ // menu instance
39433 }else if(typeof menu.length == 'number'){ // array of menu items?
39434 return new Roo.menu.Menu({items:menu});
39435 }else{ // otherwise, must be a config
39436 return new Roo.menu.Menu(menu);
39441 unregister : function(menu){
39442 delete menus[menu.id];
39443 menu.un("beforehide", onBeforeHide);
39444 menu.un("hide", onHide);
39445 menu.un("beforeshow", onBeforeShow);
39446 menu.un("show", onShow);
39447 var g = menu.group;
39448 if(g && menu.events["checkchange"]){
39449 groups[g].remove(menu);
39450 menu.un("checkchange", onCheck);
39455 registerCheckable : function(menuItem){
39456 var g = menuItem.group;
39461 groups[g].push(menuItem);
39462 menuItem.on("beforecheckchange", onBeforeCheck);
39467 unregisterCheckable : function(menuItem){
39468 var g = menuItem.group;
39470 groups[g].remove(menuItem);
39471 menuItem.un("beforecheckchange", onBeforeCheck);
39477 * Ext JS Library 1.1.1
39478 * Copyright(c) 2006-2007, Ext JS, LLC.
39480 * Originally Released Under LGPL - original licence link has changed is not relivant.
39483 * <script type="text/javascript">
39488 * @class Roo.menu.BaseItem
39489 * @extends Roo.Component
39491 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
39492 * management and base configuration options shared by all menu components.
39494 * Creates a new BaseItem
39495 * @param {Object} config Configuration options
39497 Roo.menu.BaseItem = function(config){
39498 Roo.menu.BaseItem.superclass.constructor.call(this, config);
39503 * Fires when this item is clicked
39504 * @param {Roo.menu.BaseItem} this
39505 * @param {Roo.EventObject} e
39510 * Fires when this item is activated
39511 * @param {Roo.menu.BaseItem} this
39515 * @event deactivate
39516 * Fires when this item is deactivated
39517 * @param {Roo.menu.BaseItem} this
39523 this.on("click", this.handler, this.scope, true);
39527 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
39529 * @cfg {Function} handler
39530 * A function that will handle the click event of this menu item (defaults to undefined)
39533 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
39535 canActivate : false,
39538 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
39543 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
39545 activeClass : "x-menu-item-active",
39547 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
39549 hideOnClick : true,
39551 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
39556 ctype: "Roo.menu.BaseItem",
39559 actionMode : "container",
39562 render : function(container, parentMenu){
39563 this.parentMenu = parentMenu;
39564 Roo.menu.BaseItem.superclass.render.call(this, container);
39565 this.container.menuItemId = this.id;
39569 onRender : function(container, position){
39570 this.el = Roo.get(this.el);
39571 container.dom.appendChild(this.el.dom);
39575 onClick : function(e){
39576 if(!this.disabled && this.fireEvent("click", this, e) !== false
39577 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
39578 this.handleClick(e);
39585 activate : function(){
39589 var li = this.container;
39590 li.addClass(this.activeClass);
39591 this.region = li.getRegion().adjust(2, 2, -2, -2);
39592 this.fireEvent("activate", this);
39597 deactivate : function(){
39598 this.container.removeClass(this.activeClass);
39599 this.fireEvent("deactivate", this);
39603 shouldDeactivate : function(e){
39604 return !this.region || !this.region.contains(e.getPoint());
39608 handleClick : function(e){
39609 if(this.hideOnClick){
39610 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
39615 expandMenu : function(autoActivate){
39620 hideMenu : function(){
39625 * Ext JS Library 1.1.1
39626 * Copyright(c) 2006-2007, Ext JS, LLC.
39628 * Originally Released Under LGPL - original licence link has changed is not relivant.
39631 * <script type="text/javascript">
39635 * @class Roo.menu.Adapter
39636 * @extends Roo.menu.BaseItem
39638 * 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.
39639 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
39641 * Creates a new Adapter
39642 * @param {Object} config Configuration options
39644 Roo.menu.Adapter = function(component, config){
39645 Roo.menu.Adapter.superclass.constructor.call(this, config);
39646 this.component = component;
39648 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
39650 canActivate : true,
39653 onRender : function(container, position){
39654 this.component.render(container);
39655 this.el = this.component.getEl();
39659 activate : function(){
39663 this.component.focus();
39664 this.fireEvent("activate", this);
39669 deactivate : function(){
39670 this.fireEvent("deactivate", this);
39674 disable : function(){
39675 this.component.disable();
39676 Roo.menu.Adapter.superclass.disable.call(this);
39680 enable : function(){
39681 this.component.enable();
39682 Roo.menu.Adapter.superclass.enable.call(this);
39686 * Ext JS Library 1.1.1
39687 * Copyright(c) 2006-2007, Ext JS, LLC.
39689 * Originally Released Under LGPL - original licence link has changed is not relivant.
39692 * <script type="text/javascript">
39696 * @class Roo.menu.TextItem
39697 * @extends Roo.menu.BaseItem
39698 * Adds a static text string to a menu, usually used as either a heading or group separator.
39699 * Note: old style constructor with text is still supported.
39702 * Creates a new TextItem
39703 * @param {Object} cfg Configuration
39705 Roo.menu.TextItem = function(cfg){
39706 if (typeof(cfg) == 'string') {
39709 Roo.apply(this,cfg);
39712 Roo.menu.TextItem.superclass.constructor.call(this);
39715 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
39717 * @cfg {String} text Text to show on item.
39722 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
39724 hideOnClick : false,
39726 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
39728 itemCls : "x-menu-text",
39731 onRender : function(){
39732 var s = document.createElement("span");
39733 s.className = this.itemCls;
39734 s.innerHTML = this.text;
39736 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
39740 * Ext JS Library 1.1.1
39741 * Copyright(c) 2006-2007, Ext JS, LLC.
39743 * Originally Released Under LGPL - original licence link has changed is not relivant.
39746 * <script type="text/javascript">
39750 * @class Roo.menu.Separator
39751 * @extends Roo.menu.BaseItem
39752 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
39753 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
39755 * @param {Object} config Configuration options
39757 Roo.menu.Separator = function(config){
39758 Roo.menu.Separator.superclass.constructor.call(this, config);
39761 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
39763 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
39765 itemCls : "x-menu-sep",
39767 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
39769 hideOnClick : false,
39772 onRender : function(li){
39773 var s = document.createElement("span");
39774 s.className = this.itemCls;
39775 s.innerHTML = " ";
39777 li.addClass("x-menu-sep-li");
39778 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
39782 * Ext JS Library 1.1.1
39783 * Copyright(c) 2006-2007, Ext JS, LLC.
39785 * Originally Released Under LGPL - original licence link has changed is not relivant.
39788 * <script type="text/javascript">
39791 * @class Roo.menu.Item
39792 * @extends Roo.menu.BaseItem
39793 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
39794 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
39795 * activation and click handling.
39797 * Creates a new Item
39798 * @param {Object} config Configuration options
39800 Roo.menu.Item = function(config){
39801 Roo.menu.Item.superclass.constructor.call(this, config);
39803 this.menu = Roo.menu.MenuMgr.get(this.menu);
39806 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
39808 * @cfg {Roo.menu.Menu} menu
39812 * @cfg {String} text
39813 * The text to show on the menu item.
39817 * @cfg {String} HTML to render in menu
39818 * The text to show on the menu item (HTML version).
39822 * @cfg {String} icon
39823 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
39827 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
39829 itemCls : "x-menu-item",
39831 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
39833 canActivate : true,
39835 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
39838 // doc'd in BaseItem
39842 ctype: "Roo.menu.Item",
39845 onRender : function(container, position){
39846 var el = document.createElement("a");
39847 el.hideFocus = true;
39848 el.unselectable = "on";
39849 el.href = this.href || "#";
39850 if(this.hrefTarget){
39851 el.target = this.hrefTarget;
39853 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
39855 var html = this.html.length ? this.html : String.format('{0}',this.text);
39857 el.innerHTML = String.format(
39858 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
39859 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
39861 Roo.menu.Item.superclass.onRender.call(this, container, position);
39865 * Sets the text to display in this menu item
39866 * @param {String} text The text to display
39867 * @param {Boolean} isHTML true to indicate text is pure html.
39869 setText : function(text, isHTML){
39877 var html = this.html.length ? this.html : String.format('{0}',this.text);
39879 this.el.update(String.format(
39880 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
39881 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
39882 this.parentMenu.autoWidth();
39887 handleClick : function(e){
39888 if(!this.href){ // if no link defined, stop the event automatically
39891 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
39895 activate : function(autoExpand){
39896 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
39906 shouldDeactivate : function(e){
39907 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
39908 if(this.menu && this.menu.isVisible()){
39909 return !this.menu.getEl().getRegion().contains(e.getPoint());
39917 deactivate : function(){
39918 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
39923 expandMenu : function(autoActivate){
39924 if(!this.disabled && this.menu){
39925 clearTimeout(this.hideTimer);
39926 delete this.hideTimer;
39927 if(!this.menu.isVisible() && !this.showTimer){
39928 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
39929 }else if (this.menu.isVisible() && autoActivate){
39930 this.menu.tryActivate(0, 1);
39936 deferExpand : function(autoActivate){
39937 delete this.showTimer;
39938 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
39940 this.menu.tryActivate(0, 1);
39945 hideMenu : function(){
39946 clearTimeout(this.showTimer);
39947 delete this.showTimer;
39948 if(!this.hideTimer && this.menu && this.menu.isVisible()){
39949 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
39954 deferHide : function(){
39955 delete this.hideTimer;
39960 * Ext JS Library 1.1.1
39961 * Copyright(c) 2006-2007, Ext JS, LLC.
39963 * Originally Released Under LGPL - original licence link has changed is not relivant.
39966 * <script type="text/javascript">
39970 * @class Roo.menu.CheckItem
39971 * @extends Roo.menu.Item
39972 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
39974 * Creates a new CheckItem
39975 * @param {Object} config Configuration options
39977 Roo.menu.CheckItem = function(config){
39978 Roo.menu.CheckItem.superclass.constructor.call(this, config);
39981 * @event beforecheckchange
39982 * Fires before the checked value is set, providing an opportunity to cancel if needed
39983 * @param {Roo.menu.CheckItem} this
39984 * @param {Boolean} checked The new checked value that will be set
39986 "beforecheckchange" : true,
39988 * @event checkchange
39989 * Fires after the checked value has been set
39990 * @param {Roo.menu.CheckItem} this
39991 * @param {Boolean} checked The checked value that was set
39993 "checkchange" : true
39995 if(this.checkHandler){
39996 this.on('checkchange', this.checkHandler, this.scope);
39999 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
40001 * @cfg {String} group
40002 * All check items with the same group name will automatically be grouped into a single-select
40003 * radio button group (defaults to '')
40006 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
40008 itemCls : "x-menu-item x-menu-check-item",
40010 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
40012 groupClass : "x-menu-group-item",
40015 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
40016 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
40017 * initialized with checked = true will be rendered as checked.
40022 ctype: "Roo.menu.CheckItem",
40025 onRender : function(c){
40026 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
40028 this.el.addClass(this.groupClass);
40030 Roo.menu.MenuMgr.registerCheckable(this);
40032 this.checked = false;
40033 this.setChecked(true, true);
40038 destroy : function(){
40040 Roo.menu.MenuMgr.unregisterCheckable(this);
40042 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
40046 * Set the checked state of this item
40047 * @param {Boolean} checked The new checked value
40048 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
40050 setChecked : function(state, suppressEvent){
40051 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
40052 if(this.container){
40053 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
40055 this.checked = state;
40056 if(suppressEvent !== true){
40057 this.fireEvent("checkchange", this, state);
40063 handleClick : function(e){
40064 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
40065 this.setChecked(!this.checked);
40067 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
40071 * Ext JS Library 1.1.1
40072 * Copyright(c) 2006-2007, Ext JS, LLC.
40074 * Originally Released Under LGPL - original licence link has changed is not relivant.
40077 * <script type="text/javascript">
40081 * @class Roo.menu.DateItem
40082 * @extends Roo.menu.Adapter
40083 * A menu item that wraps the {@link Roo.DatPicker} component.
40085 * Creates a new DateItem
40086 * @param {Object} config Configuration options
40088 Roo.menu.DateItem = function(config){
40089 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
40090 /** The Roo.DatePicker object @type Roo.DatePicker */
40091 this.picker = this.component;
40092 this.addEvents({select: true});
40094 this.picker.on("render", function(picker){
40095 picker.getEl().swallowEvent("click");
40096 picker.container.addClass("x-menu-date-item");
40099 this.picker.on("select", this.onSelect, this);
40102 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
40104 onSelect : function(picker, date){
40105 this.fireEvent("select", this, date, picker);
40106 Roo.menu.DateItem.superclass.handleClick.call(this);
40110 * Ext JS Library 1.1.1
40111 * Copyright(c) 2006-2007, Ext JS, LLC.
40113 * Originally Released Under LGPL - original licence link has changed is not relivant.
40116 * <script type="text/javascript">
40120 * @class Roo.menu.ColorItem
40121 * @extends Roo.menu.Adapter
40122 * A menu item that wraps the {@link Roo.ColorPalette} component.
40124 * Creates a new ColorItem
40125 * @param {Object} config Configuration options
40127 Roo.menu.ColorItem = function(config){
40128 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
40129 /** The Roo.ColorPalette object @type Roo.ColorPalette */
40130 this.palette = this.component;
40131 this.relayEvents(this.palette, ["select"]);
40132 if(this.selectHandler){
40133 this.on('select', this.selectHandler, this.scope);
40136 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
40138 * Ext JS Library 1.1.1
40139 * Copyright(c) 2006-2007, Ext JS, LLC.
40141 * Originally Released Under LGPL - original licence link has changed is not relivant.
40144 * <script type="text/javascript">
40149 * @class Roo.menu.DateMenu
40150 * @extends Roo.menu.Menu
40151 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
40153 * Creates a new DateMenu
40154 * @param {Object} config Configuration options
40156 Roo.menu.DateMenu = function(config){
40157 Roo.menu.DateMenu.superclass.constructor.call(this, config);
40159 var di = new Roo.menu.DateItem(config);
40162 * The {@link Roo.DatePicker} instance for this DateMenu
40165 this.picker = di.picker;
40168 * @param {DatePicker} picker
40169 * @param {Date} date
40171 this.relayEvents(di, ["select"]);
40172 this.on('beforeshow', function(){
40174 this.picker.hideMonthPicker(false);
40178 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
40182 * Ext JS Library 1.1.1
40183 * Copyright(c) 2006-2007, Ext JS, LLC.
40185 * Originally Released Under LGPL - original licence link has changed is not relivant.
40188 * <script type="text/javascript">
40193 * @class Roo.menu.ColorMenu
40194 * @extends Roo.menu.Menu
40195 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
40197 * Creates a new ColorMenu
40198 * @param {Object} config Configuration options
40200 Roo.menu.ColorMenu = function(config){
40201 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
40203 var ci = new Roo.menu.ColorItem(config);
40206 * The {@link Roo.ColorPalette} instance for this ColorMenu
40207 * @type ColorPalette
40209 this.palette = ci.palette;
40212 * @param {ColorPalette} palette
40213 * @param {String} color
40215 this.relayEvents(ci, ["select"]);
40217 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
40219 * Ext JS Library 1.1.1
40220 * Copyright(c) 2006-2007, Ext JS, LLC.
40222 * Originally Released Under LGPL - original licence link has changed is not relivant.
40225 * <script type="text/javascript">
40229 * @class Roo.form.TextItem
40230 * @extends Roo.BoxComponent
40231 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
40233 * Creates a new TextItem
40234 * @param {Object} config Configuration options
40236 Roo.form.TextItem = function(config){
40237 Roo.form.TextItem.superclass.constructor.call(this, config);
40240 Roo.extend(Roo.form.TextItem, Roo.BoxComponent, {
40243 * @cfg {String} tag the tag for this item (default div)
40247 * @cfg {String} html the content for this item
40251 getAutoCreate : function()
40264 onRender : function(ct, position)
40266 Roo.form.TextItem.superclass.onRender.call(this, ct, position);
40269 var cfg = this.getAutoCreate();
40271 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
40273 if (!cfg.name.length) {
40276 this.el = ct.createChild(cfg, position);
40281 * @param {String} html update the Contents of the element.
40283 setHTML : function(html)
40285 this.fieldEl.dom.innerHTML = html;
40290 * Ext JS Library 1.1.1
40291 * Copyright(c) 2006-2007, Ext JS, LLC.
40293 * Originally Released Under LGPL - original licence link has changed is not relivant.
40296 * <script type="text/javascript">
40300 * @class Roo.form.Field
40301 * @extends Roo.BoxComponent
40302 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
40304 * Creates a new Field
40305 * @param {Object} config Configuration options
40307 Roo.form.Field = function(config){
40308 Roo.form.Field.superclass.constructor.call(this, config);
40311 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
40313 * @cfg {String} fieldLabel Label to use when rendering a form.
40316 * @cfg {String} qtip Mouse over tip
40320 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
40322 invalidClass : "x-form-invalid",
40324 * @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")
40326 invalidText : "The value in this field is invalid",
40328 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
40330 focusClass : "x-form-focus",
40332 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
40333 automatic validation (defaults to "keyup").
40335 validationEvent : "keyup",
40337 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
40339 validateOnBlur : true,
40341 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
40343 validationDelay : 250,
40345 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40346 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
40348 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
40350 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
40352 fieldClass : "x-form-field",
40354 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
40357 ----------- ----------------------------------------------------------------------
40358 qtip Display a quick tip when the user hovers over the field
40359 title Display a default browser title attribute popup
40360 under Add a block div beneath the field containing the error text
40361 side Add an error icon to the right of the field with a popup on hover
40362 [element id] Add the error text directly to the innerHTML of the specified element
40365 msgTarget : 'qtip',
40367 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
40372 * @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.
40377 * @cfg {Boolean} disabled True to disable the field (defaults to false).
40382 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
40384 inputType : undefined,
40387 * @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).
40389 tabIndex : undefined,
40392 isFormField : true,
40397 * @property {Roo.Element} fieldEl
40398 * Element Containing the rendered Field (with label etc.)
40401 * @cfg {Mixed} value A value to initialize this field with.
40406 * @cfg {String} name The field's HTML name attribute.
40409 * @cfg {String} cls A CSS class to apply to the field's underlying element.
40412 loadedValue : false,
40416 initComponent : function(){
40417 Roo.form.Field.superclass.initComponent.call(this);
40421 * Fires when this field receives input focus.
40422 * @param {Roo.form.Field} this
40427 * Fires when this field loses input focus.
40428 * @param {Roo.form.Field} this
40432 * @event specialkey
40433 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
40434 * {@link Roo.EventObject#getKey} to determine which key was pressed.
40435 * @param {Roo.form.Field} this
40436 * @param {Roo.EventObject} e The event object
40441 * Fires just before the field blurs if the field value has changed.
40442 * @param {Roo.form.Field} this
40443 * @param {Mixed} newValue The new value
40444 * @param {Mixed} oldValue The original value
40449 * Fires after the field has been marked as invalid.
40450 * @param {Roo.form.Field} this
40451 * @param {String} msg The validation message
40456 * Fires after the field has been validated with no errors.
40457 * @param {Roo.form.Field} this
40462 * Fires after the key up
40463 * @param {Roo.form.Field} this
40464 * @param {Roo.EventObject} e The event Object
40471 * Returns the name attribute of the field if available
40472 * @return {String} name The field name
40474 getName: function(){
40475 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40479 onRender : function(ct, position){
40480 Roo.form.Field.superclass.onRender.call(this, ct, position);
40482 var cfg = this.getAutoCreate();
40484 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
40486 if (!cfg.name.length) {
40489 if(this.inputType){
40490 cfg.type = this.inputType;
40492 this.el = ct.createChild(cfg, position);
40494 var type = this.el.dom.type;
40496 if(type == 'password'){
40499 this.el.addClass('x-form-'+type);
40502 this.el.dom.readOnly = true;
40504 if(this.tabIndex !== undefined){
40505 this.el.dom.setAttribute('tabIndex', this.tabIndex);
40508 this.el.addClass([this.fieldClass, this.cls]);
40513 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
40514 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
40515 * @return {Roo.form.Field} this
40517 applyTo : function(target){
40518 this.allowDomMove = false;
40519 this.el = Roo.get(target);
40520 this.render(this.el.dom.parentNode);
40525 initValue : function(){
40526 if(this.value !== undefined){
40527 this.setValue(this.value);
40528 }else if(this.el.dom.value.length > 0){
40529 this.setValue(this.el.dom.value);
40534 * Returns true if this field has been changed since it was originally loaded and is not disabled.
40535 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
40537 isDirty : function() {
40538 if(this.disabled) {
40541 return String(this.getValue()) !== String(this.originalValue);
40545 * stores the current value in loadedValue
40547 resetHasChanged : function()
40549 this.loadedValue = String(this.getValue());
40552 * checks the current value against the 'loaded' value.
40553 * Note - will return false if 'resetHasChanged' has not been called first.
40555 hasChanged : function()
40557 if(this.disabled || this.readOnly) {
40560 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
40566 afterRender : function(){
40567 Roo.form.Field.superclass.afterRender.call(this);
40572 fireKey : function(e){
40573 //Roo.log('field ' + e.getKey());
40574 if(e.isNavKeyPress()){
40575 this.fireEvent("specialkey", this, e);
40580 * Resets the current field value to the originally loaded value and clears any validation messages
40582 reset : function(){
40583 this.setValue(this.resetValue);
40584 this.originalValue = this.getValue();
40585 this.clearInvalid();
40589 initEvents : function(){
40590 // safari killled keypress - so keydown is now used..
40591 this.el.on("keydown" , this.fireKey, this);
40592 this.el.on("focus", this.onFocus, this);
40593 this.el.on("blur", this.onBlur, this);
40594 this.el.relayEvent('keyup', this);
40596 // reference to original value for reset
40597 this.originalValue = this.getValue();
40598 this.resetValue = this.getValue();
40602 onFocus : function(){
40603 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40604 this.el.addClass(this.focusClass);
40606 if(!this.hasFocus){
40607 this.hasFocus = true;
40608 this.startValue = this.getValue();
40609 this.fireEvent("focus", this);
40613 beforeBlur : Roo.emptyFn,
40616 onBlur : function(){
40618 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40619 this.el.removeClass(this.focusClass);
40621 this.hasFocus = false;
40622 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40625 var v = this.getValue();
40626 if(String(v) !== String(this.startValue)){
40627 this.fireEvent('change', this, v, this.startValue);
40629 this.fireEvent("blur", this);
40633 * Returns whether or not the field value is currently valid
40634 * @param {Boolean} preventMark True to disable marking the field invalid
40635 * @return {Boolean} True if the value is valid, else false
40637 isValid : function(preventMark){
40641 var restore = this.preventMark;
40642 this.preventMark = preventMark === true;
40643 var v = this.validateValue(this.processValue(this.getRawValue()));
40644 this.preventMark = restore;
40649 * Validates the field value
40650 * @return {Boolean} True if the value is valid, else false
40652 validate : function(){
40653 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
40654 this.clearInvalid();
40660 processValue : function(value){
40665 // Subclasses should provide the validation implementation by overriding this
40666 validateValue : function(value){
40671 * Mark this field as invalid
40672 * @param {String} msg The validation message
40674 markInvalid : function(msg){
40675 if(!this.rendered || this.preventMark){ // not rendered
40679 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
40681 obj.el.addClass(this.invalidClass);
40682 msg = msg || this.invalidText;
40683 switch(this.msgTarget){
40685 obj.el.dom.qtip = msg;
40686 obj.el.dom.qclass = 'x-form-invalid-tip';
40687 if(Roo.QuickTips){ // fix for floating editors interacting with DND
40688 Roo.QuickTips.enable();
40692 this.el.dom.title = msg;
40696 var elp = this.el.findParent('.x-form-element', 5, true);
40697 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
40698 this.errorEl.setWidth(elp.getWidth(true)-20);
40700 this.errorEl.update(msg);
40701 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
40704 if(!this.errorIcon){
40705 var elp = this.el.findParent('.x-form-element', 5, true);
40706 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
40708 this.alignErrorIcon();
40709 this.errorIcon.dom.qtip = msg;
40710 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
40711 this.errorIcon.show();
40712 this.on('resize', this.alignErrorIcon, this);
40715 var t = Roo.getDom(this.msgTarget);
40717 t.style.display = this.msgDisplay;
40720 this.fireEvent('invalid', this, msg);
40724 alignErrorIcon : function(){
40725 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
40729 * Clear any invalid styles/messages for this field
40731 clearInvalid : function(){
40732 if(!this.rendered || this.preventMark){ // not rendered
40735 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
40737 obj.el.removeClass(this.invalidClass);
40738 switch(this.msgTarget){
40740 obj.el.dom.qtip = '';
40743 this.el.dom.title = '';
40747 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
40751 if(this.errorIcon){
40752 this.errorIcon.dom.qtip = '';
40753 this.errorIcon.hide();
40754 this.un('resize', this.alignErrorIcon, this);
40758 var t = Roo.getDom(this.msgTarget);
40760 t.style.display = 'none';
40763 this.fireEvent('valid', this);
40767 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
40768 * @return {Mixed} value The field value
40770 getRawValue : function(){
40771 var v = this.el.getValue();
40777 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
40778 * @return {Mixed} value The field value
40780 getValue : function(){
40781 var v = this.el.getValue();
40787 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
40788 * @param {Mixed} value The value to set
40790 setRawValue : function(v){
40791 return this.el.dom.value = (v === null || v === undefined ? '' : v);
40795 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
40796 * @param {Mixed} value The value to set
40798 setValue : function(v){
40801 this.el.dom.value = (v === null || v === undefined ? '' : v);
40806 adjustSize : function(w, h){
40807 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
40808 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
40812 adjustWidth : function(tag, w){
40813 tag = tag.toLowerCase();
40814 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
40815 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
40816 if(tag == 'input'){
40819 if(tag == 'textarea'){
40822 }else if(Roo.isOpera){
40823 if(tag == 'input'){
40826 if(tag == 'textarea'){
40836 // anything other than normal should be considered experimental
40837 Roo.form.Field.msgFx = {
40839 show: function(msgEl, f){
40840 msgEl.setDisplayed('block');
40843 hide : function(msgEl, f){
40844 msgEl.setDisplayed(false).update('');
40849 show: function(msgEl, f){
40850 msgEl.slideIn('t', {stopFx:true});
40853 hide : function(msgEl, f){
40854 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
40859 show: function(msgEl, f){
40860 msgEl.fixDisplay();
40861 msgEl.alignTo(f.el, 'tl-tr');
40862 msgEl.slideIn('l', {stopFx:true});
40865 hide : function(msgEl, f){
40866 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
40871 * Ext JS Library 1.1.1
40872 * Copyright(c) 2006-2007, Ext JS, LLC.
40874 * Originally Released Under LGPL - original licence link has changed is not relivant.
40877 * <script type="text/javascript">
40882 * @class Roo.form.TextField
40883 * @extends Roo.form.Field
40884 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
40885 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
40887 * Creates a new TextField
40888 * @param {Object} config Configuration options
40890 Roo.form.TextField = function(config){
40891 Roo.form.TextField.superclass.constructor.call(this, config);
40895 * Fires when the autosize function is triggered. The field may or may not have actually changed size
40896 * according to the default logic, but this event provides a hook for the developer to apply additional
40897 * logic at runtime to resize the field if needed.
40898 * @param {Roo.form.Field} this This text field
40899 * @param {Number} width The new field width
40905 Roo.extend(Roo.form.TextField, Roo.form.Field, {
40907 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
40911 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
40915 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
40919 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
40923 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
40927 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
40929 disableKeyFilter : false,
40931 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
40935 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
40939 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
40941 maxLength : Number.MAX_VALUE,
40943 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
40945 minLengthText : "The minimum length for this field is {0}",
40947 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
40949 maxLengthText : "The maximum length for this field is {0}",
40951 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
40953 selectOnFocus : false,
40955 * @cfg {Boolean} allowLeadingSpace True to prevent the stripping of leading white space
40957 allowLeadingSpace : false,
40959 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
40961 blankText : "This field is required",
40963 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
40964 * If available, this function will be called only after the basic validators all return true, and will be passed the
40965 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
40969 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
40970 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
40971 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
40975 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
40979 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
40985 initEvents : function()
40987 if (this.emptyText) {
40988 this.el.attr('placeholder', this.emptyText);
40991 Roo.form.TextField.superclass.initEvents.call(this);
40992 if(this.validationEvent == 'keyup'){
40993 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40994 this.el.on('keyup', this.filterValidation, this);
40996 else if(this.validationEvent !== false){
40997 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
41000 if(this.selectOnFocus){
41001 this.on("focus", this.preFocus, this);
41003 if (!this.allowLeadingSpace) {
41004 this.on('blur', this.cleanLeadingSpace, this);
41007 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
41008 this.el.on("keypress", this.filterKeys, this);
41011 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
41012 this.el.on("click", this.autoSize, this);
41014 if(this.el.is('input[type=password]') && Roo.isSafari){
41015 this.el.on('keydown', this.SafariOnKeyDown, this);
41019 processValue : function(value){
41020 if(this.stripCharsRe){
41021 var newValue = value.replace(this.stripCharsRe, '');
41022 if(newValue !== value){
41023 this.setRawValue(newValue);
41030 filterValidation : function(e){
41031 if(!e.isNavKeyPress()){
41032 this.validationTask.delay(this.validationDelay);
41037 onKeyUp : function(e){
41038 if(!e.isNavKeyPress()){
41042 // private - clean the leading white space
41043 cleanLeadingSpace : function(e)
41045 if ( this.inputType == 'file') {
41049 this.setValue((this.getValue() + '').replace(/^\s+/,''));
41052 * Resets the current field value to the originally-loaded value and clears any validation messages.
41055 reset : function(){
41056 Roo.form.TextField.superclass.reset.call(this);
41060 preFocus : function(){
41062 if(this.selectOnFocus){
41063 this.el.dom.select();
41069 filterKeys : function(e){
41070 var k = e.getKey();
41071 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
41074 var c = e.getCharCode(), cc = String.fromCharCode(c);
41075 if(Roo.isIE && (e.isSpecialKey() || !cc)){
41078 if(!this.maskRe.test(cc)){
41083 setValue : function(v){
41085 Roo.form.TextField.superclass.setValue.apply(this, arguments);
41091 * Validates a value according to the field's validation rules and marks the field as invalid
41092 * if the validation fails
41093 * @param {Mixed} value The value to validate
41094 * @return {Boolean} True if the value is valid, else false
41096 validateValue : function(value){
41097 if(value.length < 1) { // if it's blank
41098 if(this.allowBlank){
41099 this.clearInvalid();
41102 this.markInvalid(this.blankText);
41106 if(value.length < this.minLength){
41107 this.markInvalid(String.format(this.minLengthText, this.minLength));
41110 if(value.length > this.maxLength){
41111 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
41115 var vt = Roo.form.VTypes;
41116 if(!vt[this.vtype](value, this)){
41117 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
41121 if(typeof this.validator == "function"){
41122 var msg = this.validator(value);
41124 this.markInvalid(msg);
41128 if(this.regex && !this.regex.test(value)){
41129 this.markInvalid(this.regexText);
41136 * Selects text in this field
41137 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
41138 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
41140 selectText : function(start, end){
41141 var v = this.getRawValue();
41143 start = start === undefined ? 0 : start;
41144 end = end === undefined ? v.length : end;
41145 var d = this.el.dom;
41146 if(d.setSelectionRange){
41147 d.setSelectionRange(start, end);
41148 }else if(d.createTextRange){
41149 var range = d.createTextRange();
41150 range.moveStart("character", start);
41151 range.moveEnd("character", v.length-end);
41158 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
41159 * This only takes effect if grow = true, and fires the autosize event.
41161 autoSize : function(){
41162 if(!this.grow || !this.rendered){
41166 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
41169 var v = el.dom.value;
41170 var d = document.createElement('div');
41171 d.appendChild(document.createTextNode(v));
41175 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
41176 this.el.setWidth(w);
41177 this.fireEvent("autosize", this, w);
41181 SafariOnKeyDown : function(event)
41183 // this is a workaround for a password hang bug on chrome/ webkit.
41185 var isSelectAll = false;
41187 if(this.el.dom.selectionEnd > 0){
41188 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
41190 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
41191 event.preventDefault();
41196 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
41198 event.preventDefault();
41199 // this is very hacky as keydown always get's upper case.
41201 var cc = String.fromCharCode(event.getCharCode());
41204 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
41212 * Ext JS Library 1.1.1
41213 * Copyright(c) 2006-2007, Ext JS, LLC.
41215 * Originally Released Under LGPL - original licence link has changed is not relivant.
41218 * <script type="text/javascript">
41222 * @class Roo.form.Hidden
41223 * @extends Roo.form.TextField
41224 * Simple Hidden element used on forms
41226 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
41229 * Creates a new Hidden form element.
41230 * @param {Object} config Configuration options
41235 // easy hidden field...
41236 Roo.form.Hidden = function(config){
41237 Roo.form.Hidden.superclass.constructor.call(this, config);
41240 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
41242 inputType: 'hidden',
41245 labelSeparator: '',
41247 itemCls : 'x-form-item-display-none'
41255 * Ext JS Library 1.1.1
41256 * Copyright(c) 2006-2007, Ext JS, LLC.
41258 * Originally Released Under LGPL - original licence link has changed is not relivant.
41261 * <script type="text/javascript">
41265 * @class Roo.form.TriggerField
41266 * @extends Roo.form.TextField
41267 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
41268 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
41269 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
41270 * for which you can provide a custom implementation. For example:
41272 var trigger = new Roo.form.TriggerField();
41273 trigger.onTriggerClick = myTriggerFn;
41274 trigger.applyTo('my-field');
41277 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
41278 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
41279 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
41280 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
41282 * Create a new TriggerField.
41283 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
41284 * to the base TextField)
41286 Roo.form.TriggerField = function(config){
41287 this.mimicing = false;
41288 Roo.form.TriggerField.superclass.constructor.call(this, config);
41291 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
41293 * @cfg {String} triggerClass A CSS class to apply to the trigger
41296 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
41297 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
41299 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
41301 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
41305 /** @cfg {Boolean} grow @hide */
41306 /** @cfg {Number} growMin @hide */
41307 /** @cfg {Number} growMax @hide */
41313 autoSize: Roo.emptyFn,
41317 deferHeight : true,
41320 actionMode : 'wrap',
41322 onResize : function(w, h){
41323 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
41324 if(typeof w == 'number'){
41325 var x = w - this.trigger.getWidth();
41326 this.el.setWidth(this.adjustWidth('input', x));
41327 this.trigger.setStyle('left', x+'px');
41332 adjustSize : Roo.BoxComponent.prototype.adjustSize,
41335 getResizeEl : function(){
41340 getPositionEl : function(){
41345 alignErrorIcon : function(){
41346 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
41350 onRender : function(ct, position){
41351 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
41352 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
41353 this.trigger = this.wrap.createChild(this.triggerConfig ||
41354 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
41355 if(this.hideTrigger){
41356 this.trigger.setDisplayed(false);
41358 this.initTrigger();
41360 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
41365 initTrigger : function(){
41366 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
41367 this.trigger.addClassOnOver('x-form-trigger-over');
41368 this.trigger.addClassOnClick('x-form-trigger-click');
41372 onDestroy : function(){
41374 this.trigger.removeAllListeners();
41375 this.trigger.remove();
41378 this.wrap.remove();
41380 Roo.form.TriggerField.superclass.onDestroy.call(this);
41384 onFocus : function(){
41385 Roo.form.TriggerField.superclass.onFocus.call(this);
41386 if(!this.mimicing){
41387 this.wrap.addClass('x-trigger-wrap-focus');
41388 this.mimicing = true;
41389 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
41390 if(this.monitorTab){
41391 this.el.on("keydown", this.checkTab, this);
41397 checkTab : function(e){
41398 if(e.getKey() == e.TAB){
41399 this.triggerBlur();
41404 onBlur : function(){
41409 mimicBlur : function(e, t){
41410 if(!this.wrap.contains(t) && this.validateBlur()){
41411 this.triggerBlur();
41416 triggerBlur : function(){
41417 this.mimicing = false;
41418 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
41419 if(this.monitorTab){
41420 this.el.un("keydown", this.checkTab, this);
41422 this.wrap.removeClass('x-trigger-wrap-focus');
41423 Roo.form.TriggerField.superclass.onBlur.call(this);
41427 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
41428 validateBlur : function(e, t){
41433 onDisable : function(){
41434 Roo.form.TriggerField.superclass.onDisable.call(this);
41436 this.wrap.addClass('x-item-disabled');
41441 onEnable : function(){
41442 Roo.form.TriggerField.superclass.onEnable.call(this);
41444 this.wrap.removeClass('x-item-disabled');
41449 onShow : function(){
41450 var ae = this.getActionEl();
41453 ae.dom.style.display = '';
41454 ae.dom.style.visibility = 'visible';
41460 onHide : function(){
41461 var ae = this.getActionEl();
41462 ae.dom.style.display = 'none';
41466 * The function that should handle the trigger's click event. This method does nothing by default until overridden
41467 * by an implementing function.
41469 * @param {EventObject} e
41471 onTriggerClick : Roo.emptyFn
41474 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
41475 // to be extended by an implementing class. For an example of implementing this class, see the custom
41476 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
41477 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
41478 initComponent : function(){
41479 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
41481 this.triggerConfig = {
41482 tag:'span', cls:'x-form-twin-triggers', cn:[
41483 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
41484 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
41488 getTrigger : function(index){
41489 return this.triggers[index];
41492 initTrigger : function(){
41493 var ts = this.trigger.select('.x-form-trigger', true);
41494 this.wrap.setStyle('overflow', 'hidden');
41495 var triggerField = this;
41496 ts.each(function(t, all, index){
41497 t.hide = function(){
41498 var w = triggerField.wrap.getWidth();
41499 this.dom.style.display = 'none';
41500 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
41502 t.show = function(){
41503 var w = triggerField.wrap.getWidth();
41504 this.dom.style.display = '';
41505 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
41507 var triggerIndex = 'Trigger'+(index+1);
41509 if(this['hide'+triggerIndex]){
41510 t.dom.style.display = 'none';
41512 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
41513 t.addClassOnOver('x-form-trigger-over');
41514 t.addClassOnClick('x-form-trigger-click');
41516 this.triggers = ts.elements;
41519 onTrigger1Click : Roo.emptyFn,
41520 onTrigger2Click : Roo.emptyFn
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">
41533 * @class Roo.form.TextArea
41534 * @extends Roo.form.TextField
41535 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
41536 * support for auto-sizing.
41538 * Creates a new TextArea
41539 * @param {Object} config Configuration options
41541 Roo.form.TextArea = function(config){
41542 Roo.form.TextArea.superclass.constructor.call(this, config);
41543 // these are provided exchanges for backwards compat
41544 // minHeight/maxHeight were replaced by growMin/growMax to be
41545 // compatible with TextField growing config values
41546 if(this.minHeight !== undefined){
41547 this.growMin = this.minHeight;
41549 if(this.maxHeight !== undefined){
41550 this.growMax = this.maxHeight;
41554 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
41556 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
41560 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
41564 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
41565 * in the field (equivalent to setting overflow: hidden, defaults to false)
41567 preventScrollbars: false,
41569 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
41570 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
41574 onRender : function(ct, position){
41576 this.defaultAutoCreate = {
41578 style:"width:300px;height:60px;",
41579 autocomplete: "new-password"
41582 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
41584 this.textSizeEl = Roo.DomHelper.append(document.body, {
41585 tag: "pre", cls: "x-form-grow-sizer"
41587 if(this.preventScrollbars){
41588 this.el.setStyle("overflow", "hidden");
41590 this.el.setHeight(this.growMin);
41594 onDestroy : function(){
41595 if(this.textSizeEl){
41596 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
41598 Roo.form.TextArea.superclass.onDestroy.call(this);
41602 onKeyUp : function(e){
41603 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
41609 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
41610 * This only takes effect if grow = true, and fires the autosize event if the height changes.
41612 autoSize : function(){
41613 if(!this.grow || !this.textSizeEl){
41617 var v = el.dom.value;
41618 var ts = this.textSizeEl;
41621 ts.appendChild(document.createTextNode(v));
41624 Roo.fly(ts).setWidth(this.el.getWidth());
41626 v = "  ";
41629 v = v.replace(/\n/g, '<p> </p>');
41631 v += " \n ";
41634 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
41635 if(h != this.lastHeight){
41636 this.lastHeight = h;
41637 this.el.setHeight(h);
41638 this.fireEvent("autosize", this, h);
41643 * Ext JS Library 1.1.1
41644 * Copyright(c) 2006-2007, Ext JS, LLC.
41646 * Originally Released Under LGPL - original licence link has changed is not relivant.
41649 * <script type="text/javascript">
41654 * @class Roo.form.NumberField
41655 * @extends Roo.form.TextField
41656 * Numeric text field that provides automatic keystroke filtering and numeric validation.
41658 * Creates a new NumberField
41659 * @param {Object} config Configuration options
41661 Roo.form.NumberField = function(config){
41662 Roo.form.NumberField.superclass.constructor.call(this, config);
41665 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
41667 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
41669 fieldClass: "x-form-field x-form-num-field",
41671 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
41673 allowDecimals : true,
41675 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
41677 decimalSeparator : ".",
41679 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
41681 decimalPrecision : 2,
41683 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
41685 allowNegative : true,
41687 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
41689 minValue : Number.NEGATIVE_INFINITY,
41691 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
41693 maxValue : Number.MAX_VALUE,
41695 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
41697 minText : "The minimum value for this field is {0}",
41699 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
41701 maxText : "The maximum value for this field is {0}",
41703 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
41704 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
41706 nanText : "{0} is not a valid number",
41709 initEvents : function(){
41710 Roo.form.NumberField.superclass.initEvents.call(this);
41711 var allowed = "0123456789";
41712 if(this.allowDecimals){
41713 allowed += this.decimalSeparator;
41715 if(this.allowNegative){
41718 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41719 var keyPress = function(e){
41720 var k = e.getKey();
41721 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41724 var c = e.getCharCode();
41725 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41729 this.el.on("keypress", keyPress, this);
41733 validateValue : function(value){
41734 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
41737 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
41740 var num = this.parseValue(value);
41742 this.markInvalid(String.format(this.nanText, value));
41745 if(num < this.minValue){
41746 this.markInvalid(String.format(this.minText, this.minValue));
41749 if(num > this.maxValue){
41750 this.markInvalid(String.format(this.maxText, this.maxValue));
41756 getValue : function(){
41757 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
41761 parseValue : function(value){
41762 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41763 return isNaN(value) ? '' : value;
41767 fixPrecision : function(value){
41768 var nan = isNaN(value);
41769 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41770 return nan ? '' : value;
41772 return parseFloat(value).toFixed(this.decimalPrecision);
41775 setValue : function(v){
41776 v = this.fixPrecision(v);
41777 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
41781 decimalPrecisionFcn : function(v){
41782 return Math.floor(v);
41785 beforeBlur : function(){
41786 var v = this.parseValue(this.getRawValue());
41793 * Ext JS Library 1.1.1
41794 * Copyright(c) 2006-2007, Ext JS, LLC.
41796 * Originally Released Under LGPL - original licence link has changed is not relivant.
41799 * <script type="text/javascript">
41803 * @class Roo.form.DateField
41804 * @extends Roo.form.TriggerField
41805 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
41807 * Create a new DateField
41808 * @param {Object} config
41810 Roo.form.DateField = function(config)
41812 Roo.form.DateField.superclass.constructor.call(this, config);
41818 * Fires when a date is selected
41819 * @param {Roo.form.DateField} combo This combo box
41820 * @param {Date} date The date selected
41827 if(typeof this.minValue == "string") {
41828 this.minValue = this.parseDate(this.minValue);
41830 if(typeof this.maxValue == "string") {
41831 this.maxValue = this.parseDate(this.maxValue);
41833 this.ddMatch = null;
41834 if(this.disabledDates){
41835 var dd = this.disabledDates;
41837 for(var i = 0; i < dd.length; i++){
41839 if(i != dd.length-1) {
41843 this.ddMatch = new RegExp(re + ")");
41847 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
41849 * @cfg {String} format
41850 * The default date format string which can be overriden for localization support. The format must be
41851 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
41855 * @cfg {String} altFormats
41856 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
41857 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
41859 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
41861 * @cfg {Array} disabledDays
41862 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
41864 disabledDays : null,
41866 * @cfg {String} disabledDaysText
41867 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
41869 disabledDaysText : "Disabled",
41871 * @cfg {Array} disabledDates
41872 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
41873 * expression so they are very powerful. Some examples:
41875 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
41876 * <li>["03/08", "09/16"] would disable those days for every year</li>
41877 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
41878 * <li>["03/../2006"] would disable every day in March 2006</li>
41879 * <li>["^03"] would disable every day in every March</li>
41881 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
41882 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
41884 disabledDates : null,
41886 * @cfg {String} disabledDatesText
41887 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
41889 disabledDatesText : "Disabled",
41893 * @cfg {Date/String} zeroValue
41894 * if the date is less that this number, then the field is rendered as empty
41897 zeroValue : '1800-01-01',
41901 * @cfg {Date/String} minValue
41902 * The minimum allowed date. Can be either a Javascript date object or a string date in a
41903 * valid format (defaults to null).
41907 * @cfg {Date/String} maxValue
41908 * The maximum allowed date. Can be either a Javascript date object or a string date in a
41909 * valid format (defaults to null).
41913 * @cfg {String} minText
41914 * The error text to display when the date in the cell is before minValue (defaults to
41915 * 'The date in this field must be after {minValue}').
41917 minText : "The date in this field must be equal to or after {0}",
41919 * @cfg {String} maxText
41920 * The error text to display when the date in the cell is after maxValue (defaults to
41921 * 'The date in this field must be before {maxValue}').
41923 maxText : "The date in this field must be equal to or before {0}",
41925 * @cfg {String} invalidText
41926 * The error text to display when the date in the field is invalid (defaults to
41927 * '{value} is not a valid date - it must be in the format {format}').
41929 invalidText : "{0} is not a valid date - it must be in the format {1}",
41931 * @cfg {String} triggerClass
41932 * An additional CSS class used to style the trigger button. The trigger will always get the
41933 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
41934 * which displays a calendar icon).
41936 triggerClass : 'x-form-date-trigger',
41940 * @cfg {Boolean} useIso
41941 * if enabled, then the date field will use a hidden field to store the
41942 * real value as iso formated date. default (false)
41946 * @cfg {String/Object} autoCreate
41947 * A DomHelper element spec, or true for a default element spec (defaults to
41948 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
41951 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
41954 hiddenField: false,
41956 onRender : function(ct, position)
41958 Roo.form.DateField.superclass.onRender.call(this, ct, position);
41960 //this.el.dom.removeAttribute('name');
41961 Roo.log("Changing name?");
41962 this.el.dom.setAttribute('name', this.name + '____hidden___' );
41963 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
41965 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
41966 // prevent input submission
41967 this.hiddenName = this.name;
41974 validateValue : function(value)
41976 value = this.formatDate(value);
41977 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
41978 Roo.log('super failed');
41981 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
41984 var svalue = value;
41985 value = this.parseDate(value);
41987 Roo.log('parse date failed' + svalue);
41988 this.markInvalid(String.format(this.invalidText, svalue, this.format));
41991 var time = value.getTime();
41992 if(this.minValue && time < this.minValue.getTime()){
41993 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
41996 if(this.maxValue && time > this.maxValue.getTime()){
41997 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
42000 if(this.disabledDays){
42001 var day = value.getDay();
42002 for(var i = 0; i < this.disabledDays.length; i++) {
42003 if(day === this.disabledDays[i]){
42004 this.markInvalid(this.disabledDaysText);
42009 var fvalue = this.formatDate(value);
42010 if(this.ddMatch && this.ddMatch.test(fvalue)){
42011 this.markInvalid(String.format(this.disabledDatesText, fvalue));
42018 // Provides logic to override the default TriggerField.validateBlur which just returns true
42019 validateBlur : function(){
42020 return !this.menu || !this.menu.isVisible();
42023 getName: function()
42025 // returns hidden if it's set..
42026 if (!this.rendered) {return ''};
42027 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
42032 * Returns the current date value of the date field.
42033 * @return {Date} The date value
42035 getValue : function(){
42037 return this.hiddenField ?
42038 this.hiddenField.value :
42039 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
42043 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
42044 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
42045 * (the default format used is "m/d/y").
42048 //All of these calls set the same date value (May 4, 2006)
42050 //Pass a date object:
42051 var dt = new Date('5/4/06');
42052 dateField.setValue(dt);
42054 //Pass a date string (default format):
42055 dateField.setValue('5/4/06');
42057 //Pass a date string (custom format):
42058 dateField.format = 'Y-m-d';
42059 dateField.setValue('2006-5-4');
42061 * @param {String/Date} date The date or valid date string
42063 setValue : function(date){
42064 if (this.hiddenField) {
42065 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
42067 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
42068 // make sure the value field is always stored as a date..
42069 this.value = this.parseDate(date);
42075 parseDate : function(value){
42077 if (value instanceof Date) {
42078 if (value < Date.parseDate(this.zeroValue, 'Y-m-d') ) {
42085 if(!value || value instanceof Date){
42088 var v = Date.parseDate(value, this.format);
42089 if (!v && this.useIso) {
42090 v = Date.parseDate(value, 'Y-m-d');
42092 if(!v && this.altFormats){
42093 if(!this.altFormatsArray){
42094 this.altFormatsArray = this.altFormats.split("|");
42096 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
42097 v = Date.parseDate(value, this.altFormatsArray[i]);
42100 if (v < Date.parseDate(this.zeroValue, 'Y-m-d') ) {
42107 formatDate : function(date, fmt){
42108 return (!date || !(date instanceof Date)) ?
42109 date : date.dateFormat(fmt || this.format);
42114 select: function(m, d){
42117 this.fireEvent('select', this, d);
42119 show : function(){ // retain focus styling
42123 this.focus.defer(10, this);
42124 var ml = this.menuListeners;
42125 this.menu.un("select", ml.select, this);
42126 this.menu.un("show", ml.show, this);
42127 this.menu.un("hide", ml.hide, this);
42132 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
42133 onTriggerClick : function(){
42137 if(this.menu == null){
42138 this.menu = new Roo.menu.DateMenu();
42140 Roo.apply(this.menu.picker, {
42141 showClear: this.allowBlank,
42142 minDate : this.minValue,
42143 maxDate : this.maxValue,
42144 disabledDatesRE : this.ddMatch,
42145 disabledDatesText : this.disabledDatesText,
42146 disabledDays : this.disabledDays,
42147 disabledDaysText : this.disabledDaysText,
42148 format : this.useIso ? 'Y-m-d' : this.format,
42149 minText : String.format(this.minText, this.formatDate(this.minValue)),
42150 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
42152 this.menu.on(Roo.apply({}, this.menuListeners, {
42155 this.menu.picker.setValue(this.getValue() || new Date());
42156 this.menu.show(this.el, "tl-bl?");
42159 beforeBlur : function(){
42160 var v = this.parseDate(this.getRawValue());
42170 isDirty : function() {
42171 if(this.disabled) {
42175 if(typeof(this.startValue) === 'undefined'){
42179 return String(this.getValue()) !== String(this.startValue);
42183 cleanLeadingSpace : function(e)
42190 * Ext JS Library 1.1.1
42191 * Copyright(c) 2006-2007, Ext JS, LLC.
42193 * Originally Released Under LGPL - original licence link has changed is not relivant.
42196 * <script type="text/javascript">
42200 * @class Roo.form.MonthField
42201 * @extends Roo.form.TriggerField
42202 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
42204 * Create a new MonthField
42205 * @param {Object} config
42207 Roo.form.MonthField = function(config){
42209 Roo.form.MonthField.superclass.constructor.call(this, config);
42215 * Fires when a date is selected
42216 * @param {Roo.form.MonthFieeld} combo This combo box
42217 * @param {Date} date The date selected
42224 if(typeof this.minValue == "string") {
42225 this.minValue = this.parseDate(this.minValue);
42227 if(typeof this.maxValue == "string") {
42228 this.maxValue = this.parseDate(this.maxValue);
42230 this.ddMatch = null;
42231 if(this.disabledDates){
42232 var dd = this.disabledDates;
42234 for(var i = 0; i < dd.length; i++){
42236 if(i != dd.length-1) {
42240 this.ddMatch = new RegExp(re + ")");
42244 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
42246 * @cfg {String} format
42247 * The default date format string which can be overriden for localization support. The format must be
42248 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
42252 * @cfg {String} altFormats
42253 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
42254 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
42256 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
42258 * @cfg {Array} disabledDays
42259 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
42261 disabledDays : [0,1,2,3,4,5,6],
42263 * @cfg {String} disabledDaysText
42264 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
42266 disabledDaysText : "Disabled",
42268 * @cfg {Array} disabledDates
42269 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
42270 * expression so they are very powerful. Some examples:
42272 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
42273 * <li>["03/08", "09/16"] would disable those days for every year</li>
42274 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
42275 * <li>["03/../2006"] would disable every day in March 2006</li>
42276 * <li>["^03"] would disable every day in every March</li>
42278 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
42279 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
42281 disabledDates : null,
42283 * @cfg {String} disabledDatesText
42284 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
42286 disabledDatesText : "Disabled",
42288 * @cfg {Date/String} minValue
42289 * The minimum allowed date. Can be either a Javascript date object or a string date in a
42290 * valid format (defaults to null).
42294 * @cfg {Date/String} maxValue
42295 * The maximum allowed date. Can be either a Javascript date object or a string date in a
42296 * valid format (defaults to null).
42300 * @cfg {String} minText
42301 * The error text to display when the date in the cell is before minValue (defaults to
42302 * 'The date in this field must be after {minValue}').
42304 minText : "The date in this field must be equal to or after {0}",
42306 * @cfg {String} maxTextf
42307 * The error text to display when the date in the cell is after maxValue (defaults to
42308 * 'The date in this field must be before {maxValue}').
42310 maxText : "The date in this field must be equal to or before {0}",
42312 * @cfg {String} invalidText
42313 * The error text to display when the date in the field is invalid (defaults to
42314 * '{value} is not a valid date - it must be in the format {format}').
42316 invalidText : "{0} is not a valid date - it must be in the format {1}",
42318 * @cfg {String} triggerClass
42319 * An additional CSS class used to style the trigger button. The trigger will always get the
42320 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
42321 * which displays a calendar icon).
42323 triggerClass : 'x-form-date-trigger',
42327 * @cfg {Boolean} useIso
42328 * if enabled, then the date field will use a hidden field to store the
42329 * real value as iso formated date. default (true)
42333 * @cfg {String/Object} autoCreate
42334 * A DomHelper element spec, or true for a default element spec (defaults to
42335 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
42338 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
42341 hiddenField: false,
42343 hideMonthPicker : false,
42345 onRender : function(ct, position)
42347 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
42349 this.el.dom.removeAttribute('name');
42350 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
42352 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
42353 // prevent input submission
42354 this.hiddenName = this.name;
42361 validateValue : function(value)
42363 value = this.formatDate(value);
42364 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
42367 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
42370 var svalue = value;
42371 value = this.parseDate(value);
42373 this.markInvalid(String.format(this.invalidText, svalue, this.format));
42376 var time = value.getTime();
42377 if(this.minValue && time < this.minValue.getTime()){
42378 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
42381 if(this.maxValue && time > this.maxValue.getTime()){
42382 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
42385 /*if(this.disabledDays){
42386 var day = value.getDay();
42387 for(var i = 0; i < this.disabledDays.length; i++) {
42388 if(day === this.disabledDays[i]){
42389 this.markInvalid(this.disabledDaysText);
42395 var fvalue = this.formatDate(value);
42396 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
42397 this.markInvalid(String.format(this.disabledDatesText, fvalue));
42405 // Provides logic to override the default TriggerField.validateBlur which just returns true
42406 validateBlur : function(){
42407 return !this.menu || !this.menu.isVisible();
42411 * Returns the current date value of the date field.
42412 * @return {Date} The date value
42414 getValue : function(){
42418 return this.hiddenField ?
42419 this.hiddenField.value :
42420 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
42424 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
42425 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
42426 * (the default format used is "m/d/y").
42429 //All of these calls set the same date value (May 4, 2006)
42431 //Pass a date object:
42432 var dt = new Date('5/4/06');
42433 monthField.setValue(dt);
42435 //Pass a date string (default format):
42436 monthField.setValue('5/4/06');
42438 //Pass a date string (custom format):
42439 monthField.format = 'Y-m-d';
42440 monthField.setValue('2006-5-4');
42442 * @param {String/Date} date The date or valid date string
42444 setValue : function(date){
42445 Roo.log('month setValue' + date);
42446 // can only be first of month..
42448 var val = this.parseDate(date);
42450 if (this.hiddenField) {
42451 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
42453 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
42454 this.value = this.parseDate(date);
42458 parseDate : function(value){
42459 if(!value || value instanceof Date){
42460 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
42463 var v = Date.parseDate(value, this.format);
42464 if (!v && this.useIso) {
42465 v = Date.parseDate(value, 'Y-m-d');
42469 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
42473 if(!v && this.altFormats){
42474 if(!this.altFormatsArray){
42475 this.altFormatsArray = this.altFormats.split("|");
42477 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
42478 v = Date.parseDate(value, this.altFormatsArray[i]);
42485 formatDate : function(date, fmt){
42486 return (!date || !(date instanceof Date)) ?
42487 date : date.dateFormat(fmt || this.format);
42492 select: function(m, d){
42494 this.fireEvent('select', this, d);
42496 show : function(){ // retain focus styling
42500 this.focus.defer(10, this);
42501 var ml = this.menuListeners;
42502 this.menu.un("select", ml.select, this);
42503 this.menu.un("show", ml.show, this);
42504 this.menu.un("hide", ml.hide, this);
42508 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
42509 onTriggerClick : function(){
42513 if(this.menu == null){
42514 this.menu = new Roo.menu.DateMenu();
42518 Roo.apply(this.menu.picker, {
42520 showClear: this.allowBlank,
42521 minDate : this.minValue,
42522 maxDate : this.maxValue,
42523 disabledDatesRE : this.ddMatch,
42524 disabledDatesText : this.disabledDatesText,
42526 format : this.useIso ? 'Y-m-d' : this.format,
42527 minText : String.format(this.minText, this.formatDate(this.minValue)),
42528 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
42531 this.menu.on(Roo.apply({}, this.menuListeners, {
42539 // hide month picker get's called when we called by 'before hide';
42541 var ignorehide = true;
42542 p.hideMonthPicker = function(disableAnim){
42546 if(this.monthPicker){
42547 Roo.log("hideMonthPicker called");
42548 if(disableAnim === true){
42549 this.monthPicker.hide();
42551 this.monthPicker.slideOut('t', {duration:.2});
42552 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
42553 p.fireEvent("select", this, this.value);
42559 Roo.log('picker set value');
42560 Roo.log(this.getValue());
42561 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
42562 m.show(this.el, 'tl-bl?');
42563 ignorehide = false;
42564 // this will trigger hideMonthPicker..
42567 // hidden the day picker
42568 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
42574 p.showMonthPicker.defer(100, p);
42580 beforeBlur : function(){
42581 var v = this.parseDate(this.getRawValue());
42587 /** @cfg {Boolean} grow @hide */
42588 /** @cfg {Number} growMin @hide */
42589 /** @cfg {Number} growMax @hide */
42596 * Ext JS Library 1.1.1
42597 * Copyright(c) 2006-2007, Ext JS, LLC.
42599 * Originally Released Under LGPL - original licence link has changed is not relivant.
42602 * <script type="text/javascript">
42607 * @class Roo.form.ComboBox
42608 * @extends Roo.form.TriggerField
42609 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
42611 * Create a new ComboBox.
42612 * @param {Object} config Configuration options
42614 Roo.form.ComboBox = function(config){
42615 Roo.form.ComboBox.superclass.constructor.call(this, config);
42619 * Fires when the dropdown list is expanded
42620 * @param {Roo.form.ComboBox} combo This combo box
42625 * Fires when the dropdown list is collapsed
42626 * @param {Roo.form.ComboBox} combo This combo box
42630 * @event beforeselect
42631 * Fires before a list item is selected. Return false to cancel the selection.
42632 * @param {Roo.form.ComboBox} combo This combo box
42633 * @param {Roo.data.Record} record The data record returned from the underlying store
42634 * @param {Number} index The index of the selected item in the dropdown list
42636 'beforeselect' : true,
42639 * Fires when a list item is selected
42640 * @param {Roo.form.ComboBox} combo This combo box
42641 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
42642 * @param {Number} index The index of the selected item in the dropdown list
42646 * @event beforequery
42647 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
42648 * The event object passed has these properties:
42649 * @param {Roo.form.ComboBox} combo This combo box
42650 * @param {String} query The query
42651 * @param {Boolean} forceAll true to force "all" query
42652 * @param {Boolean} cancel true to cancel the query
42653 * @param {Object} e The query event object
42655 'beforequery': true,
42658 * Fires when the 'add' icon is pressed (add a listener to enable add button)
42659 * @param {Roo.form.ComboBox} combo This combo box
42664 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
42665 * @param {Roo.form.ComboBox} combo This combo box
42666 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
42672 if(this.transform){
42673 this.allowDomMove = false;
42674 var s = Roo.getDom(this.transform);
42675 if(!this.hiddenName){
42676 this.hiddenName = s.name;
42679 this.mode = 'local';
42680 var d = [], opts = s.options;
42681 for(var i = 0, len = opts.length;i < len; i++){
42683 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
42685 this.value = value;
42687 d.push([value, o.text]);
42689 this.store = new Roo.data.SimpleStore({
42691 fields: ['value', 'text'],
42694 this.valueField = 'value';
42695 this.displayField = 'text';
42697 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
42698 if(!this.lazyRender){
42699 this.target = true;
42700 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
42701 s.parentNode.removeChild(s); // remove it
42702 this.render(this.el.parentNode);
42704 s.parentNode.removeChild(s); // remove it
42709 this.store = Roo.factory(this.store, Roo.data);
42712 this.selectedIndex = -1;
42713 if(this.mode == 'local'){
42714 if(config.queryDelay === undefined){
42715 this.queryDelay = 10;
42717 if(config.minChars === undefined){
42723 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
42725 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
42728 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
42729 * rendering into an Roo.Editor, defaults to false)
42732 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
42733 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
42736 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
42739 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
42740 * the dropdown list (defaults to undefined, with no header element)
42744 * @cfg {String/Roo.Template} tpl The template to use to render the output
42748 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
42750 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
42752 listWidth: undefined,
42754 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
42755 * mode = 'remote' or 'text' if mode = 'local')
42757 displayField: undefined,
42759 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
42760 * mode = 'remote' or 'value' if mode = 'local').
42761 * Note: use of a valueField requires the user make a selection
42762 * in order for a value to be mapped.
42764 valueField: undefined,
42768 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
42769 * field's data value (defaults to the underlying DOM element's name)
42771 hiddenName: undefined,
42773 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
42777 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
42779 selectedClass: 'x-combo-selected',
42781 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
42782 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
42783 * which displays a downward arrow icon).
42785 triggerClass : 'x-form-arrow-trigger',
42787 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
42791 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
42792 * anchor positions (defaults to 'tl-bl')
42794 listAlign: 'tl-bl?',
42796 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
42800 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
42801 * query specified by the allQuery config option (defaults to 'query')
42803 triggerAction: 'query',
42805 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
42806 * (defaults to 4, does not apply if editable = false)
42810 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
42811 * delay (typeAheadDelay) if it matches a known value (defaults to false)
42815 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
42816 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
42820 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
42821 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
42825 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
42826 * when editable = true (defaults to false)
42828 selectOnFocus:false,
42830 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
42832 queryParam: 'query',
42834 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
42835 * when mode = 'remote' (defaults to 'Loading...')
42837 loadingText: 'Loading...',
42839 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
42843 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
42847 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
42848 * traditional select (defaults to true)
42852 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
42856 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
42860 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
42861 * listWidth has a higher value)
42865 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
42866 * allow the user to set arbitrary text into the field (defaults to false)
42868 forceSelection:false,
42870 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
42871 * if typeAhead = true (defaults to 250)
42873 typeAheadDelay : 250,
42875 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
42876 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
42878 valueNotFoundText : undefined,
42880 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
42882 blockFocus : false,
42885 * @cfg {Boolean} disableClear Disable showing of clear button.
42887 disableClear : false,
42889 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
42891 alwaysQuery : false,
42897 // element that contains real text value.. (when hidden is used..)
42900 onRender : function(ct, position)
42902 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
42904 if(this.hiddenName){
42905 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
42907 this.hiddenField.value =
42908 this.hiddenValue !== undefined ? this.hiddenValue :
42909 this.value !== undefined ? this.value : '';
42911 // prevent input submission
42912 this.el.dom.removeAttribute('name');
42918 this.el.dom.setAttribute('autocomplete', 'off');
42921 var cls = 'x-combo-list';
42923 this.list = new Roo.Layer({
42924 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
42927 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
42928 this.list.setWidth(lw);
42929 this.list.swallowEvent('mousewheel');
42930 this.assetHeight = 0;
42933 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
42934 this.assetHeight += this.header.getHeight();
42937 this.innerList = this.list.createChild({cls:cls+'-inner'});
42938 this.innerList.on('mouseover', this.onViewOver, this);
42939 this.innerList.on('mousemove', this.onViewMove, this);
42940 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42942 if(this.allowBlank && !this.pageSize && !this.disableClear){
42943 this.footer = this.list.createChild({cls:cls+'-ft'});
42944 this.pageTb = new Roo.Toolbar(this.footer);
42948 this.footer = this.list.createChild({cls:cls+'-ft'});
42949 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
42950 {pageSize: this.pageSize});
42954 if (this.pageTb && this.allowBlank && !this.disableClear) {
42956 this.pageTb.add(new Roo.Toolbar.Fill(), {
42957 cls: 'x-btn-icon x-btn-clear',
42959 handler: function()
42962 _this.clearValue();
42963 _this.onSelect(false, -1);
42968 this.assetHeight += this.footer.getHeight();
42973 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
42976 this.view = new Roo.View(this.innerList, this.tpl, {
42979 selectedClass: this.selectedClass
42982 this.view.on('click', this.onViewClick, this);
42984 this.store.on('beforeload', this.onBeforeLoad, this);
42985 this.store.on('load', this.onLoad, this);
42986 this.store.on('loadexception', this.onLoadException, this);
42988 if(this.resizable){
42989 this.resizer = new Roo.Resizable(this.list, {
42990 pinned:true, handles:'se'
42992 this.resizer.on('resize', function(r, w, h){
42993 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
42994 this.listWidth = w;
42995 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
42996 this.restrictHeight();
42998 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
43000 if(!this.editable){
43001 this.editable = true;
43002 this.setEditable(false);
43006 if (typeof(this.events.add.listeners) != 'undefined') {
43008 this.addicon = this.wrap.createChild(
43009 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
43011 this.addicon.on('click', function(e) {
43012 this.fireEvent('add', this);
43015 if (typeof(this.events.edit.listeners) != 'undefined') {
43017 this.editicon = this.wrap.createChild(
43018 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
43019 if (this.addicon) {
43020 this.editicon.setStyle('margin-left', '40px');
43022 this.editicon.on('click', function(e) {
43024 // we fire even if inothing is selected..
43025 this.fireEvent('edit', this, this.lastData );
43035 initEvents : function(){
43036 Roo.form.ComboBox.superclass.initEvents.call(this);
43038 this.keyNav = new Roo.KeyNav(this.el, {
43039 "up" : function(e){
43040 this.inKeyMode = true;
43044 "down" : function(e){
43045 if(!this.isExpanded()){
43046 this.onTriggerClick();
43048 this.inKeyMode = true;
43053 "enter" : function(e){
43054 this.onViewClick();
43058 "esc" : function(e){
43062 "tab" : function(e){
43063 this.onViewClick(false);
43064 this.fireEvent("specialkey", this, e);
43070 doRelay : function(foo, bar, hname){
43071 if(hname == 'down' || this.scope.isExpanded()){
43072 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
43079 this.queryDelay = Math.max(this.queryDelay || 10,
43080 this.mode == 'local' ? 10 : 250);
43081 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
43082 if(this.typeAhead){
43083 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
43085 if(this.editable !== false){
43086 this.el.on("keyup", this.onKeyUp, this);
43088 if(this.forceSelection){
43089 this.on('blur', this.doForce, this);
43093 onDestroy : function(){
43095 this.view.setStore(null);
43096 this.view.el.removeAllListeners();
43097 this.view.el.remove();
43098 this.view.purgeListeners();
43101 this.list.destroy();
43104 this.store.un('beforeload', this.onBeforeLoad, this);
43105 this.store.un('load', this.onLoad, this);
43106 this.store.un('loadexception', this.onLoadException, this);
43108 Roo.form.ComboBox.superclass.onDestroy.call(this);
43112 fireKey : function(e){
43113 if(e.isNavKeyPress() && !this.list.isVisible()){
43114 this.fireEvent("specialkey", this, e);
43119 onResize: function(w, h){
43120 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
43122 if(typeof w != 'number'){
43123 // we do not handle it!?!?
43126 var tw = this.trigger.getWidth();
43127 tw += this.addicon ? this.addicon.getWidth() : 0;
43128 tw += this.editicon ? this.editicon.getWidth() : 0;
43130 this.el.setWidth( this.adjustWidth('input', x));
43132 this.trigger.setStyle('left', x+'px');
43134 if(this.list && this.listWidth === undefined){
43135 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
43136 this.list.setWidth(lw);
43137 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
43145 * Allow or prevent the user from directly editing the field text. If false is passed,
43146 * the user will only be able to select from the items defined in the dropdown list. This method
43147 * is the runtime equivalent of setting the 'editable' config option at config time.
43148 * @param {Boolean} value True to allow the user to directly edit the field text
43150 setEditable : function(value){
43151 if(value == this.editable){
43154 this.editable = value;
43156 this.el.dom.setAttribute('readOnly', true);
43157 this.el.on('mousedown', this.onTriggerClick, this);
43158 this.el.addClass('x-combo-noedit');
43160 this.el.dom.setAttribute('readOnly', false);
43161 this.el.un('mousedown', this.onTriggerClick, this);
43162 this.el.removeClass('x-combo-noedit');
43167 onBeforeLoad : function(){
43168 if(!this.hasFocus){
43171 this.innerList.update(this.loadingText ?
43172 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
43173 this.restrictHeight();
43174 this.selectedIndex = -1;
43178 onLoad : function(){
43179 if(!this.hasFocus){
43182 if(this.store.getCount() > 0){
43184 this.restrictHeight();
43185 if(this.lastQuery == this.allQuery){
43187 this.el.dom.select();
43189 if(!this.selectByValue(this.value, true)){
43190 this.select(0, true);
43194 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
43195 this.taTask.delay(this.typeAheadDelay);
43199 this.onEmptyResults();
43204 onLoadException : function()
43207 Roo.log(this.store.reader.jsonData);
43208 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
43209 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
43215 onTypeAhead : function(){
43216 if(this.store.getCount() > 0){
43217 var r = this.store.getAt(0);
43218 var newValue = r.data[this.displayField];
43219 var len = newValue.length;
43220 var selStart = this.getRawValue().length;
43221 if(selStart != len){
43222 this.setRawValue(newValue);
43223 this.selectText(selStart, newValue.length);
43229 onSelect : function(record, index){
43230 if(this.fireEvent('beforeselect', this, record, index) !== false){
43231 this.setFromData(index > -1 ? record.data : false);
43233 this.fireEvent('select', this, record, index);
43238 * Returns the currently selected field value or empty string if no value is set.
43239 * @return {String} value The selected value
43241 getValue : function(){
43242 if(this.valueField){
43243 return typeof this.value != 'undefined' ? this.value : '';
43245 return Roo.form.ComboBox.superclass.getValue.call(this);
43249 * Clears any text/value currently set in the field
43251 clearValue : function(){
43252 if(this.hiddenField){
43253 this.hiddenField.value = '';
43256 this.setRawValue('');
43257 this.lastSelectionText = '';
43262 * Sets the specified value into the field. If the value finds a match, the corresponding record text
43263 * will be displayed in the field. If the value does not match the data value of an existing item,
43264 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
43265 * Otherwise the field will be blank (although the value will still be set).
43266 * @param {String} value The value to match
43268 setValue : function(v){
43270 if(this.valueField){
43271 var r = this.findRecord(this.valueField, v);
43273 text = r.data[this.displayField];
43274 }else if(this.valueNotFoundText !== undefined){
43275 text = this.valueNotFoundText;
43278 this.lastSelectionText = text;
43279 if(this.hiddenField){
43280 this.hiddenField.value = v;
43282 Roo.form.ComboBox.superclass.setValue.call(this, text);
43286 * @property {Object} the last set data for the element
43291 * Sets the value of the field based on a object which is related to the record format for the store.
43292 * @param {Object} value the value to set as. or false on reset?
43294 setFromData : function(o){
43295 var dv = ''; // display value
43296 var vv = ''; // value value..
43298 if (this.displayField) {
43299 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
43301 // this is an error condition!!!
43302 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
43305 if(this.valueField){
43306 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
43308 if(this.hiddenField){
43309 this.hiddenField.value = vv;
43311 this.lastSelectionText = dv;
43312 Roo.form.ComboBox.superclass.setValue.call(this, dv);
43316 // no hidden field.. - we store the value in 'value', but still display
43317 // display field!!!!
43318 this.lastSelectionText = dv;
43319 Roo.form.ComboBox.superclass.setValue.call(this, dv);
43325 reset : function(){
43326 // overridden so that last data is reset..
43327 this.setValue(this.resetValue);
43328 this.originalValue = this.getValue();
43329 this.clearInvalid();
43330 this.lastData = false;
43332 this.view.clearSelections();
43336 findRecord : function(prop, value){
43338 if(this.store.getCount() > 0){
43339 this.store.each(function(r){
43340 if(r.data[prop] == value){
43350 getName: function()
43352 // returns hidden if it's set..
43353 if (!this.rendered) {return ''};
43354 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
43358 onViewMove : function(e, t){
43359 this.inKeyMode = false;
43363 onViewOver : function(e, t){
43364 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
43367 var item = this.view.findItemFromChild(t);
43369 var index = this.view.indexOf(item);
43370 this.select(index, false);
43375 onViewClick : function(doFocus)
43377 var index = this.view.getSelectedIndexes()[0];
43378 var r = this.store.getAt(index);
43380 this.onSelect(r, index);
43382 if(doFocus !== false && !this.blockFocus){
43388 restrictHeight : function(){
43389 this.innerList.dom.style.height = '';
43390 var inner = this.innerList.dom;
43391 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
43392 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
43393 this.list.beginUpdate();
43394 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
43395 this.list.alignTo(this.el, this.listAlign);
43396 this.list.endUpdate();
43400 onEmptyResults : function(){
43405 * Returns true if the dropdown list is expanded, else false.
43407 isExpanded : function(){
43408 return this.list.isVisible();
43412 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
43413 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
43414 * @param {String} value The data value of the item to select
43415 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
43416 * selected item if it is not currently in view (defaults to true)
43417 * @return {Boolean} True if the value matched an item in the list, else false
43419 selectByValue : function(v, scrollIntoView){
43420 if(v !== undefined && v !== null){
43421 var r = this.findRecord(this.valueField || this.displayField, v);
43423 this.select(this.store.indexOf(r), scrollIntoView);
43431 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
43432 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
43433 * @param {Number} index The zero-based index of the list item to select
43434 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
43435 * selected item if it is not currently in view (defaults to true)
43437 select : function(index, scrollIntoView){
43438 this.selectedIndex = index;
43439 this.view.select(index);
43440 if(scrollIntoView !== false){
43441 var el = this.view.getNode(index);
43443 this.innerList.scrollChildIntoView(el, false);
43449 selectNext : function(){
43450 var ct = this.store.getCount();
43452 if(this.selectedIndex == -1){
43454 }else if(this.selectedIndex < ct-1){
43455 this.select(this.selectedIndex+1);
43461 selectPrev : function(){
43462 var ct = this.store.getCount();
43464 if(this.selectedIndex == -1){
43466 }else if(this.selectedIndex != 0){
43467 this.select(this.selectedIndex-1);
43473 onKeyUp : function(e){
43474 if(this.editable !== false && !e.isSpecialKey()){
43475 this.lastKey = e.getKey();
43476 this.dqTask.delay(this.queryDelay);
43481 validateBlur : function(){
43482 return !this.list || !this.list.isVisible();
43486 initQuery : function(){
43487 this.doQuery(this.getRawValue());
43491 doForce : function(){
43492 if(this.el.dom.value.length > 0){
43493 this.el.dom.value =
43494 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
43500 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
43501 * query allowing the query action to be canceled if needed.
43502 * @param {String} query The SQL query to execute
43503 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
43504 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
43505 * saved in the current store (defaults to false)
43507 doQuery : function(q, forceAll){
43508 if(q === undefined || q === null){
43513 forceAll: forceAll,
43517 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
43521 forceAll = qe.forceAll;
43522 if(forceAll === true || (q.length >= this.minChars)){
43523 if(this.lastQuery != q || this.alwaysQuery){
43524 this.lastQuery = q;
43525 if(this.mode == 'local'){
43526 this.selectedIndex = -1;
43528 this.store.clearFilter();
43530 this.store.filter(this.displayField, q);
43534 this.store.baseParams[this.queryParam] = q;
43536 params: this.getParams(q)
43541 this.selectedIndex = -1;
43548 getParams : function(q){
43550 //p[this.queryParam] = q;
43553 p.limit = this.pageSize;
43559 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
43561 collapse : function(){
43562 if(!this.isExpanded()){
43566 Roo.get(document).un('mousedown', this.collapseIf, this);
43567 Roo.get(document).un('mousewheel', this.collapseIf, this);
43568 if (!this.editable) {
43569 Roo.get(document).un('keydown', this.listKeyPress, this);
43571 this.fireEvent('collapse', this);
43575 collapseIf : function(e){
43576 if(!e.within(this.wrap) && !e.within(this.list)){
43582 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
43584 expand : function(){
43585 if(this.isExpanded() || !this.hasFocus){
43588 this.list.alignTo(this.el, this.listAlign);
43590 Roo.get(document).on('mousedown', this.collapseIf, this);
43591 Roo.get(document).on('mousewheel', this.collapseIf, this);
43592 if (!this.editable) {
43593 Roo.get(document).on('keydown', this.listKeyPress, this);
43596 this.fireEvent('expand', this);
43600 // Implements the default empty TriggerField.onTriggerClick function
43601 onTriggerClick : function(){
43605 if(this.isExpanded()){
43607 if (!this.blockFocus) {
43612 this.hasFocus = true;
43613 if(this.triggerAction == 'all') {
43614 this.doQuery(this.allQuery, true);
43616 this.doQuery(this.getRawValue());
43618 if (!this.blockFocus) {
43623 listKeyPress : function(e)
43625 //Roo.log('listkeypress');
43626 // scroll to first matching element based on key pres..
43627 if (e.isSpecialKey()) {
43630 var k = String.fromCharCode(e.getKey()).toUpperCase();
43633 var csel = this.view.getSelectedNodes();
43634 var cselitem = false;
43636 var ix = this.view.indexOf(csel[0]);
43637 cselitem = this.store.getAt(ix);
43638 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
43644 this.store.each(function(v) {
43646 // start at existing selection.
43647 if (cselitem.id == v.id) {
43653 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
43654 match = this.store.indexOf(v);
43659 if (match === false) {
43660 return true; // no more action?
43663 this.view.select(match);
43664 var sn = Roo.get(this.view.getSelectedNodes()[0]);
43665 sn.scrollIntoView(sn.dom.parentNode, false);
43669 * @cfg {Boolean} grow
43673 * @cfg {Number} growMin
43677 * @cfg {Number} growMax
43685 * Copyright(c) 2010-2012, Roo J Solutions Limited
43692 * @class Roo.form.ComboBoxArray
43693 * @extends Roo.form.TextField
43694 * A facebook style adder... for lists of email / people / countries etc...
43695 * pick multiple items from a combo box, and shows each one.
43697 * Fred [x] Brian [x] [Pick another |v]
43700 * For this to work: it needs various extra information
43701 * - normal combo problay has
43703 * + displayField, valueField
43705 * For our purpose...
43708 * If we change from 'extends' to wrapping...
43715 * Create a new ComboBoxArray.
43716 * @param {Object} config Configuration options
43720 Roo.form.ComboBoxArray = function(config)
43724 * @event beforeremove
43725 * Fires before remove the value from the list
43726 * @param {Roo.form.ComboBoxArray} _self This combo box array
43727 * @param {Roo.form.ComboBoxArray.Item} item removed item
43729 'beforeremove' : true,
43732 * Fires when remove the value from the list
43733 * @param {Roo.form.ComboBoxArray} _self This combo box array
43734 * @param {Roo.form.ComboBoxArray.Item} item removed item
43741 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
43743 this.items = new Roo.util.MixedCollection(false);
43745 // construct the child combo...
43755 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
43758 * @cfg {Roo.form.ComboBox} combo [required] The combo box that is wrapped
43763 // behavies liek a hiddne field
43764 inputType: 'hidden',
43766 * @cfg {Number} width The width of the box that displays the selected element
43773 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
43777 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
43779 hiddenName : false,
43781 * @cfg {String} seperator The value seperator normally ','
43785 // private the array of items that are displayed..
43787 // private - the hidden field el.
43789 // private - the filed el..
43792 //validateValue : function() { return true; }, // all values are ok!
43793 //onAddClick: function() { },
43795 onRender : function(ct, position)
43798 // create the standard hidden element
43799 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
43802 // give fake names to child combo;
43803 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
43804 this.combo.name = this.name ? (this.name+'-subcombo') : this.name;
43806 this.combo = Roo.factory(this.combo, Roo.form);
43807 this.combo.onRender(ct, position);
43808 if (typeof(this.combo.width) != 'undefined') {
43809 this.combo.onResize(this.combo.width,0);
43812 this.combo.initEvents();
43814 // assigned so form know we need to do this..
43815 this.store = this.combo.store;
43816 this.valueField = this.combo.valueField;
43817 this.displayField = this.combo.displayField ;
43820 this.combo.wrap.addClass('x-cbarray-grp');
43822 var cbwrap = this.combo.wrap.createChild(
43823 {tag: 'div', cls: 'x-cbarray-cb'},
43828 this.hiddenEl = this.combo.wrap.createChild({
43829 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
43831 this.el = this.combo.wrap.createChild({
43832 tag: 'input', type:'hidden' , name: this.name, value : ''
43834 // this.el.dom.removeAttribute("name");
43837 this.outerWrap = this.combo.wrap;
43838 this.wrap = cbwrap;
43840 this.outerWrap.setWidth(this.width);
43841 this.outerWrap.dom.removeChild(this.el.dom);
43843 this.wrap.dom.appendChild(this.el.dom);
43844 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
43845 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
43847 this.combo.trigger.setStyle('position','relative');
43848 this.combo.trigger.setStyle('left', '0px');
43849 this.combo.trigger.setStyle('top', '2px');
43851 this.combo.el.setStyle('vertical-align', 'text-bottom');
43853 //this.trigger.setStyle('vertical-align', 'top');
43855 // this should use the code from combo really... on('add' ....)
43859 this.adder = this.outerWrap.createChild(
43860 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
43862 this.adder.on('click', function(e) {
43863 _t.fireEvent('adderclick', this, e);
43867 //this.adder.on('click', this.onAddClick, _t);
43870 this.combo.on('select', function(cb, rec, ix) {
43871 this.addItem(rec.data);
43874 cb.el.dom.value = '';
43875 //cb.lastData = rec.data;
43884 getName: function()
43886 // returns hidden if it's set..
43887 if (!this.rendered) {return ''};
43888 return this.hiddenName ? this.hiddenName : this.name;
43893 onResize: function(w, h){
43896 // not sure if this is needed..
43897 //this.combo.onResize(w,h);
43899 if(typeof w != 'number'){
43900 // we do not handle it!?!?
43903 var tw = this.combo.trigger.getWidth();
43904 tw += this.addicon ? this.addicon.getWidth() : 0;
43905 tw += this.editicon ? this.editicon.getWidth() : 0;
43907 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
43909 this.combo.trigger.setStyle('left', '0px');
43911 if(this.list && this.listWidth === undefined){
43912 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
43913 this.list.setWidth(lw);
43914 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
43921 addItem: function(rec)
43923 var valueField = this.combo.valueField;
43924 var displayField = this.combo.displayField;
43926 if (this.items.indexOfKey(rec[valueField]) > -1) {
43927 //console.log("GOT " + rec.data.id);
43931 var x = new Roo.form.ComboBoxArray.Item({
43932 //id : rec[this.idField],
43934 displayField : displayField ,
43935 tipField : displayField ,
43939 this.items.add(rec[valueField],x);
43940 // add it before the element..
43941 this.updateHiddenEl();
43942 x.render(this.outerWrap, this.wrap.dom);
43943 // add the image handler..
43946 updateHiddenEl : function()
43949 if (!this.hiddenEl) {
43953 var idField = this.combo.valueField;
43955 this.items.each(function(f) {
43956 ar.push(f.data[idField]);
43958 this.hiddenEl.dom.value = ar.join(this.seperator);
43964 this.items.clear();
43966 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
43970 this.el.dom.value = '';
43971 if (this.hiddenEl) {
43972 this.hiddenEl.dom.value = '';
43976 getValue: function()
43978 return this.hiddenEl ? this.hiddenEl.dom.value : '';
43980 setValue: function(v) // not a valid action - must use addItems..
43985 if (this.store.isLocal && (typeof(v) == 'string')) {
43986 // then we can use the store to find the values..
43987 // comma seperated at present.. this needs to allow JSON based encoding..
43988 this.hiddenEl.value = v;
43990 Roo.each(v.split(this.seperator), function(k) {
43991 Roo.log("CHECK " + this.valueField + ',' + k);
43992 var li = this.store.query(this.valueField, k);
43997 add[this.valueField] = k;
43998 add[this.displayField] = li.item(0).data[this.displayField];
44004 if (typeof(v) == 'object' ) {
44005 // then let's assume it's an array of objects..
44006 Roo.each(v, function(l) {
44008 if (typeof(l) == 'string') {
44010 add[this.valueField] = l;
44011 add[this.displayField] = l
44020 setFromData: function(v)
44022 // this recieves an object, if setValues is called.
44024 this.el.dom.value = v[this.displayField];
44025 this.hiddenEl.dom.value = v[this.valueField];
44026 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
44029 var kv = v[this.valueField];
44030 var dv = v[this.displayField];
44031 kv = typeof(kv) != 'string' ? '' : kv;
44032 dv = typeof(dv) != 'string' ? '' : dv;
44035 var keys = kv.split(this.seperator);
44036 var display = dv.split(this.seperator);
44037 for (var i = 0 ; i < keys.length; i++) {
44039 add[this.valueField] = keys[i];
44040 add[this.displayField] = display[i];
44048 * Validates the combox array value
44049 * @return {Boolean} True if the value is valid, else false
44051 validate : function(){
44052 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
44053 this.clearInvalid();
44059 validateValue : function(value){
44060 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
44068 isDirty : function() {
44069 if(this.disabled) {
44074 var d = Roo.decode(String(this.originalValue));
44076 return String(this.getValue()) !== String(this.originalValue);
44079 var originalValue = [];
44081 for (var i = 0; i < d.length; i++){
44082 originalValue.push(d[i][this.valueField]);
44085 return String(this.getValue()) !== String(originalValue.join(this.seperator));
44094 * @class Roo.form.ComboBoxArray.Item
44095 * @extends Roo.BoxComponent
44096 * A selected item in the list
44097 * Fred [x] Brian [x] [Pick another |v]
44100 * Create a new item.
44101 * @param {Object} config Configuration options
44104 Roo.form.ComboBoxArray.Item = function(config) {
44105 config.id = Roo.id();
44106 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
44109 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
44112 displayField : false,
44116 defaultAutoCreate : {
44118 cls: 'x-cbarray-item',
44125 src : Roo.BLANK_IMAGE_URL ,
44133 onRender : function(ct, position)
44135 Roo.form.Field.superclass.onRender.call(this, ct, position);
44138 var cfg = this.getAutoCreate();
44139 this.el = ct.createChild(cfg, position);
44142 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
44144 this.el.child('div').dom.innerHTML = this.cb.renderer ?
44145 this.cb.renderer(this.data) :
44146 String.format('{0}',this.data[this.displayField]);
44149 this.el.child('div').dom.setAttribute('qtip',
44150 String.format('{0}',this.data[this.tipField])
44153 this.el.child('img').on('click', this.remove, this);
44157 remove : function()
44159 if(this.cb.disabled){
44163 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
44164 this.cb.items.remove(this);
44165 this.el.child('img').un('click', this.remove, this);
44167 this.cb.updateHiddenEl();
44169 this.cb.fireEvent('remove', this.cb, this);
44174 * RooJS Library 1.1.1
44175 * Copyright(c) 2008-2011 Alan Knowles
44182 * @class Roo.form.ComboNested
44183 * @extends Roo.form.ComboBox
44184 * A combobox for that allows selection of nested items in a list,
44199 * Create a new ComboNested
44200 * @param {Object} config Configuration options
44202 Roo.form.ComboNested = function(config){
44203 Roo.form.ComboCheck.superclass.constructor.call(this, config);
44204 // should verify some data...
44206 // hiddenName = required..
44207 // displayField = required
44208 // valudField == required
44209 var req= [ 'hiddenName', 'displayField', 'valueField' ];
44211 Roo.each(req, function(e) {
44212 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
44213 throw "Roo.form.ComboNested : missing value for: " + e;
44220 Roo.extend(Roo.form.ComboNested, Roo.form.ComboBox, {
44223 * @config {Number} max Number of columns to show
44228 list : null, // the outermost div..
44229 innerLists : null, // the
44233 loadingChildren : false,
44235 onRender : function(ct, position)
44237 Roo.form.ComboBox.superclass.onRender.call(this, ct, position); // skip parent call - got to above..
44239 if(this.hiddenName){
44240 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
44242 this.hiddenField.value =
44243 this.hiddenValue !== undefined ? this.hiddenValue :
44244 this.value !== undefined ? this.value : '';
44246 // prevent input submission
44247 this.el.dom.removeAttribute('name');
44253 this.el.dom.setAttribute('autocomplete', 'off');
44256 var cls = 'x-combo-list';
44258 this.list = new Roo.Layer({
44259 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
44262 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
44263 this.list.setWidth(lw);
44264 this.list.swallowEvent('mousewheel');
44265 this.assetHeight = 0;
44268 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
44269 this.assetHeight += this.header.getHeight();
44271 this.innerLists = [];
44274 for (var i =0 ; i < this.maxColumns; i++) {
44275 this.onRenderList( cls, i);
44278 // always needs footer, as we are going to have an 'OK' button.
44279 this.footer = this.list.createChild({cls:cls+'-ft'});
44280 this.pageTb = new Roo.Toolbar(this.footer);
44285 handler: function()
44291 if ( this.allowBlank && !this.disableClear) {
44293 this.pageTb.add(new Roo.Toolbar.Fill(), {
44294 cls: 'x-btn-icon x-btn-clear',
44296 handler: function()
44299 _this.clearValue();
44300 _this.onSelect(false, -1);
44305 this.assetHeight += this.footer.getHeight();
44309 onRenderList : function ( cls, i)
44312 var lw = Math.floor(
44313 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
44316 this.list.setWidth(lw); // default to '1'
44318 var il = this.innerLists[i] = this.list.createChild({cls:cls+'-inner'});
44319 //il.on('mouseover', this.onViewOver, this, { list: i });
44320 //il.on('mousemove', this.onViewMove, this, { list: i });
44322 il.setStyle({ 'overflow-x' : 'hidden'});
44325 this.tpl = new Roo.Template({
44326 html : '<div class="'+cls+'-item '+cls+'-item-{cn:this.isEmpty}">{' + this.displayField + '}</div>',
44327 isEmpty: function (value, allValues) {
44329 var dl = typeof(value.data) != 'undefined' ? value.data.length : value.length; ///json is a nested response..
44330 return dl ? 'has-children' : 'no-children'
44335 var store = this.store;
44337 store = new Roo.data.SimpleStore({
44338 //fields : this.store.reader.meta.fields,
44339 reader : this.store.reader,
44343 this.stores[i] = store;
44345 var view = this.views[i] = new Roo.View(
44351 selectedClass: this.selectedClass
44354 view.getEl().setWidth(lw);
44355 view.getEl().setStyle({
44356 position: i < 1 ? 'relative' : 'absolute',
44358 left: (i * lw ) + 'px',
44359 display : i > 0 ? 'none' : 'block'
44361 view.on('selectionchange', this.onSelectChange.createDelegate(this, {list : i }, true));
44362 view.on('dblclick', this.onDoubleClick.createDelegate(this, {list : i }, true));
44363 //view.on('click', this.onViewClick, this, { list : i });
44365 store.on('beforeload', this.onBeforeLoad, this);
44366 store.on('load', this.onLoad, this, { list : i});
44367 store.on('loadexception', this.onLoadException, this);
44369 // hide the other vies..
44375 restrictHeight : function()
44378 Roo.each(this.innerLists, function(il,i) {
44379 var el = this.views[i].getEl();
44380 el.dom.style.height = '';
44381 var inner = el.dom;
44382 var h = Math.max(il.clientHeight, il.offsetHeight, il.scrollHeight);
44383 // only adjust heights on other ones..
44384 mh = Math.max(h, mh);
44387 el.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
44388 il.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
44395 this.list.beginUpdate();
44396 this.list.setHeight(mh+this.list.getFrameWidth('tb')+this.assetHeight);
44397 this.list.alignTo(this.el, this.listAlign);
44398 this.list.endUpdate();
44403 // -- store handlers..
44405 onBeforeLoad : function()
44407 if(!this.hasFocus){
44410 this.innerLists[0].update(this.loadingText ?
44411 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
44412 this.restrictHeight();
44413 this.selectedIndex = -1;
44416 onLoad : function(a,b,c,d)
44418 if (!this.loadingChildren) {
44419 // then we are loading the top level. - hide the children
44420 for (var i = 1;i < this.views.length; i++) {
44421 this.views[i].getEl().setStyle({ display : 'none' });
44423 var lw = Math.floor(
44424 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
44427 this.list.setWidth(lw); // default to '1'
44431 if(!this.hasFocus){
44435 if(this.store.getCount() > 0) {
44437 this.restrictHeight();
44439 this.onEmptyResults();
44442 if (!this.loadingChildren) {
44443 this.selectActive();
44446 this.stores[1].loadData([]);
44447 this.stores[2].loadData([]);
44456 onLoadException : function()
44459 Roo.log(this.store.reader.jsonData);
44460 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
44461 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
44466 // no cleaning of leading spaces on blur here.
44467 cleanLeadingSpace : function(e) { },
44470 onSelectChange : function (view, sels, opts )
44472 var ix = view.getSelectedIndexes();
44474 if (opts.list > this.maxColumns - 2) {
44475 if (view.store.getCount()< 1) {
44476 this.views[opts.list ].getEl().setStyle({ display : 'none' });
44480 // used to clear ?? but if we are loading unselected
44481 this.setFromData(view.store.getAt(ix[0]).data);
44490 // this get's fired when trigger opens..
44491 // this.setFromData({});
44492 var str = this.stores[opts.list+1];
44493 str.data.clear(); // removeall wihtout the fire events..
44497 var rec = view.store.getAt(ix[0]);
44499 this.setFromData(rec.data);
44500 this.fireEvent('select', this, rec, ix[0]);
44502 var lw = Math.floor(
44504 (this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')
44505 ) / this.maxColumns
44507 this.loadingChildren = true;
44508 this.stores[opts.list+1].loadDataFromChildren( rec );
44509 this.loadingChildren = false;
44510 var dl = this.stores[opts.list+1]. getTotalCount();
44512 this.views[opts.list+1].getEl().setHeight( this.innerLists[0].getHeight());
44514 this.views[opts.list+1].getEl().setStyle({ display : dl ? 'block' : 'none' });
44515 for (var i = opts.list+2; i < this.views.length;i++) {
44516 this.views[i].getEl().setStyle({ display : 'none' });
44519 this.innerLists[opts.list+1].setHeight( this.innerLists[0].getHeight());
44520 this.list.setWidth(lw * (opts.list + (dl ? 2 : 1)));
44522 if (this.isLoading) {
44523 // this.selectActive(opts.list);
44531 onDoubleClick : function()
44533 this.collapse(); //??
44541 recordToStack : function(store, prop, value, stack)
44543 var cstore = new Roo.data.SimpleStore({
44544 //fields : this.store.reader.meta.fields, // we need array reader.. for
44545 reader : this.store.reader,
44549 var record = false;
44551 if(store.getCount() < 1){
44554 store.each(function(r){
44555 if(r.data[prop] == value){
44560 if (r.data.cn && r.data.cn.length) {
44561 cstore.loadDataFromChildren( r);
44562 var cret = _this.recordToStack(cstore, prop, value, stack);
44563 if (cret !== false) {
44572 if (record == false) {
44575 stack.unshift(srec);
44580 * find the stack of stores that match our value.
44585 selectActive : function ()
44587 // if store is not loaded, then we will need to wait for that to happen first.
44589 this.recordToStack(this.store, this.valueField, this.getValue(), stack);
44590 for (var i = 0; i < stack.length; i++ ) {
44591 this.views[i].select(stack[i].store.indexOf(stack[i]), false, false );
44603 * Ext JS Library 1.1.1
44604 * Copyright(c) 2006-2007, Ext JS, LLC.
44606 * Originally Released Under LGPL - original licence link has changed is not relivant.
44609 * <script type="text/javascript">
44612 * @class Roo.form.Checkbox
44613 * @extends Roo.form.Field
44614 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
44616 * Creates a new Checkbox
44617 * @param {Object} config Configuration options
44619 Roo.form.Checkbox = function(config){
44620 Roo.form.Checkbox.superclass.constructor.call(this, config);
44624 * Fires when the checkbox is checked or unchecked.
44625 * @param {Roo.form.Checkbox} this This checkbox
44626 * @param {Boolean} checked The new checked value
44632 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
44634 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
44636 focusClass : undefined,
44638 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
44640 fieldClass: "x-form-field",
44642 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
44646 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
44647 * {tag: "input", type: "checkbox", autocomplete: "off"})
44649 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
44651 * @cfg {String} boxLabel The text that appears beside the checkbox
44655 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
44659 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
44661 valueOff: '0', // value when not checked..
44663 actionMode : 'viewEl',
44666 itemCls : 'x-menu-check-item x-form-item',
44667 groupClass : 'x-menu-group-item',
44668 inputType : 'hidden',
44671 inSetChecked: false, // check that we are not calling self...
44673 inputElement: false, // real input element?
44674 basedOn: false, // ????
44676 isFormField: true, // not sure where this is needed!!!!
44678 onResize : function(){
44679 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
44680 if(!this.boxLabel){
44681 this.el.alignTo(this.wrap, 'c-c');
44685 initEvents : function(){
44686 Roo.form.Checkbox.superclass.initEvents.call(this);
44687 this.el.on("click", this.onClick, this);
44688 this.el.on("change", this.onClick, this);
44692 getResizeEl : function(){
44696 getPositionEl : function(){
44701 onRender : function(ct, position){
44702 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
44704 if(this.inputValue !== undefined){
44705 this.el.dom.value = this.inputValue;
44708 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
44709 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
44710 var viewEl = this.wrap.createChild({
44711 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
44712 this.viewEl = viewEl;
44713 this.wrap.on('click', this.onClick, this);
44715 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
44716 this.el.on('propertychange', this.setFromHidden, this); //ie
44721 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
44722 // viewEl.on('click', this.onClick, this);
44724 //if(this.checked){
44725 this.setChecked(this.checked);
44727 //this.checked = this.el.dom;
44733 initValue : Roo.emptyFn,
44736 * Returns the checked state of the checkbox.
44737 * @return {Boolean} True if checked, else false
44739 getValue : function(){
44741 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
44743 return this.valueOff;
44748 onClick : function(){
44749 if (this.disabled) {
44752 this.setChecked(!this.checked);
44754 //if(this.el.dom.checked != this.checked){
44755 // this.setValue(this.el.dom.checked);
44760 * Sets the checked state of the checkbox.
44761 * On is always based on a string comparison between inputValue and the param.
44762 * @param {Boolean/String} value - the value to set
44763 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
44765 setValue : function(v,suppressEvent){
44768 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
44769 //if(this.el && this.el.dom){
44770 // this.el.dom.checked = this.checked;
44771 // this.el.dom.defaultChecked = this.checked;
44773 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
44774 //this.fireEvent("check", this, this.checked);
44777 setChecked : function(state,suppressEvent)
44779 if (this.inSetChecked) {
44780 this.checked = state;
44786 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
44788 this.checked = state;
44789 if(suppressEvent !== true){
44790 this.fireEvent('check', this, state);
44792 this.inSetChecked = true;
44793 this.el.dom.value = state ? this.inputValue : this.valueOff;
44794 this.inSetChecked = false;
44797 // handle setting of hidden value by some other method!!?!?
44798 setFromHidden: function()
44803 //console.log("SET FROM HIDDEN");
44804 //alert('setFrom hidden');
44805 this.setValue(this.el.dom.value);
44808 onDestroy : function()
44811 Roo.get(this.viewEl).remove();
44814 Roo.form.Checkbox.superclass.onDestroy.call(this);
44817 setBoxLabel : function(str)
44819 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
44824 * Ext JS Library 1.1.1
44825 * Copyright(c) 2006-2007, Ext JS, LLC.
44827 * Originally Released Under LGPL - original licence link has changed is not relivant.
44830 * <script type="text/javascript">
44834 * @class Roo.form.Radio
44835 * @extends Roo.form.Checkbox
44836 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
44837 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
44839 * Creates a new Radio
44840 * @param {Object} config Configuration options
44842 Roo.form.Radio = function(){
44843 Roo.form.Radio.superclass.constructor.apply(this, arguments);
44845 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
44846 inputType: 'radio',
44849 * If this radio is part of a group, it will return the selected value
44852 getGroupValue : function(){
44853 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
44857 onRender : function(ct, position){
44858 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
44860 if(this.inputValue !== undefined){
44861 this.el.dom.value = this.inputValue;
44864 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
44865 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
44866 //var viewEl = this.wrap.createChild({
44867 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
44868 //this.viewEl = viewEl;
44869 //this.wrap.on('click', this.onClick, this);
44871 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
44872 //this.el.on('propertychange', this.setFromHidden, this); //ie
44877 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
44878 // viewEl.on('click', this.onClick, this);
44881 this.el.dom.checked = 'checked' ;
44887 });Roo.rtf = {}; // namespace
44888 Roo.rtf.Hex = function(hex)
44892 Roo.rtf.Paragraph = function(opts)
44894 this.content = []; ///??? is that used?
44895 };Roo.rtf.Span = function(opts)
44897 this.value = opts.value;
44900 Roo.rtf.Group = function(parent)
44902 // we dont want to acutally store parent - it will make debug a nightmare..
44910 Roo.rtf.Group.prototype = {
44914 addContent : function(node) {
44915 // could set styles...
44916 this.content.push(node);
44918 addChild : function(cn)
44922 // only for images really...
44923 toDataURL : function()
44925 var mimetype = false;
44927 case this.content.filter(function(a) { return a.value == 'pngblip' } ).length > 0:
44928 mimetype = "image/png";
44930 case this.content.filter(function(a) { return a.value == 'jpegblip' } ).length > 0:
44931 mimetype = "image/jpeg";
44934 return 'about:blank'; // ?? error?
44938 var hexstring = this.content[this.content.length-1].value;
44940 return 'data:' + mimetype + ';base64,' + btoa(hexstring.match(/\w{2}/g).map(function(a) {
44941 return String.fromCharCode(parseInt(a, 16));
44946 // this looks like it's normally the {rtf{ .... }}
44947 Roo.rtf.Document = function()
44949 // we dont want to acutally store parent - it will make debug a nightmare..
44955 Roo.extend(Roo.rtf.Document, Roo.rtf.Group, {
44956 addChild : function(cn)
44960 case 'rtlch': // most content seems to be inside this??
44963 this.rtlch.push(cn);
44966 this[cn.type] = cn;
44971 getElementsByType : function(type)
44974 this._getElementsByType(type, ret, this.cn, 'rtf');
44977 _getElementsByType : function (type, ret, search_array, path)
44979 search_array.forEach(function(n,i) {
44980 if (n.type == type) {
44981 n.path = path + '/' + n.type + ':' + i;
44984 if (n.cn.length > 0) {
44985 this._getElementsByType(type, ret, n.cn, path + '/' + n.type+':'+i);
44992 Roo.rtf.Ctrl = function(opts)
44994 this.value = opts.value;
44995 this.param = opts.param;
45000 * based on this https://github.com/iarna/rtf-parser
45001 * it's really only designed to extract pict from pasted RTF
45005 * var images = new Roo.rtf.Parser().parse(a_string).filter(function(g) { return g.type == 'pict'; });
45014 Roo.rtf.Parser = function(text) {
45015 //super({objectMode: true})
45017 this.parserState = this.parseText;
45019 // these are for interpeter...
45021 ///this.parserState = this.parseTop
45022 this.groupStack = [];
45023 this.hexStore = [];
45026 this.groups = []; // where we put the return.
45028 for (var ii = 0; ii < text.length; ++ii) {
45031 if (text[ii] === '\n') {
45037 this.parserState(text[ii]);
45043 Roo.rtf.Parser.prototype = {
45044 text : '', // string being parsed..
45046 controlWordParam : '',
45050 groupStack : false,
45055 row : 1, // reportin?
45059 push : function (el)
45061 var m = 'cmd'+ el.type;
45062 if (typeof(this[m]) == 'undefined') {
45063 Roo.log('invalid cmd:' + el.type);
45069 flushHexStore : function()
45071 if (this.hexStore.length < 1) {
45074 var hexstr = this.hexStore.map(
45079 this.group.addContent( new Roo.rtf.Hex( hexstr ));
45082 this.hexStore.splice(0)
45086 cmdgroupstart : function()
45088 this.flushHexStore();
45090 this.groupStack.push(this.group);
45093 if (this.doc === false) {
45094 this.group = this.doc = new Roo.rtf.Document();
45098 this.group = new Roo.rtf.Group(this.group);
45100 cmdignorable : function()
45102 this.flushHexStore();
45103 this.group.ignorable = true;
45105 cmdendparagraph : function()
45107 this.flushHexStore();
45108 this.group.addContent(new Roo.rtf.Paragraph());
45110 cmdgroupend : function ()
45112 this.flushHexStore();
45113 var endingGroup = this.group;
45116 this.group = this.groupStack.pop();
45118 this.group.addChild(endingGroup);
45123 var doc = this.group || this.doc;
45124 //if (endingGroup instanceof FontTable) {
45125 // doc.fonts = endingGroup.table
45126 //} else if (endingGroup instanceof ColorTable) {
45127 // doc.colors = endingGroup.table
45128 //} else if (endingGroup !== this.doc && !endingGroup.get('ignorable')) {
45129 if (endingGroup.ignorable === false) {
45131 this.groups.push(endingGroup);
45132 // Roo.log( endingGroup );
45134 //Roo.each(endingGroup.content, function(item)) {
45135 // doc.addContent(item);
45137 //process.emit('debug', 'GROUP END', endingGroup.type, endingGroup.get('ignorable'))
45140 cmdtext : function (cmd)
45142 this.flushHexStore();
45143 if (!this.group) { // an RTF fragment, missing the {\rtf1 header
45144 //this.group = this.doc
45146 this.group.addContent(new Roo.rtf.Span(cmd));
45148 cmdcontrolword : function (cmd)
45150 this.flushHexStore();
45151 if (!this.group.type) {
45152 this.group.type = cmd.value;
45155 this.group.addContent(new Roo.rtf.Ctrl(cmd));
45156 // we actually don't care about ctrl words...
45159 var method = 'ctrl$' + cmd.value.replace(/-(.)/g, (_, char) => char.toUpperCase())
45160 if (this[method]) {
45161 this[method](cmd.param)
45163 if (!this.group.get('ignorable')) process.emit('debug', method, cmd.param)
45167 cmdhexchar : function(cmd) {
45168 this.hexStore.push(cmd);
45170 cmderror : function(cmd) {
45171 throw new Exception (cmd.value);
45176 if (this.text !== '\u0000') this.emitText()
45182 parseText : function(c)
45185 this.parserState = this.parseEscapes;
45186 } else if (c === '{') {
45187 this.emitStartGroup();
45188 } else if (c === '}') {
45189 this.emitEndGroup();
45190 } else if (c === '\x0A' || c === '\x0D') {
45191 // cr/lf are noise chars
45197 parseEscapes: function (c)
45199 if (c === '\\' || c === '{' || c === '}') {
45201 this.parserState = this.parseText;
45203 this.parserState = this.parseControlSymbol;
45204 this.parseControlSymbol(c);
45207 parseControlSymbol: function(c)
45210 this.text += '\u00a0'; // nbsp
45211 this.parserState = this.parseText
45212 } else if (c === '-') {
45213 this.text += '\u00ad'; // soft hyphen
45214 } else if (c === '_') {
45215 this.text += '\u2011'; // non-breaking hyphen
45216 } else if (c === '*') {
45217 this.emitIgnorable();
45218 this.parserState = this.parseText;
45219 } else if (c === "'") {
45220 this.parserState = this.parseHexChar;
45221 } else if (c === '|') { // formula cacter
45222 this.emitFormula();
45223 this.parserState = this.parseText;
45224 } else if (c === ':') { // subentry in an index entry
45225 this.emitIndexSubEntry();
45226 this.parserState = this.parseText;
45227 } else if (c === '\x0a') {
45228 this.emitEndParagraph();
45229 this.parserState = this.parseText;
45230 } else if (c === '\x0d') {
45231 this.emitEndParagraph();
45232 this.parserState = this.parseText;
45234 this.parserState = this.parseControlWord;
45235 this.parseControlWord(c);
45238 parseHexChar: function (c)
45240 if (/^[A-Fa-f0-9]$/.test(c)) {
45242 if (this.hexChar.length >= 2) {
45243 this.emitHexChar();
45244 this.parserState = this.parseText;
45248 this.emitError("Invalid character \"" + c + "\" in hex literal.");
45249 this.parserState = this.parseText;
45252 parseControlWord : function(c)
45255 this.emitControlWord();
45256 this.parserState = this.parseText;
45257 } else if (/^[-\d]$/.test(c)) {
45258 this.parserState = this.parseControlWordParam;
45259 this.controlWordParam += c;
45260 } else if (/^[A-Za-z]$/.test(c)) {
45261 this.controlWord += c;
45263 this.emitControlWord();
45264 this.parserState = this.parseText;
45268 parseControlWordParam : function (c) {
45269 if (/^\d$/.test(c)) {
45270 this.controlWordParam += c;
45271 } else if (c === ' ') {
45272 this.emitControlWord();
45273 this.parserState = this.parseText;
45275 this.emitControlWord();
45276 this.parserState = this.parseText;
45284 emitText : function () {
45285 if (this.text === '') {
45297 emitControlWord : function ()
45300 if (this.controlWord === '') {
45301 this.emitError('empty control word');
45304 type: 'controlword',
45305 value: this.controlWord,
45306 param: this.controlWordParam !== '' && Number(this.controlWordParam),
45312 this.controlWord = '';
45313 this.controlWordParam = '';
45315 emitStartGroup : function ()
45319 type: 'groupstart',
45325 emitEndGroup : function ()
45335 emitIgnorable : function ()
45345 emitHexChar : function ()
45350 value: this.hexChar,
45357 emitError : function (message)
45365 char: this.cpos //,
45366 //stack: new Error().stack
45369 emitEndParagraph : function () {
45372 type: 'endparagraph',
45380 Roo.htmleditor = {};
45383 * @class Roo.htmleditor.Filter
45384 * Base Class for filtering htmleditor stuff. - do not use this directly - extend it.
45385 * @cfg {DomElement} node The node to iterate and filter
45386 * @cfg {boolean|String|Array} tag Tags to replace
45388 * Create a new Filter.
45389 * @param {Object} config Configuration options
45394 Roo.htmleditor.Filter = function(cfg) {
45395 Roo.apply(this.cfg);
45396 // this does not actually call walk as it's really just a abstract class
45400 Roo.htmleditor.Filter.prototype = {
45406 // overrride to do replace comments.
45407 replaceComment : false,
45409 // overrride to do replace or do stuff with tags..
45410 replaceTag : false,
45412 walk : function(dom)
45414 Roo.each( Array.from(dom.childNodes), function( e ) {
45417 case e.nodeType == 8 && typeof(this.replaceComment) != 'undefined': // comment
45418 this.replaceComment(e);
45421 case e.nodeType != 1: //not a node.
45424 case this.tag === true: // everything
45425 case typeof(this.tag) == 'object' && this.tag.indexOf(e.tagName) > -1: // array and it matches.
45426 case typeof(this.tag) == 'string' && this.tag == e.tagName: // array and it matches.
45427 if (this.replaceTag && false === this.replaceTag(e)) {
45430 if (e.hasChildNodes()) {
45435 default: // tags .. that do not match.
45436 if (e.hasChildNodes()) {
45447 * @class Roo.htmleditor.FilterAttributes
45448 * clean attributes and styles including http:// etc.. in attribute
45450 * Run a new Attribute Filter
45451 * @param {Object} config Configuration options
45453 Roo.htmleditor.FilterAttributes = function(cfg)
45455 Roo.apply(this, cfg);
45456 this.attrib_black = this.attrib_black || [];
45457 this.attrib_white = this.attrib_white || [];
45459 this.attrib_clean = this.attrib_clean || [];
45460 this.style_white = this.style_white || [];
45461 this.style_black = this.style_black || [];
45462 this.walk(cfg.node);
45465 Roo.extend(Roo.htmleditor.FilterAttributes, Roo.htmleditor.Filter,
45467 tag: true, // all tags
45469 attrib_black : false, // array
45470 attrib_clean : false,
45471 attrib_white : false,
45473 style_white : false,
45474 style_black : false,
45477 replaceTag : function(node)
45479 if (!node.attributes || !node.attributes.length) {
45483 for (var i = node.attributes.length-1; i > -1 ; i--) {
45484 var a = node.attributes[i];
45486 if (this.attrib_white.length && this.attrib_white.indexOf(a.name.toLowerCase()) < 0) {
45487 node.removeAttribute(a.name);
45493 if (a.name.toLowerCase().substr(0,2)=='on') {
45494 node.removeAttribute(a.name);
45499 if (this.attrib_black.indexOf(a.name.toLowerCase()) > -1) {
45500 node.removeAttribute(a.name);
45503 if (this.attrib_clean.indexOf(a.name.toLowerCase()) > -1) {
45504 this.cleanAttr(node,a.name,a.value); // fixme..
45507 if (a.name == 'style') {
45508 this.cleanStyle(node,a.name,a.value);
45511 /// clean up MS crap..
45512 // tecnically this should be a list of valid class'es..
45515 if (a.name == 'class') {
45516 if (a.value.match(/^Mso/)) {
45517 node.removeAttribute('class');
45520 if (a.value.match(/^body$/)) {
45521 node.removeAttribute('class');
45531 return true; // clean children
45534 cleanAttr: function(node, n,v)
45537 if (v.match(/^\./) || v.match(/^\//)) {
45540 if (v.match(/^(http|https):\/\//)
45541 || v.match(/^mailto:/)
45542 || v.match(/^ftp:/)
45543 || v.match(/^data:/)
45547 if (v.match(/^#/)) {
45550 if (v.match(/^\{/)) { // allow template editing.
45553 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
45554 node.removeAttribute(n);
45557 cleanStyle : function(node, n,v)
45559 if (v.match(/expression/)) { //XSS?? should we even bother..
45560 node.removeAttribute(n);
45564 var parts = v.split(/;/);
45567 Roo.each(parts, function(p) {
45568 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
45572 var l = p.split(':').shift().replace(/\s+/g,'');
45573 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
45575 if ( this.style_black.length && (this.style_black.indexOf(l) > -1 || this.style_black.indexOf(l.toLowerCase()) > -1)) {
45579 // only allow 'c whitelisted system attributes'
45580 if ( this.style_white.length && style_white.indexOf(l) < 0 && style_white.indexOf(l.toLowerCase()) < 0 ) {
45588 if (clean.length) {
45589 node.setAttribute(n, clean.join(';'));
45591 node.removeAttribute(n);
45600 * @class Roo.htmleditor.FilterBlack
45601 * remove blacklisted elements.
45603 * Run a new Blacklisted Filter
45604 * @param {Object} config Configuration options
45607 Roo.htmleditor.FilterBlack = function(cfg)
45609 Roo.apply(this, cfg);
45610 this.walk(cfg.node);
45613 Roo.extend(Roo.htmleditor.FilterBlack, Roo.htmleditor.Filter,
45615 tag : true, // all elements.
45617 replace : function(n)
45619 n.parentNode.removeChild(n);
45623 * @class Roo.htmleditor.FilterComment
45626 * Run a new Comments Filter
45627 * @param {Object} config Configuration options
45629 Roo.htmleditor.FilterComment = function(cfg)
45631 this.walk(cfg.node);
45634 Roo.extend(Roo.htmleditor.FilterComment, Roo.htmleditor.Filter,
45637 replaceComment : function(n)
45639 n.parentNode.removeChild(n);
45642 * @class Roo.htmleditor.FilterKeepChildren
45643 * remove tags but keep children
45645 * Run a new Keep Children Filter
45646 * @param {Object} config Configuration options
45649 Roo.htmleditor.FilterKeepChildren = function(cfg)
45651 Roo.apply(this, cfg);
45652 if (this.tag === false) {
45653 return; // dont walk.. (you can use this to use this just to do a child removal on a single tag )
45655 this.walk(cfg.node);
45658 Roo.extend(Roo.htmleditor.FilterKeepChildren, Roo.htmleditor.FilterBlack,
45662 replaceTag : function(node)
45664 // walk children...
45666 var ar = Array.from(node.childNodes);
45668 for (var i = 0; i < ar.length; i++) {
45669 if (ar[i].nodeType == 1) {
45671 (typeof(this.tag) == 'object' && this.tag.indexOf(ar[i].tagName) > -1)
45672 || // array and it matches
45673 (typeof(this.tag) == 'string' && this.tag == ar[i].tagName)
45675 this.replaceTag(ar[i]); // child is blacklisted as well...
45680 ar = Array.from(node.childNodes);
45681 for (var i = 0; i < ar.length; i++) {
45683 node.removeChild(ar[i]);
45684 // what if we need to walk these???
45685 node.parentNode.insertBefore(ar[i], node);
45686 if (this.tag !== false) {
45691 node.parentNode.removeChild(node);
45692 return false; // don't walk children
45697 * @class Roo.htmleditor.FilterParagraph
45698 * paragraphs cause a nightmare for shared content - this filter is designed to be called ? at various points when editing
45699 * like on 'push' to remove the <p> tags and replace them with line breaks.
45701 * Run a new Paragraph Filter
45702 * @param {Object} config Configuration options
45705 Roo.htmleditor.FilterParagraph = function(cfg)
45707 // no need to apply config.
45708 this.walk(cfg.node);
45711 Roo.extend(Roo.htmleditor.FilterParagraph, Roo.htmleditor.Filter,
45718 replaceTag : function(node)
45721 if (node.childNodes.length == 1 &&
45722 node.childNodes[0].nodeType == 3 &&
45723 node.childNodes[0].textContent.trim().length < 1
45725 // remove and replace with '<BR>';
45726 node.parentNode.replaceChild(node.ownerDocument.createElement('BR'),node);
45727 return false; // no need to walk..
45729 var ar = Array.from(node.childNodes);
45730 for (var i = 0; i < ar.length; i++) {
45731 node.removeChild(ar[i]);
45732 // what if we need to walk these???
45733 node.parentNode.insertBefore(ar[i], node);
45735 // now what about this?
45739 node.parentNode.insertBefore(node.ownerDocument.createElement('BR'), node);
45740 node.parentNode.insertBefore(node.ownerDocument.createElement('BR'), node);
45741 node.parentNode.removeChild(node);
45748 * @class Roo.htmleditor.FilterSpan
45749 * filter span's with no attributes out..
45751 * Run a new Span Filter
45752 * @param {Object} config Configuration options
45755 Roo.htmleditor.FilterSpan = function(cfg)
45757 // no need to apply config.
45758 this.walk(cfg.node);
45761 Roo.extend(Roo.htmleditor.FilterSpan, Roo.htmleditor.FilterKeepChildren,
45767 replaceTag : function(node)
45769 if (node.attributes && node.attributes.length > 0) {
45770 return true; // walk if there are any.
45772 Roo.htmleditor.FilterKeepChildren.prototype.replaceTag.call(this, node);
45778 * @class Roo.htmleditor.FilterTableWidth
45779 try and remove table width data - as that frequently messes up other stuff.
45781 * was cleanTableWidths.
45783 * Quite often pasting from word etc.. results in tables with column and widths.
45784 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
45787 * Run a new Table Filter
45788 * @param {Object} config Configuration options
45791 Roo.htmleditor.FilterTableWidth = function(cfg)
45793 // no need to apply config.
45794 this.tag = ['TABLE', 'TD', 'TR', 'TH', 'THEAD', 'TBODY' ];
45795 this.walk(cfg.node);
45798 Roo.extend(Roo.htmleditor.FilterTableWidth, Roo.htmleditor.Filter,
45803 replaceTag: function(node) {
45807 if (node.hasAttribute('width')) {
45808 node.removeAttribute('width');
45812 if (node.hasAttribute("style")) {
45815 var styles = node.getAttribute("style").split(";");
45817 Roo.each(styles, function(s) {
45818 if (!s.match(/:/)) {
45821 var kv = s.split(":");
45822 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
45825 // what ever is left... we allow.
45828 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
45829 if (!nstyle.length) {
45830 node.removeAttribute('style');
45834 return true; // continue doing children..
45837 * @class Roo.htmleditor.FilterWord
45838 * try and clean up all the mess that Word generates.
45840 * This is the 'nice version' - see 'Heavy' that white lists a very short list of elements, and multi-filters
45843 * Run a new Span Filter
45844 * @param {Object} config Configuration options
45847 Roo.htmleditor.FilterWord = function(cfg)
45849 // no need to apply config.
45850 this.walk(cfg.node);
45853 Roo.extend(Roo.htmleditor.FilterWord, Roo.htmleditor.Filter,
45859 * Clean up MS wordisms...
45861 replaceTag : function(node)
45864 // no idea what this does - span with text, replaceds with just text.
45866 node.nodeName == 'SPAN' &&
45867 !node.hasAttributes() &&
45868 node.childNodes.length == 1 &&
45869 node.firstChild.nodeName == "#text"
45871 var textNode = node.firstChild;
45872 node.removeChild(textNode);
45873 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
45874 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
45876 node.parentNode.insertBefore(textNode, node);
45877 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
45878 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
45881 node.parentNode.removeChild(node);
45882 return false; // dont do chidren - we have remove our node - so no need to do chdhilren?
45887 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
45888 node.parentNode.removeChild(node);
45889 return false; // dont do chidlren
45891 //Roo.log(node.tagName);
45892 // remove - but keep children..
45893 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
45894 //Roo.log('-- removed');
45895 while (node.childNodes.length) {
45896 var cn = node.childNodes[0];
45897 node.removeChild(cn);
45898 node.parentNode.insertBefore(cn, node);
45899 // move node to parent - and clean it..
45900 this.replaceTag(cn);
45902 node.parentNode.removeChild(node);
45903 /// no need to iterate chidlren = it's got none..
45904 //this.iterateChildren(node, this.cleanWord);
45905 return false; // no need to iterate children.
45908 if (node.className.length) {
45910 var cn = node.className.split(/\W+/);
45912 Roo.each(cn, function(cls) {
45913 if (cls.match(/Mso[a-zA-Z]+/)) {
45918 node.className = cna.length ? cna.join(' ') : '';
45920 node.removeAttribute("class");
45924 if (node.hasAttribute("lang")) {
45925 node.removeAttribute("lang");
45928 if (node.hasAttribute("style")) {
45930 var styles = node.getAttribute("style").split(";");
45932 Roo.each(styles, function(s) {
45933 if (!s.match(/:/)) {
45936 var kv = s.split(":");
45937 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
45940 // what ever is left... we allow.
45943 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
45944 if (!nstyle.length) {
45945 node.removeAttribute('style');
45948 return true; // do children
45955 * @class Roo.htmleditor.FilterStyleToTag
45956 * part of the word stuff... - certain 'styles' should be converted to tags.
45958 * font-weight: bold -> bold
45959 * ?? super / subscrit etc..
45962 * Run a new style to tag filter.
45963 * @param {Object} config Configuration options
45965 Roo.htmleditor.FilterStyleToTag = function(cfg)
45969 B : [ 'fontWeight' , 'bold'],
45970 I : [ 'fontStyle' , 'italic'],
45971 //pre : [ 'font-style' , 'italic'],
45972 // h1.. h6 ?? font-size?
45973 SUP : [ 'verticalAlign' , 'super' ],
45974 SUB : [ 'verticalAlign' , 'sub' ]
45979 Roo.apply(this, cfg);
45982 this.walk(cfg.node);
45989 Roo.extend(Roo.htmleditor.FilterStyleToTag, Roo.htmleditor.Filter,
45991 tag: true, // all tags
45996 replaceTag : function(node)
46000 if (node.getAttribute("style") === null) {
46004 for (var k in this.tags) {
46005 if (node.style[this.tags[k][0]] == this.tags[k][1]) {
46007 node.style.removeProperty(this.tags[k][0]);
46010 if (!inject.length) {
46013 var cn = Array.from(node.childNodes);
46015 Roo.each(inject, function(t) {
46016 var nc = node.ownerDocument.createelement(t);
46017 nn.appendChild(nc);
46020 for(var i = 0;i < cn.length;cn++) {
46021 node.removeChild(cn[i]);
46022 nn.appendChild(cn[i]);
46024 return true /// iterate thru
46028 * @class Roo.htmleditor.FilterLongBr
46029 * BR/BR/BR - keep a maximum of 2...
46031 * Run a new Long BR Filter
46032 * @param {Object} config Configuration options
46035 Roo.htmleditor.FilterLongBr = function(cfg)
46037 // no need to apply config.
46038 this.walk(cfg.node);
46041 Roo.extend(Roo.htmleditor.FilterLongBr, Roo.htmleditor.Filter,
46048 replaceTag : function(node)
46051 var ps = node.nextSibling;
46052 while (ps && ps.nodeType == 3 && ps.nodeValue.trim().length < 1) {
46053 ps = ps.nextSibling;
46056 if (!ps && [ 'TD', 'TH', 'LI', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6' ].indexOf(node.parentNode.tagName) > -1) {
46057 node.parentNode.removeChild(node); // remove last BR inside one fo these tags
46061 if (!ps || ps.nodeType != 1) {
46065 if (!ps || ps.tagName != 'BR') {
46074 if (!node.previousSibling) {
46077 var ps = node.previousSibling;
46079 while (ps && ps.nodeType == 3 && ps.nodeValue.trim().length < 1) {
46080 ps = ps.previousSibling;
46082 if (!ps || ps.nodeType != 1) {
46085 // if header or BR before.. then it's a candidate for removal.. - as we only want '2' of these..
46086 if (!ps || [ 'BR', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6' ].indexOf(ps.tagName) < 0) {
46090 node.parentNode.removeChild(node); // remove me...
46092 return false; // no need to do children
46098 * @class Roo.htmleditor.Tidy
46100 * @cfg {Roo.HtmlEditorCore} core the editor.
46102 * Create a new Filter.
46103 * @param {Object} config Configuration options
46107 Roo.htmleditor.Tidy = function(cfg) {
46108 Roo.apply(this, cfg);
46110 this.core.doc.body.innerHTML = this.tidy(this.core.doc.body, '');
46114 Roo.htmleditor.Tidy.toString = function(node)
46116 return Roo.htmleditor.Tidy.prototype.tidy(node, '');
46119 Roo.htmleditor.Tidy.prototype = {
46122 wrap : function(s) {
46123 return s.replace(/\n/g, " ").replace(/(?![^\n]{1,80}$)([^\n]{1,80})\s/g, '$1\n');
46127 tidy : function(node, indent) {
46129 if (node.nodeType == 3) {
46133 return indent === false ? node.nodeValue : this.wrap(node.nodeValue.trim()).split("\n").join("\n" + indent);
46138 if (node.nodeType != 1) {
46144 if (node.tagName == 'BODY') {
46146 return this.cn(node, '');
46149 // Prints the node tagName, such as <A>, <IMG>, etc
46150 var ret = "<" + node.tagName + this.attr(node) ;
46152 // elements with no children..
46153 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(node.tagName) > -1) {
46159 var cindent = indent === false ? '' : (indent + ' ');
46160 // tags where we will not pad the children.. (inline text tags etc..)
46161 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN', 'B', 'I', 'S'].indexOf(node.tagName) > -1) { // or code?
46167 var cn = this.cn(node, cindent );
46169 return ret + cn + '</' + node.tagName + '>';
46172 cn: function(node, indent)
46176 var ar = Array.from(node.childNodes);
46177 for (var i = 0 ; i < ar.length ; i++) {
46181 if (indent !== false // indent==false preservies everything
46183 && ar[i].nodeType == 3
46184 && ar[i].nodeValue.length > 0
46185 && ar[i].nodeValue.match(/^\s+/)
46187 if (ret.length && ret[ret.length-1] == "\n" + indent) {
46188 ret.pop(); // remove line break from last?
46191 ret.push(" "); // add a space if i'm a text item with a space at the front, as tidy will strip spaces.
46193 if (indent !== false
46194 && ar[i].nodeType == 1 // element - and indent is not set...
46196 ret.push("\n" + indent);
46199 ret.push(this.tidy(ar[i], indent));
46200 // text + trailing indent
46201 if (indent !== false
46202 && ar[i].nodeType == 3
46203 && ar[i].nodeValue.length > 0
46204 && ar[i].nodeValue.match(/\s+$/)
46206 ret.push("\n" + indent);
46213 // what if all text?
46216 return ret.join('');
46221 attr : function(node)
46224 for(i = 0; i < node.attributes.length;i++) {
46226 // skip empty values?
46227 if (!node.attributes.item(i).value.length) {
46230 attr.push( node.attributes.item(i).name + '="' +
46231 Roo.util.Format.htmlEncode(node.attributes.item(i).value) + '"'
46234 return attr.length ? (' ' + attr.join(' ') ) : '';
46242 * @class Roo.htmleditor.KeyEnter
46243 * Handle Enter press..
46244 * @cfg {Roo.HtmlEditorCore} core the editor.
46246 * Create a new Filter.
46247 * @param {Object} config Configuration options
46252 Roo.htmleditor.KeyEnter = function(cfg) {
46253 Roo.apply(this, cfg);
46254 // this does not actually call walk as it's really just a abstract class
46256 Roo.get(this.core.doc.body).on('keypress', this.keypress, this);
46260 Roo.htmleditor.KeyEnter.prototype = {
46264 keypress : function(e)
46266 if (e.charCode != 13) {
46269 e.preventDefault();
46270 // https://stackoverflow.com/questions/18552336/prevent-contenteditable-adding-div-on-enter-chrome
46271 var doc = this.core.doc;
46273 var docFragment = doc.createDocumentFragment();
46276 var newEle = doc.createTextNode('\n');
46277 docFragment.appendChild(newEle);
46280 var range = this.core.win.getSelection().getRangeAt(0);
46281 var n = range.commonAncestorContainer ;
46282 while (n && n.nodeType != 1) {
46286 if (n && n.tagName == 'UL') {
46287 li = doc.createElement('LI');
46291 if (n && n.tagName == 'LI') {
46292 li = doc.createElement('LI');
46293 if (n.nextSibling) {
46294 n.parentNode.insertBefore(li, n.firstSibling);
46297 n.parentNode.appendChild(li);
46301 range = doc.createRange();
46302 range.setStartAfter(li);
46303 range.collapse(true);
46305 //make the cursor there
46306 var sel = this.core.win.getSelection();
46307 sel.removeAllRanges();
46308 sel.addRange(range);
46313 //add the br, or p, or something else
46314 newEle = doc.createElement('br');
46315 docFragment.appendChild(newEle);
46317 //make the br replace selection
46319 range.deleteContents();
46321 range.insertNode(docFragment);
46322 range = range.cloneRange();
46323 range.collapse(true);
46324 var sel = this.core.win.getSelection();
46325 sel.removeAllRanges();
46326 sel.addRange(range);
46327 sel.collapseToEnd();
46335 * @class Roo.htmleditor.Block
46336 * Base class for html editor blocks - do not use it directly .. extend it..
46337 * @cfg {DomElement} node The node to apply stuff to.
46338 * @cfg {String} friendly_name the name that appears in the context bar about this block
46339 * @cfg {Object} Context menu - see Roo.form.HtmlEditor.ToolbarContext
46342 * Create a new Filter.
46343 * @param {Object} config Configuration options
46346 Roo.htmleditor.Block = function(cfg)
46348 // do nothing .. should not be called really.
46351 Roo.htmleditor.Block.factory = function(node)
46354 var id = Roo.get(node).id;
46355 if (typeof(Roo.htmleditor.Block.cache[id]) != 'undefined') {
46356 Roo.htmleditor.Block.cache[id].readElement();
46357 return Roo.htmleditor.Block.cache[id];
46360 var cls = Roo.htmleditor['Block' + node.getAttribute('data-block')];
46361 if (typeof(cls) == 'undefined') {
46362 Roo.log("OOps missing block : " + 'Block' + node.getAttribute('data-block'));
46365 Roo.htmleditor.Block.cache[id] = new cls({ node: node });
46366 return Roo.htmleditor.Block.cache[id]; /// should trigger update element
46368 // question goes here... do we need to clear out this cache sometimes?
46369 // or show we make it relivant to the htmleditor.
46370 Roo.htmleditor.Block.cache = {};
46372 Roo.htmleditor.Block.prototype = {
46376 // used by context menu
46377 friendly_name : 'Image with caption',
46381 * Update a node with values from this object
46382 * @param {DomElement} node
46384 updateElement : function(node)
46386 Roo.DomHelper.update(node === undefined ? this.node : node, this.toObject());
46389 * convert to plain HTML for calling insertAtCursor..
46391 toHTML : function()
46393 return Roo.DomHelper.markup(this.toObject());
46396 * used by readEleemnt to extract data from a node
46397 * may need improving as it's pretty basic
46399 * @param {DomElement} node
46400 * @param {String} tag - tag to find, eg. IMG ?? might be better to use DomQuery ?
46401 * @param {String} attribute (use html - for contents, or style for using next param as style)
46402 * @param {String} style the style property - eg. text-align
46404 getVal : function(node, tag, attr, style)
46407 if (tag !== true && n.tagName != tag.toUpperCase()) {
46408 // in theory we could do figure[3] << 3rd figure? or some more complex search..?
46409 // but kiss for now.
46410 n = node.getElementsByTagName(tag).item(0);
46412 if (attr == 'html') {
46413 return n.innerHTML;
46415 if (attr == 'style') {
46416 return n.style[style]
46419 return Roo.get(n).attr(attr);
46423 * create a DomHelper friendly object - for use with
46424 * Roo.DomHelper.markup / overwrite / etc..
46427 toObject : function()
46432 * Read a node that has a 'data-block' property - and extract the values from it.
46433 * @param {DomElement} node - the node
46435 readElement : function(node)
46446 * @class Roo.htmleditor.BlockFigure
46447 * Block that has an image and a figcaption
46448 * @cfg {String} image_src the url for the image
46449 * @cfg {String} align (left|right) alignment for the block default left
46450 * @cfg {String} text_align (left|right) alignment for the text caption default left.
46451 * @cfg {String} caption the text to appear below (and in the alt tag)
46452 * @cfg {String|number} image_width the width of the image number or %?
46453 * @cfg {String|number} image_height the height of the image number or %?
46456 * Create a new Filter.
46457 * @param {Object} config Configuration options
46460 Roo.htmleditor.BlockFigure = function(cfg)
46463 this.readElement(cfg.node);
46464 this.updateElement(cfg.node);
46466 Roo.apply(this, cfg);
46468 Roo.extend(Roo.htmleditor.BlockFigure, Roo.htmleditor.Block, {
46476 text_align: 'left',
46481 // used by context menu
46482 friendly_name : 'Image with caption',
46484 context : { // ?? static really
46497 opts : [[ "left"],[ "right"]],
46502 title: "Caption Align",
46503 opts : [ [ "left"],[ "right"],[ "center"]],
46514 * create a DomHelper friendly object - for use with
46515 * Roo.DomHelper.markup / overwrite / etc..
46517 toObject : function()
46519 var d = document.createElement('div');
46520 d.innerHTML = this.caption;
46524 'data-block' : 'Figure',
46525 contenteditable : 'false',
46528 float : this.align ,
46529 width : this.width,
46530 margin: this.margin
46535 src : this.image_src,
46536 alt : d.innerText.replace(/\n/g, " "), // removeHTML..
46543 contenteditable : true,
46545 'text-align': this.text_align
46547 html : this.caption
46554 readElement : function(node)
46556 this.image_src = this.getVal(node, 'img', 'src');
46557 this.align = this.getVal(node, 'figure', 'style', 'float');
46558 this.caption = this.getVal(node, 'figcaption', 'html');
46559 this.text_align = this.getVal(node, 'figcaption', 'style','text-align');
46560 this.width = this.getVal(node, 'figure', 'style', 'width');
46561 this.margin = this.getVal(node, 'figure', 'style', 'margin');
46574 //<script type="text/javascript">
46577 * Based Ext JS Library 1.1.1
46578 * Copyright(c) 2006-2007, Ext JS, LLC.
46584 * @class Roo.HtmlEditorCore
46585 * @extends Roo.Component
46586 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
46588 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
46591 Roo.HtmlEditorCore = function(config){
46594 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
46599 * @event initialize
46600 * Fires when the editor is fully initialized (including the iframe)
46601 * @param {Roo.HtmlEditorCore} this
46606 * Fires when the editor is first receives the focus. Any insertion must wait
46607 * until after this event.
46608 * @param {Roo.HtmlEditorCore} this
46612 * @event beforesync
46613 * Fires before the textarea is updated with content from the editor iframe. Return false
46614 * to cancel the sync.
46615 * @param {Roo.HtmlEditorCore} this
46616 * @param {String} html
46620 * @event beforepush
46621 * Fires before the iframe editor is updated with content from the textarea. Return false
46622 * to cancel the push.
46623 * @param {Roo.HtmlEditorCore} this
46624 * @param {String} html
46629 * Fires when the textarea is updated with content from the editor iframe.
46630 * @param {Roo.HtmlEditorCore} this
46631 * @param {String} html
46636 * Fires when the iframe editor is updated with content from the textarea.
46637 * @param {Roo.HtmlEditorCore} this
46638 * @param {String} html
46643 * @event editorevent
46644 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
46645 * @param {Roo.HtmlEditorCore} this
46651 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
46653 // defaults : white / black...
46654 this.applyBlacklists();
46661 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
46665 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
46671 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
46676 * @cfg {Number} height (in pixels)
46680 * @cfg {Number} width (in pixels)
46685 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
46688 stylesheets: false,
46691 * @cfg {boolean} allowComments - default false - allow comments in HTML source - by default they are stripped - if you are editing email you may need this.
46693 allowComments: false,
46697 // private properties
46698 validationEvent : false,
46700 initialized : false,
46702 sourceEditMode : false,
46703 onFocus : Roo.emptyFn,
46705 hideMode:'offsets',
46709 // blacklist + whitelisted elements..
46716 undoManager : false,
46718 * Protected method that will not generally be called directly. It
46719 * is called when the editor initializes the iframe with HTML contents. Override this method if you
46720 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
46722 getDocMarkup : function(){
46726 // inherit styels from page...??
46727 if (this.stylesheets === false) {
46729 Roo.get(document.head).select('style').each(function(node) {
46730 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
46733 Roo.get(document.head).select('link').each(function(node) {
46734 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
46737 } else if (!this.stylesheets.length) {
46739 st = '<style type="text/css">' +
46740 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
46743 for (var i in this.stylesheets) {
46744 if (typeof(this.stylesheets[i]) != 'string') {
46747 st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
46752 st += '<style type="text/css">' +
46753 'IMG { cursor: pointer } ' +
46756 var cls = 'roo-htmleditor-body';
46758 if(this.bodyCls.length){
46759 cls += ' ' + this.bodyCls;
46762 return '<html><head>' + st +
46763 //<style type="text/css">' +
46764 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
46766 ' </head><body contenteditable="true" data-enable-grammerly="true" class="' + cls + '"></body></html>';
46770 onRender : function(ct, position)
46773 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
46774 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
46777 this.el.dom.style.border = '0 none';
46778 this.el.dom.setAttribute('tabIndex', -1);
46779 this.el.addClass('x-hidden hide');
46783 if(Roo.isIE){ // fix IE 1px bogus margin
46784 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
46788 this.frameId = Roo.id();
46792 var iframe = this.owner.wrap.createChild({
46794 cls: 'form-control', // bootstrap..
46796 name: this.frameId,
46797 frameBorder : 'no',
46798 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
46803 this.iframe = iframe.dom;
46805 this.assignDocWin();
46807 this.doc.designMode = 'on';
46810 this.doc.write(this.getDocMarkup());
46814 var task = { // must defer to wait for browser to be ready
46816 //console.log("run task?" + this.doc.readyState);
46817 this.assignDocWin();
46818 if(this.doc.body || this.doc.readyState == 'complete'){
46820 this.doc.designMode="on";
46825 Roo.TaskMgr.stop(task);
46826 this.initEditor.defer(10, this);
46833 Roo.TaskMgr.start(task);
46838 onResize : function(w, h)
46840 Roo.log('resize: ' +w + ',' + h );
46841 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
46845 if(typeof w == 'number'){
46847 this.iframe.style.width = w + 'px';
46849 if(typeof h == 'number'){
46851 this.iframe.style.height = h + 'px';
46853 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
46860 * Toggles the editor between standard and source edit mode.
46861 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
46863 toggleSourceEdit : function(sourceEditMode){
46865 this.sourceEditMode = sourceEditMode === true;
46867 if(this.sourceEditMode){
46869 Roo.get(this.iframe).addClass(['x-hidden','hide', 'd-none']); //FIXME - what's the BS styles for these
46872 Roo.get(this.iframe).removeClass(['x-hidden','hide', 'd-none']);
46873 //this.iframe.className = '';
46876 //this.setSize(this.owner.wrap.getSize());
46877 //this.fireEvent('editmodechange', this, this.sourceEditMode);
46884 * Protected method that will not generally be called directly. If you need/want
46885 * custom HTML cleanup, this is the method you should override.
46886 * @param {String} html The HTML to be cleaned
46887 * return {String} The cleaned HTML
46889 cleanHtml : function(html){
46890 html = String(html);
46891 if(html.length > 5){
46892 if(Roo.isSafari){ // strip safari nonsense
46893 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
46896 if(html == ' '){
46903 * HTML Editor -> Textarea
46904 * Protected method that will not generally be called directly. Syncs the contents
46905 * of the editor iframe with the textarea.
46907 syncValue : function()
46909 Roo.log("HtmlEditorCore:syncValue (EDITOR->TEXT)");
46910 if(this.initialized){
46912 this.undoManager.addEvent();
46915 var bd = (this.doc.body || this.doc.documentElement);
46916 //this.cleanUpPaste(); -- this is done else where and causes havoc..
46918 // not sure if this is really the place for this
46919 // the blocks are synced occasionaly - since we currently dont add listeners on the blocks
46920 // this has to update attributes that get duped.. like alt and caption..
46923 //Roo.each(Roo.get(this.doc.body).query('*[data-block]'), function(e) {
46924 // Roo.htmleditor.Block.factory(e);
46928 var div = document.createElement('div');
46929 div.innerHTML = bd.innerHTML;
46930 // remove content editable. (blocks)
46933 new Roo.htmleditor.FilterAttributes({node : div, attrib_black: [ 'contenteditable' ] });
46935 var html = div.innerHTML;
46937 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
46938 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
46940 html = '<div style="'+m[0]+'">' + html + '</div>';
46943 html = this.cleanHtml(html);
46944 // fix up the special chars.. normaly like back quotes in word...
46945 // however we do not want to do this with chinese..
46946 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
46948 var cc = match.charCodeAt();
46950 // Get the character value, handling surrogate pairs
46951 if (match.length == 2) {
46952 // It's a surrogate pair, calculate the Unicode code point
46953 var high = match.charCodeAt(0) - 0xD800;
46954 var low = match.charCodeAt(1) - 0xDC00;
46955 cc = (high * 0x400) + low + 0x10000;
46957 (cc >= 0x4E00 && cc < 0xA000 ) ||
46958 (cc >= 0x3400 && cc < 0x4E00 ) ||
46959 (cc >= 0xf900 && cc < 0xfb00 )
46964 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
46965 return "&#" + cc + ";";
46972 if(this.owner.fireEvent('beforesync', this, html) !== false){
46973 this.el.dom.value = html;
46974 this.owner.fireEvent('sync', this, html);
46980 * TEXTAREA -> EDITABLE
46981 * Protected method that will not generally be called directly. Pushes the value of the textarea
46982 * into the iframe editor.
46984 pushValue : function()
46986 Roo.log("HtmlEditorCore:pushValue (TEXT->EDITOR)");
46987 if(this.initialized){
46988 var v = this.el.dom.value.trim();
46991 if(this.owner.fireEvent('beforepush', this, v) !== false){
46992 var d = (this.doc.body || this.doc.documentElement);
46995 this.el.dom.value = d.innerHTML;
46996 this.owner.fireEvent('push', this, v);
46999 Roo.each(Roo.get(this.doc.body).query('*[data-block]'), function(e) {
47001 Roo.htmleditor.Block.factory(e);
47004 var lc = this.doc.body.lastChild;
47005 if (lc && lc.nodeType == 1 && lc.getAttribute("contenteditable") == "false") {
47006 // add an extra line at the end.
47007 this.doc.body.appendChild(this.doc.createElement('br'));
47015 deferFocus : function(){
47016 this.focus.defer(10, this);
47020 focus : function(){
47021 if(this.win && !this.sourceEditMode){
47028 assignDocWin: function()
47030 var iframe = this.iframe;
47033 this.doc = iframe.contentWindow.document;
47034 this.win = iframe.contentWindow;
47036 // if (!Roo.get(this.frameId)) {
47039 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
47040 // this.win = Roo.get(this.frameId).dom.contentWindow;
47042 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
47046 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
47047 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
47052 initEditor : function(){
47053 //console.log("INIT EDITOR");
47054 this.assignDocWin();
47058 this.doc.designMode="on";
47060 this.doc.write(this.getDocMarkup());
47063 var dbody = (this.doc.body || this.doc.documentElement);
47064 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
47065 // this copies styles from the containing element into thsi one..
47066 // not sure why we need all of this..
47067 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
47069 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
47070 //ss['background-attachment'] = 'fixed'; // w3c
47071 dbody.bgProperties = 'fixed'; // ie
47072 //Roo.DomHelper.applyStyles(dbody, ss);
47073 Roo.EventManager.on(this.doc, {
47074 //'mousedown': this.onEditorEvent,
47075 'mouseup': this.onEditorEvent,
47076 'dblclick': this.onEditorEvent,
47077 'click': this.onEditorEvent,
47078 'keyup': this.onEditorEvent,
47083 Roo.EventManager.on(this.doc, {
47084 'paste': this.onPasteEvent,
47088 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
47090 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
47091 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
47093 this.initialized = true;
47096 // initialize special key events - enter
47097 new Roo.htmleditor.KeyEnter({core : this});
47101 this.owner.fireEvent('initialize', this);
47105 onPasteEvent : function(e,v)
47107 // I think we better assume paste is going to be a dirty load of rubish from word..
47109 // even pasting into a 'email version' of this widget will have to clean up that mess.
47110 var cd = (e.browserEvent.clipboardData || window.clipboardData);
47112 // check what type of paste - if it's an image, then handle it differently.
47113 if (cd.files.length > 0) {
47115 var urlAPI = (window.createObjectURL && window) ||
47116 (window.URL && URL.revokeObjectURL && URL) ||
47117 (window.webkitURL && webkitURL);
47119 var url = urlAPI.createObjectURL( cd.files[0]);
47120 this.insertAtCursor('<img src=" + url + ">');
47124 var html = cd.getData('text/html'); // clipboard event
47125 var parser = new Roo.rtf.Parser(cd.getData('text/rtf'));
47126 var images = parser.doc ? parser.doc.getElementsByType('pict') : [];
47130 images = images.filter(function(g) { return !g.path.match(/^rtf\/(head|pgdsctbl|listtable)/); }) // ignore headers
47131 .map(function(g) { return g.toDataURL(); });
47134 html = this.cleanWordChars(html);
47136 var d = (new DOMParser().parseFromString(html, 'text/html')).body;
47138 if (images.length > 0) {
47139 Roo.each(d.getElementsByTagName('img'), function(img, i) {
47140 img.setAttribute('src', images[i]);
47145 new Roo.htmleditor.FilterStyleToTag({ node : d });
47146 new Roo.htmleditor.FilterAttributes({
47148 attrib_white : ['href', 'src', 'name', 'align'],
47149 attrib_clean : ['href', 'src' ]
47151 new Roo.htmleditor.FilterBlack({ node : d, tag : this.black});
47152 // should be fonts..
47153 new Roo.htmleditor.FilterKeepChildren({node : d, tag : [ 'FONT' ]} );
47154 new Roo.htmleditor.FilterParagraph({ node : d });
47155 new Roo.htmleditor.FilterSpan({ node : d });
47156 new Roo.htmleditor.FilterLongBr({ node : d });
47160 this.insertAtCursor(d.innerHTML);
47162 e.preventDefault();
47164 // default behaveiour should be our local cleanup paste? (optional?)
47165 // for simple editor - we want to hammer the paste and get rid of everything... - so over-rideable..
47166 //this.owner.fireEvent('paste', e, v);
47169 onDestroy : function(){
47175 //for (var i =0; i < this.toolbars.length;i++) {
47176 // // fixme - ask toolbars for heights?
47177 // this.toolbars[i].onDestroy();
47180 //this.wrap.dom.innerHTML = '';
47181 //this.wrap.remove();
47186 onFirstFocus : function(){
47188 this.assignDocWin();
47189 this.undoManager = new Roo.lib.UndoManager(100,(this.doc.body || this.doc.documentElement));
47191 this.activated = true;
47194 if(Roo.isGecko){ // prevent silly gecko errors
47196 var s = this.win.getSelection();
47197 if(!s.focusNode || s.focusNode.nodeType != 3){
47198 var r = s.getRangeAt(0);
47199 r.selectNodeContents((this.doc.body || this.doc.documentElement));
47204 this.execCmd('useCSS', true);
47205 this.execCmd('styleWithCSS', false);
47208 this.owner.fireEvent('activate', this);
47212 adjustFont: function(btn){
47213 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
47214 //if(Roo.isSafari){ // safari
47217 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
47218 if(Roo.isSafari){ // safari
47219 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
47220 v = (v < 10) ? 10 : v;
47221 v = (v > 48) ? 48 : v;
47222 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
47227 v = Math.max(1, v+adjust);
47229 this.execCmd('FontSize', v );
47232 onEditorEvent : function(e)
47234 this.owner.fireEvent('editorevent', this, e);
47235 // this.updateToolbar();
47236 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
47239 insertTag : function(tg)
47241 // could be a bit smarter... -> wrap the current selected tRoo..
47242 if (tg.toLowerCase() == 'span' ||
47243 tg.toLowerCase() == 'code' ||
47244 tg.toLowerCase() == 'sup' ||
47245 tg.toLowerCase() == 'sub'
47248 range = this.createRange(this.getSelection());
47249 var wrappingNode = this.doc.createElement(tg.toLowerCase());
47250 wrappingNode.appendChild(range.extractContents());
47251 range.insertNode(wrappingNode);
47258 this.execCmd("formatblock", tg);
47259 this.undoManager.addEvent();
47262 insertText : function(txt)
47266 var range = this.createRange();
47267 range.deleteContents();
47268 //alert(Sender.getAttribute('label'));
47270 range.insertNode(this.doc.createTextNode(txt));
47271 this.undoManager.addEvent();
47277 * Executes a Midas editor command on the editor document and performs necessary focus and
47278 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
47279 * @param {String} cmd The Midas command
47280 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
47282 relayCmd : function(cmd, value){
47284 this.execCmd(cmd, value);
47285 this.owner.fireEvent('editorevent', this);
47286 //this.updateToolbar();
47287 this.owner.deferFocus();
47291 * Executes a Midas editor command directly on the editor document.
47292 * For visual commands, you should use {@link #relayCmd} instead.
47293 * <b>This should only be called after the editor is initialized.</b>
47294 * @param {String} cmd The Midas command
47295 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
47297 execCmd : function(cmd, value){
47298 this.doc.execCommand(cmd, false, value === undefined ? null : value);
47305 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
47307 * @param {String} text | dom node..
47309 insertAtCursor : function(text)
47312 if(!this.activated){
47316 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
47320 // from jquery ui (MIT licenced)
47322 var win = this.win;
47324 if (win.getSelection && win.getSelection().getRangeAt) {
47326 // delete the existing?
47328 this.createRange(this.getSelection()).deleteContents();
47329 range = win.getSelection().getRangeAt(0);
47330 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
47331 range.insertNode(node);
47332 range = range.cloneRange();
47333 range.collapse(false);
47335 win.getSelection().removeAllRanges();
47336 win.getSelection().addRange(range);
47340 } else if (win.document.selection && win.document.selection.createRange) {
47341 // no firefox support
47342 var txt = typeof(text) == 'string' ? text : text.outerHTML;
47343 win.document.selection.createRange().pasteHTML(txt);
47346 // no firefox support
47347 var txt = typeof(text) == 'string' ? text : text.outerHTML;
47348 this.execCmd('InsertHTML', txt);
47356 mozKeyPress : function(e){
47358 var c = e.getCharCode(), cmd;
47361 c = String.fromCharCode(c).toLowerCase();
47375 // this.cleanUpPaste.defer(100, this);
47383 e.preventDefault();
47391 fixKeys : function(){ // load time branching for fastest keydown performance
47393 return function(e){
47394 var k = e.getKey(), r;
47397 r = this.doc.selection.createRange();
47400 r.pasteHTML('    ');
47407 r = this.doc.selection.createRange();
47409 var target = r.parentElement();
47410 if(!target || target.tagName.toLowerCase() != 'li'){
47412 r.pasteHTML('<br/>');
47418 //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
47419 // this.cleanUpPaste.defer(100, this);
47425 }else if(Roo.isOpera){
47426 return function(e){
47427 var k = e.getKey();
47431 this.execCmd('InsertHTML','    ');
47434 //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
47435 // this.cleanUpPaste.defer(100, this);
47440 }else if(Roo.isSafari){
47441 return function(e){
47442 var k = e.getKey();
47446 this.execCmd('InsertText','\t');
47450 //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
47451 // this.cleanUpPaste.defer(100, this);
47459 getAllAncestors: function()
47461 var p = this.getSelectedNode();
47464 a.push(p); // push blank onto stack..
47465 p = this.getParentElement();
47469 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
47473 a.push(this.doc.body);
47477 lastSelNode : false,
47480 getSelection : function()
47482 this.assignDocWin();
47483 return Roo.isIE ? this.doc.selection : this.win.getSelection();
47486 * Select a dom node
47487 * @param {DomElement} node the node to select
47489 selectNode : function(node)
47491 var nodeRange = node.ownerDocument.createRange();
47493 nodeRange.selectNode(node);
47495 nodeRange.selectNodeContents(node);
47497 //nodeRange.collapse(true);
47498 var s = this.win.getSelection();
47499 s.removeAllRanges();
47500 s.addRange(nodeRange);
47503 getSelectedNode: function()
47505 // this may only work on Gecko!!!
47507 // should we cache this!!!!
47512 var range = this.createRange(this.getSelection()).cloneRange();
47515 var parent = range.parentElement();
47517 var testRange = range.duplicate();
47518 testRange.moveToElementText(parent);
47519 if (testRange.inRange(range)) {
47522 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
47525 parent = parent.parentElement;
47530 // is ancestor a text element.
47531 var ac = range.commonAncestorContainer;
47532 if (ac.nodeType == 3) {
47533 ac = ac.parentNode;
47536 var ar = ac.childNodes;
47539 var other_nodes = [];
47540 var has_other_nodes = false;
47541 for (var i=0;i<ar.length;i++) {
47542 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
47545 // fullly contained node.
47547 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
47552 // probably selected..
47553 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
47554 other_nodes.push(ar[i]);
47558 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
47563 has_other_nodes = true;
47565 if (!nodes.length && other_nodes.length) {
47566 nodes= other_nodes;
47568 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
47574 createRange: function(sel)
47576 // this has strange effects when using with
47577 // top toolbar - not sure if it's a great idea.
47578 //this.editor.contentWindow.focus();
47579 if (typeof sel != "undefined") {
47581 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
47583 return this.doc.createRange();
47586 return this.doc.createRange();
47589 getParentElement: function()
47592 this.assignDocWin();
47593 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
47595 var range = this.createRange(sel);
47598 var p = range.commonAncestorContainer;
47599 while (p.nodeType == 3) { // text node
47610 * Range intersection.. the hard stuff...
47614 * [ -- selected range --- ]
47618 * if end is before start or hits it. fail.
47619 * if start is after end or hits it fail.
47621 * if either hits (but other is outside. - then it's not
47627 // @see http://www.thismuchiknow.co.uk/?p=64.
47628 rangeIntersectsNode : function(range, node)
47630 var nodeRange = node.ownerDocument.createRange();
47632 nodeRange.selectNode(node);
47634 nodeRange.selectNodeContents(node);
47637 var rangeStartRange = range.cloneRange();
47638 rangeStartRange.collapse(true);
47640 var rangeEndRange = range.cloneRange();
47641 rangeEndRange.collapse(false);
47643 var nodeStartRange = nodeRange.cloneRange();
47644 nodeStartRange.collapse(true);
47646 var nodeEndRange = nodeRange.cloneRange();
47647 nodeEndRange.collapse(false);
47649 return rangeStartRange.compareBoundaryPoints(
47650 Range.START_TO_START, nodeEndRange) == -1 &&
47651 rangeEndRange.compareBoundaryPoints(
47652 Range.START_TO_START, nodeStartRange) == 1;
47656 rangeCompareNode : function(range, node)
47658 var nodeRange = node.ownerDocument.createRange();
47660 nodeRange.selectNode(node);
47662 nodeRange.selectNodeContents(node);
47666 range.collapse(true);
47668 nodeRange.collapse(true);
47670 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
47671 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
47673 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
47675 var nodeIsBefore = ss == 1;
47676 var nodeIsAfter = ee == -1;
47678 if (nodeIsBefore && nodeIsAfter) {
47681 if (!nodeIsBefore && nodeIsAfter) {
47682 return 1; //right trailed.
47685 if (nodeIsBefore && !nodeIsAfter) {
47686 return 2; // left trailed.
47692 cleanWordChars : function(input) {// change the chars to hex code
47695 [ 8211, "–" ],
47696 [ 8212, "—" ],
47704 var output = input;
47705 Roo.each(swapCodes, function(sw) {
47706 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
47708 output = output.replace(swapper, sw[1]);
47718 cleanUpChild : function (node)
47721 new Roo.htmleditor.FilterComment({node : node});
47722 new Roo.htmleditor.FilterAttributes({
47724 attrib_black : this.ablack,
47725 attrib_clean : this.aclean,
47726 style_white : this.cwhite,
47727 style_black : this.cblack
47729 new Roo.htmleditor.FilterBlack({ node : node, tag : this.black});
47730 new Roo.htmleditor.FilterKeepChildren({node : node, tag : this.tag_remove} );
47736 * Clean up MS wordisms...
47737 * @deprecated - use filter directly
47739 cleanWord : function(node)
47741 new Roo.htmleditor.FilterWord({ node : node ? node : this.doc.body });
47748 * @deprecated - use filters
47750 cleanTableWidths : function(node)
47752 new Roo.htmleditor.FilterTableWidth({ node : node ? node : this.doc.body});
47759 applyBlacklists : function()
47761 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
47762 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
47764 this.aclean = typeof(this.owner.aclean) != 'undefined' && this.owner.aclean ? this.owner.aclean : Roo.HtmlEditorCore.aclean;
47765 this.ablack = typeof(this.owner.ablack) != 'undefined' && this.owner.ablack ? this.owner.ablack : Roo.HtmlEditorCore.ablack;
47766 this.tag_remove = typeof(this.owner.tag_remove) != 'undefined' && this.owner.tag_remove ? this.owner.tag_remove : Roo.HtmlEditorCore.tag_remove;
47770 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
47771 if (b.indexOf(tag) > -1) {
47774 this.white.push(tag);
47778 Roo.each(w, function(tag) {
47779 if (b.indexOf(tag) > -1) {
47782 if (this.white.indexOf(tag) > -1) {
47785 this.white.push(tag);
47790 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
47791 if (w.indexOf(tag) > -1) {
47794 this.black.push(tag);
47798 Roo.each(b, function(tag) {
47799 if (w.indexOf(tag) > -1) {
47802 if (this.black.indexOf(tag) > -1) {
47805 this.black.push(tag);
47810 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
47811 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
47815 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
47816 if (b.indexOf(tag) > -1) {
47819 this.cwhite.push(tag);
47823 Roo.each(w, function(tag) {
47824 if (b.indexOf(tag) > -1) {
47827 if (this.cwhite.indexOf(tag) > -1) {
47830 this.cwhite.push(tag);
47835 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
47836 if (w.indexOf(tag) > -1) {
47839 this.cblack.push(tag);
47843 Roo.each(b, function(tag) {
47844 if (w.indexOf(tag) > -1) {
47847 if (this.cblack.indexOf(tag) > -1) {
47850 this.cblack.push(tag);
47855 setStylesheets : function(stylesheets)
47857 if(typeof(stylesheets) == 'string'){
47858 Roo.get(this.iframe.contentDocument.head).createChild({
47860 rel : 'stylesheet',
47869 Roo.each(stylesheets, function(s) {
47874 Roo.get(_this.iframe.contentDocument.head).createChild({
47876 rel : 'stylesheet',
47885 removeStylesheets : function()
47889 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
47894 setStyle : function(style)
47896 Roo.get(this.iframe.contentDocument.head).createChild({
47905 // hide stuff that is not compatible
47919 * @event specialkey
47923 * @cfg {String} fieldClass @hide
47926 * @cfg {String} focusClass @hide
47929 * @cfg {String} autoCreate @hide
47932 * @cfg {String} inputType @hide
47935 * @cfg {String} invalidClass @hide
47938 * @cfg {String} invalidText @hide
47941 * @cfg {String} msgFx @hide
47944 * @cfg {String} validateOnBlur @hide
47948 Roo.HtmlEditorCore.white = [
47949 'AREA', 'BR', 'IMG', 'INPUT', 'HR', 'WBR',
47951 'ADDRESS', 'BLOCKQUOTE', 'CENTER', 'DD', 'DIR', 'DIV',
47952 'DL', 'DT', 'H1', 'H2', 'H3', 'H4',
47953 'H5', 'H6', 'HR', 'ISINDEX', 'LISTING', 'MARQUEE',
47954 'MENU', 'MULTICOL', 'OL', 'P', 'PLAINTEXT', 'PRE',
47955 'TABLE', 'UL', 'XMP',
47957 'CAPTION', 'COL', 'COLGROUP', 'TBODY', 'TD', 'TFOOT', 'TH',
47960 'DIR', 'MENU', 'OL', 'UL', 'DL',
47966 Roo.HtmlEditorCore.black = [
47967 // 'embed', 'object', // enable - backend responsiblity to clean thiese
47969 'BASE', 'BASEFONT', 'BGSOUND', 'BLINK', 'BODY',
47970 'FRAME', 'FRAMESET', 'HEAD', 'HTML', 'ILAYER',
47971 'IFRAME', 'LAYER', 'LINK', 'META', 'OBJECT',
47972 'SCRIPT', 'STYLE' ,'TITLE', 'XML',
47973 //'FONT' // CLEAN LATER..
47974 'COLGROUP', 'COL' // messy tables.
47977 Roo.HtmlEditorCore.clean = [ // ?? needed???
47978 'SCRIPT', 'STYLE', 'TITLE', 'XML'
47980 Roo.HtmlEditorCore.tag_remove = [
47985 Roo.HtmlEditorCore.ablack = [
47989 Roo.HtmlEditorCore.aclean = [
47990 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
47994 Roo.HtmlEditorCore.pwhite= [
47995 'http', 'https', 'mailto'
47998 // white listed style attributes.
47999 Roo.HtmlEditorCore.cwhite= [
48000 // 'text-align', /// default is to allow most things..
48006 // black listed style attributes.
48007 Roo.HtmlEditorCore.cblack= [
48008 // 'font-size' -- this can be set by the project
48014 //<script type="text/javascript">
48017 * Ext JS Library 1.1.1
48018 * Copyright(c) 2006-2007, Ext JS, LLC.
48024 Roo.form.HtmlEditor = function(config){
48028 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
48030 if (!this.toolbars) {
48031 this.toolbars = [];
48033 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
48039 * @class Roo.form.HtmlEditor
48040 * @extends Roo.form.Field
48041 * Provides a lightweight HTML Editor component.
48043 * This has been tested on Fireforx / Chrome.. IE may not be so great..
48045 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
48046 * supported by this editor.</b><br/><br/>
48047 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
48048 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
48050 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
48052 * @cfg {Boolean} clearUp
48056 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
48061 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
48066 * @cfg {Number} height (in pixels)
48070 * @cfg {Number} width (in pixels)
48075 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets - this is usally a good idea rootURL + '/roojs1/css/undoreset.css', .
48078 stylesheets: false,
48082 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
48087 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
48093 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
48098 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
48103 * @cfg {boolean} allowComments - default false - allow comments in HTML source - by default they are stripped - if you are editing email you may need this.
48105 allowComments: false,
48107 * @cfg {string} bodyCls- default '' default classes to add to body of editable area - usually undoreset is a good start..
48116 // private properties
48117 validationEvent : false,
48119 initialized : false,
48122 onFocus : Roo.emptyFn,
48124 hideMode:'offsets',
48126 actionMode : 'container', // defaults to hiding it...
48128 defaultAutoCreate : { // modified by initCompnoent..
48130 style:"width:500px;height:300px;",
48131 autocomplete: "new-password"
48135 initComponent : function(){
48138 * @event initialize
48139 * Fires when the editor is fully initialized (including the iframe)
48140 * @param {HtmlEditor} this
48145 * Fires when the editor is first receives the focus. Any insertion must wait
48146 * until after this event.
48147 * @param {HtmlEditor} this
48151 * @event beforesync
48152 * Fires before the textarea is updated with content from the editor iframe. Return false
48153 * to cancel the sync.
48154 * @param {HtmlEditor} this
48155 * @param {String} html
48159 * @event beforepush
48160 * Fires before the iframe editor is updated with content from the textarea. Return false
48161 * to cancel the push.
48162 * @param {HtmlEditor} this
48163 * @param {String} html
48168 * Fires when the textarea is updated with content from the editor iframe.
48169 * @param {HtmlEditor} this
48170 * @param {String} html
48175 * Fires when the iframe editor is updated with content from the textarea.
48176 * @param {HtmlEditor} this
48177 * @param {String} html
48181 * @event editmodechange
48182 * Fires when the editor switches edit modes
48183 * @param {HtmlEditor} this
48184 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
48186 editmodechange: true,
48188 * @event editorevent
48189 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
48190 * @param {HtmlEditor} this
48194 * @event firstfocus
48195 * Fires when on first focus - needed by toolbars..
48196 * @param {HtmlEditor} this
48201 * Auto save the htmlEditor value as a file into Events
48202 * @param {HtmlEditor} this
48206 * @event savedpreview
48207 * preview the saved version of htmlEditor
48208 * @param {HtmlEditor} this
48210 savedpreview: true,
48213 * @event stylesheetsclick
48214 * Fires when press the Sytlesheets button
48215 * @param {Roo.HtmlEditorCore} this
48217 stylesheetsclick: true,
48220 * Fires when press user pastes into the editor
48221 * @param {Roo.HtmlEditorCore} this
48225 this.defaultAutoCreate = {
48227 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
48228 autocomplete: "new-password"
48233 * Protected method that will not generally be called directly. It
48234 * is called when the editor creates its toolbar. Override this method if you need to
48235 * add custom toolbar buttons.
48236 * @param {HtmlEditor} editor
48238 createToolbar : function(editor){
48239 Roo.log("create toolbars");
48240 if (!editor.toolbars || !editor.toolbars.length) {
48241 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
48244 for (var i =0 ; i < editor.toolbars.length;i++) {
48245 editor.toolbars[i] = Roo.factory(
48246 typeof(editor.toolbars[i]) == 'string' ?
48247 { xtype: editor.toolbars[i]} : editor.toolbars[i],
48248 Roo.form.HtmlEditor);
48249 editor.toolbars[i].init(editor);
48257 onRender : function(ct, position)
48260 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
48262 this.wrap = this.el.wrap({
48263 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
48266 this.editorcore.onRender(ct, position);
48268 if (this.resizable) {
48269 this.resizeEl = new Roo.Resizable(this.wrap, {
48273 minHeight : this.height,
48274 height: this.height,
48275 handles : this.resizable,
48278 resize : function(r, w, h) {
48279 _t.onResize(w,h); // -something
48285 this.createToolbar(this);
48289 this.setSize(this.wrap.getSize());
48291 if (this.resizeEl) {
48292 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
48293 // should trigger onReize..
48296 this.keyNav = new Roo.KeyNav(this.el, {
48298 "tab" : function(e){
48299 e.preventDefault();
48301 var value = this.getValue();
48303 var start = this.el.dom.selectionStart;
48304 var end = this.el.dom.selectionEnd;
48308 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
48309 this.el.dom.setSelectionRange(end + 1, end + 1);
48313 var f = value.substring(0, start).split("\t");
48315 if(f.pop().length != 0){
48319 this.setValue(f.join("\t") + value.substring(end));
48320 this.el.dom.setSelectionRange(start - 1, start - 1);
48324 "home" : function(e){
48325 e.preventDefault();
48327 var curr = this.el.dom.selectionStart;
48328 var lines = this.getValue().split("\n");
48335 this.el.dom.setSelectionRange(0, 0);
48341 for (var i = 0; i < lines.length;i++) {
48342 pos += lines[i].length;
48352 pos -= lines[i].length;
48358 this.el.dom.setSelectionRange(pos, pos);
48362 this.el.dom.selectionStart = pos;
48363 this.el.dom.selectionEnd = curr;
48366 "end" : function(e){
48367 e.preventDefault();
48369 var curr = this.el.dom.selectionStart;
48370 var lines = this.getValue().split("\n");
48377 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
48383 for (var i = 0; i < lines.length;i++) {
48385 pos += lines[i].length;
48399 this.el.dom.setSelectionRange(pos, pos);
48403 this.el.dom.selectionStart = curr;
48404 this.el.dom.selectionEnd = pos;
48409 doRelay : function(foo, bar, hname){
48410 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
48416 // if(this.autosave && this.w){
48417 // this.autoSaveFn = setInterval(this.autosave, 1000);
48422 onResize : function(w, h)
48424 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
48429 if(typeof w == 'number'){
48430 var aw = w - this.wrap.getFrameWidth('lr');
48431 this.el.setWidth(this.adjustWidth('textarea', aw));
48434 if(typeof h == 'number'){
48436 for (var i =0; i < this.toolbars.length;i++) {
48437 // fixme - ask toolbars for heights?
48438 tbh += this.toolbars[i].tb.el.getHeight();
48439 if (this.toolbars[i].footer) {
48440 tbh += this.toolbars[i].footer.el.getHeight();
48447 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
48448 ah -= 5; // knock a few pixes off for look..
48450 this.el.setHeight(this.adjustWidth('textarea', ah));
48454 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
48455 this.editorcore.onResize(ew,eh);
48460 * Toggles the editor between standard and source edit mode.
48461 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
48463 toggleSourceEdit : function(sourceEditMode)
48465 this.editorcore.toggleSourceEdit(sourceEditMode);
48467 if(this.editorcore.sourceEditMode){
48468 Roo.log('editor - showing textarea');
48471 // Roo.log(this.syncValue());
48472 this.editorcore.syncValue();
48473 this.el.removeClass('x-hidden');
48474 this.el.dom.removeAttribute('tabIndex');
48476 this.el.dom.scrollTop = 0;
48479 for (var i = 0; i < this.toolbars.length; i++) {
48480 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
48481 this.toolbars[i].tb.hide();
48482 this.toolbars[i].footer.hide();
48487 Roo.log('editor - hiding textarea');
48489 // Roo.log(this.pushValue());
48490 this.editorcore.pushValue();
48492 this.el.addClass('x-hidden');
48493 this.el.dom.setAttribute('tabIndex', -1);
48495 for (var i = 0; i < this.toolbars.length; i++) {
48496 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
48497 this.toolbars[i].tb.show();
48498 this.toolbars[i].footer.show();
48502 //this.deferFocus();
48505 this.setSize(this.wrap.getSize());
48506 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
48508 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
48511 // private (for BoxComponent)
48512 adjustSize : Roo.BoxComponent.prototype.adjustSize,
48514 // private (for BoxComponent)
48515 getResizeEl : function(){
48519 // private (for BoxComponent)
48520 getPositionEl : function(){
48525 initEvents : function(){
48526 this.originalValue = this.getValue();
48530 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
48533 markInvalid : Roo.emptyFn,
48535 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
48538 clearInvalid : Roo.emptyFn,
48540 setValue : function(v){
48541 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
48542 this.editorcore.pushValue();
48547 deferFocus : function(){
48548 this.focus.defer(10, this);
48552 focus : function(){
48553 this.editorcore.focus();
48559 onDestroy : function(){
48565 for (var i =0; i < this.toolbars.length;i++) {
48566 // fixme - ask toolbars for heights?
48567 this.toolbars[i].onDestroy();
48570 this.wrap.dom.innerHTML = '';
48571 this.wrap.remove();
48576 onFirstFocus : function(){
48577 //Roo.log("onFirstFocus");
48578 this.editorcore.onFirstFocus();
48579 for (var i =0; i < this.toolbars.length;i++) {
48580 this.toolbars[i].onFirstFocus();
48586 syncValue : function()
48588 this.editorcore.syncValue();
48591 pushValue : function()
48593 this.editorcore.pushValue();
48596 setStylesheets : function(stylesheets)
48598 this.editorcore.setStylesheets(stylesheets);
48601 removeStylesheets : function()
48603 this.editorcore.removeStylesheets();
48607 // hide stuff that is not compatible
48621 * @event specialkey
48625 * @cfg {String} fieldClass @hide
48628 * @cfg {String} focusClass @hide
48631 * @cfg {String} autoCreate @hide
48634 * @cfg {String} inputType @hide
48637 * @cfg {String} invalidClass @hide
48640 * @cfg {String} invalidText @hide
48643 * @cfg {String} msgFx @hide
48646 * @cfg {String} validateOnBlur @hide
48650 // <script type="text/javascript">
48653 * Ext JS Library 1.1.1
48654 * Copyright(c) 2006-2007, Ext JS, LLC.
48660 * @class Roo.form.HtmlEditorToolbar1
48665 new Roo.form.HtmlEditor({
48668 new Roo.form.HtmlEditorToolbar1({
48669 disable : { fonts: 1 , format: 1, ..., ... , ...],
48675 * @cfg {Object} disable List of elements to disable..
48676 * @cfg {Array} btns List of additional buttons.
48680 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
48683 Roo.form.HtmlEditor.ToolbarStandard = function(config)
48686 Roo.apply(this, config);
48688 // default disabled, based on 'good practice'..
48689 this.disable = this.disable || {};
48690 Roo.applyIf(this.disable, {
48693 specialElements : true
48697 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
48698 // dont call parent... till later.
48701 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
48708 editorcore : false,
48710 * @cfg {Object} disable List of toolbar elements to disable
48717 * @cfg {String} createLinkText The default text for the create link prompt
48719 createLinkText : 'Please enter the URL for the link:',
48721 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
48723 defaultLinkValue : 'http:/'+'/',
48727 * @cfg {Array} fontFamilies An array of available font families
48745 // "á" , ?? a acute?
48750 "°" // , // degrees
48752 // "é" , // e ecute
48753 // "ú" , // u ecute?
48756 specialElements : [
48758 text: "Insert Table",
48761 ihtml : '<table><tr><td>Cell</td></tr></table>'
48765 text: "Insert Image",
48768 ihtml : '<img src="about:blank"/>'
48777 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
48778 "input:submit", "input:button", "select", "textarea", "label" ],
48781 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
48783 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
48792 * @cfg {String} defaultFont default font to use.
48794 defaultFont: 'tahoma',
48796 fontSelect : false,
48799 formatCombo : false,
48801 init : function(editor)
48803 this.editor = editor;
48804 this.editorcore = editor.editorcore ? editor.editorcore : editor;
48805 var editorcore = this.editorcore;
48809 var fid = editorcore.frameId;
48811 function btn(id, toggle, handler){
48812 var xid = fid + '-'+ id ;
48816 cls : 'x-btn-icon x-edit-'+id,
48817 enableToggle:toggle !== false,
48818 scope: _t, // was editor...
48819 handler:handler||_t.relayBtnCmd,
48820 clickEvent:'mousedown',
48821 tooltip: etb.buttonTips[id] || undefined, ///tips ???
48828 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
48830 // stop form submits
48831 tb.el.on('click', function(e){
48832 e.preventDefault(); // what does this do?
48835 if(!this.disable.font) { // && !Roo.isSafari){
48836 /* why no safari for fonts
48837 editor.fontSelect = tb.el.createChild({
48840 cls:'x-font-select',
48841 html: this.createFontOptions()
48844 editor.fontSelect.on('change', function(){
48845 var font = editor.fontSelect.dom.value;
48846 editor.relayCmd('fontname', font);
48847 editor.deferFocus();
48851 editor.fontSelect.dom,
48857 if(!this.disable.formats){
48858 this.formatCombo = new Roo.form.ComboBox({
48859 store: new Roo.data.SimpleStore({
48862 data : this.formats // from states.js
48866 //autoCreate : {tag: "div", size: "20"},
48867 displayField:'tag',
48871 triggerAction: 'all',
48872 emptyText:'Add tag',
48873 selectOnFocus:true,
48876 'select': function(c, r, i) {
48877 editorcore.insertTag(r.get('tag'));
48883 tb.addField(this.formatCombo);
48887 if(!this.disable.format){
48892 btn('strikethrough')
48895 if(!this.disable.fontSize){
48900 btn('increasefontsize', false, editorcore.adjustFont),
48901 btn('decreasefontsize', false, editorcore.adjustFont)
48906 if(!this.disable.colors){
48909 id:editorcore.frameId +'-forecolor',
48910 cls:'x-btn-icon x-edit-forecolor',
48911 clickEvent:'mousedown',
48912 tooltip: this.buttonTips['forecolor'] || undefined,
48914 menu : new Roo.menu.ColorMenu({
48915 allowReselect: true,
48916 focus: Roo.emptyFn,
48919 selectHandler: function(cp, color){
48920 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
48921 editor.deferFocus();
48924 clickEvent:'mousedown'
48927 id:editorcore.frameId +'backcolor',
48928 cls:'x-btn-icon x-edit-backcolor',
48929 clickEvent:'mousedown',
48930 tooltip: this.buttonTips['backcolor'] || undefined,
48932 menu : new Roo.menu.ColorMenu({
48933 focus: Roo.emptyFn,
48936 allowReselect: true,
48937 selectHandler: function(cp, color){
48939 editorcore.execCmd('useCSS', false);
48940 editorcore.execCmd('hilitecolor', color);
48941 editorcore.execCmd('useCSS', true);
48942 editor.deferFocus();
48944 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
48945 Roo.isSafari || Roo.isIE ? '#'+color : color);
48946 editor.deferFocus();
48950 clickEvent:'mousedown'
48955 // now add all the items...
48958 if(!this.disable.alignments){
48961 btn('justifyleft'),
48962 btn('justifycenter'),
48963 btn('justifyright')
48967 //if(!Roo.isSafari){
48968 if(!this.disable.links){
48971 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
48975 if(!this.disable.lists){
48978 btn('insertorderedlist'),
48979 btn('insertunorderedlist')
48982 if(!this.disable.sourceEdit){
48985 btn('sourceedit', true, function(btn){
48986 this.toggleSourceEdit(btn.pressed);
48993 // special menu.. - needs to be tidied up..
48994 if (!this.disable.special) {
48997 cls: 'x-edit-none',
49003 for (var i =0; i < this.specialChars.length; i++) {
49004 smenu.menu.items.push({
49006 html: this.specialChars[i],
49007 handler: function(a,b) {
49008 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
49009 //editor.insertAtCursor(a.html);
49023 if (!this.disable.cleanStyles) {
49025 cls: 'x-btn-icon x-btn-clear',
49031 for (var i =0; i < this.cleanStyles.length; i++) {
49032 cmenu.menu.items.push({
49033 actiontype : this.cleanStyles[i],
49034 html: 'Remove ' + this.cleanStyles[i],
49035 handler: function(a,b) {
49038 var c = Roo.get(editorcore.doc.body);
49039 c.select('[style]').each(function(s) {
49040 s.dom.style.removeProperty(a.actiontype);
49042 editorcore.syncValue();
49047 cmenu.menu.items.push({
49048 actiontype : 'tablewidths',
49049 html: 'Remove Table Widths',
49050 handler: function(a,b) {
49051 editorcore.cleanTableWidths();
49052 editorcore.syncValue();
49056 cmenu.menu.items.push({
49057 actiontype : 'word',
49058 html: 'Remove MS Word Formating',
49059 handler: function(a,b) {
49060 editorcore.cleanWord();
49061 editorcore.syncValue();
49066 cmenu.menu.items.push({
49067 actiontype : 'all',
49068 html: 'Remove All Styles',
49069 handler: function(a,b) {
49071 var c = Roo.get(editorcore.doc.body);
49072 c.select('[style]').each(function(s) {
49073 s.dom.removeAttribute('style');
49075 editorcore.syncValue();
49080 cmenu.menu.items.push({
49081 actiontype : 'all',
49082 html: 'Remove All CSS Classes',
49083 handler: function(a,b) {
49085 var c = Roo.get(editorcore.doc.body);
49086 c.select('[class]').each(function(s) {
49087 s.dom.removeAttribute('class');
49089 editorcore.cleanWord();
49090 editorcore.syncValue();
49095 cmenu.menu.items.push({
49096 actiontype : 'tidy',
49097 html: 'Tidy HTML Source',
49098 handler: function(a,b) {
49099 new Roo.htmleditor.Tidy(editorcore.doc.body);
49100 editorcore.syncValue();
49109 if (!this.disable.specialElements) {
49112 cls: 'x-edit-none',
49117 for (var i =0; i < this.specialElements.length; i++) {
49118 semenu.menu.items.push(
49120 handler: function(a,b) {
49121 editor.insertAtCursor(this.ihtml);
49123 }, this.specialElements[i])
49135 for(var i =0; i< this.btns.length;i++) {
49136 var b = Roo.factory(this.btns[i],this.btns[i].xns || Roo.form);
49137 b.cls = 'x-edit-none';
49139 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
49140 b.cls += ' x-init-enable';
49143 b.scope = editorcore;
49151 // disable everything...
49153 this.tb.items.each(function(item){
49156 item.id != editorcore.frameId+ '-sourceedit' &&
49157 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
49163 this.rendered = true;
49165 // the all the btns;
49166 editor.on('editorevent', this.updateToolbar, this);
49167 // other toolbars need to implement this..
49168 //editor.on('editmodechange', this.updateToolbar, this);
49172 relayBtnCmd : function(btn) {
49173 this.editorcore.relayCmd(btn.cmd);
49175 // private used internally
49176 createLink : function(){
49177 Roo.log("create link?");
49178 var url = prompt(this.createLinkText, this.defaultLinkValue);
49179 if(url && url != 'http:/'+'/'){
49180 this.editorcore.relayCmd('createlink', url);
49186 * Protected method that will not generally be called directly. It triggers
49187 * a toolbar update by reading the markup state of the current selection in the editor.
49189 updateToolbar: function(){
49191 if(!this.editorcore.activated){
49192 this.editor.onFirstFocus();
49196 var btns = this.tb.items.map,
49197 doc = this.editorcore.doc,
49198 frameId = this.editorcore.frameId;
49200 if(!this.disable.font && !Roo.isSafari){
49202 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
49203 if(name != this.fontSelect.dom.value){
49204 this.fontSelect.dom.value = name;
49208 if(!this.disable.format){
49209 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
49210 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
49211 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
49212 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
49214 if(!this.disable.alignments){
49215 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
49216 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
49217 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
49219 if(!Roo.isSafari && !this.disable.lists){
49220 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
49221 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
49224 var ans = this.editorcore.getAllAncestors();
49225 if (this.formatCombo) {
49228 var store = this.formatCombo.store;
49229 this.formatCombo.setValue("");
49230 for (var i =0; i < ans.length;i++) {
49231 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
49233 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
49241 // hides menus... - so this cant be on a menu...
49242 Roo.menu.MenuMgr.hideAll();
49244 //this.editorsyncValue();
49248 createFontOptions : function(){
49249 var buf = [], fs = this.fontFamilies, ff, lc;
49253 for(var i = 0, len = fs.length; i< len; i++){
49255 lc = ff.toLowerCase();
49257 '<option value="',lc,'" style="font-family:',ff,';"',
49258 (this.defaultFont == lc ? ' selected="true">' : '>'),
49263 return buf.join('');
49266 toggleSourceEdit : function(sourceEditMode){
49268 Roo.log("toolbar toogle");
49269 if(sourceEditMode === undefined){
49270 sourceEditMode = !this.sourceEditMode;
49272 this.sourceEditMode = sourceEditMode === true;
49273 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
49274 // just toggle the button?
49275 if(btn.pressed !== this.sourceEditMode){
49276 btn.toggle(this.sourceEditMode);
49280 if(sourceEditMode){
49281 Roo.log("disabling buttons");
49282 this.tb.items.each(function(item){
49283 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
49289 Roo.log("enabling buttons");
49290 if(this.editorcore.initialized){
49291 this.tb.items.each(function(item){
49297 Roo.log("calling toggole on editor");
49298 // tell the editor that it's been pressed..
49299 this.editor.toggleSourceEdit(sourceEditMode);
49303 * Object collection of toolbar tooltips for the buttons in the editor. The key
49304 * is the command id associated with that button and the value is a valid QuickTips object.
49309 title: 'Bold (Ctrl+B)',
49310 text: 'Make the selected text bold.',
49311 cls: 'x-html-editor-tip'
49314 title: 'Italic (Ctrl+I)',
49315 text: 'Make the selected text italic.',
49316 cls: 'x-html-editor-tip'
49324 title: 'Bold (Ctrl+B)',
49325 text: 'Make the selected text bold.',
49326 cls: 'x-html-editor-tip'
49329 title: 'Italic (Ctrl+I)',
49330 text: 'Make the selected text italic.',
49331 cls: 'x-html-editor-tip'
49334 title: 'Underline (Ctrl+U)',
49335 text: 'Underline the selected text.',
49336 cls: 'x-html-editor-tip'
49339 title: 'Strikethrough',
49340 text: 'Strikethrough the selected text.',
49341 cls: 'x-html-editor-tip'
49343 increasefontsize : {
49344 title: 'Grow Text',
49345 text: 'Increase the font size.',
49346 cls: 'x-html-editor-tip'
49348 decreasefontsize : {
49349 title: 'Shrink Text',
49350 text: 'Decrease the font size.',
49351 cls: 'x-html-editor-tip'
49354 title: 'Text Highlight Color',
49355 text: 'Change the background color of the selected text.',
49356 cls: 'x-html-editor-tip'
49359 title: 'Font Color',
49360 text: 'Change the color of the selected text.',
49361 cls: 'x-html-editor-tip'
49364 title: 'Align Text Left',
49365 text: 'Align text to the left.',
49366 cls: 'x-html-editor-tip'
49369 title: 'Center Text',
49370 text: 'Center text in the editor.',
49371 cls: 'x-html-editor-tip'
49374 title: 'Align Text Right',
49375 text: 'Align text to the right.',
49376 cls: 'x-html-editor-tip'
49378 insertunorderedlist : {
49379 title: 'Bullet List',
49380 text: 'Start a bulleted list.',
49381 cls: 'x-html-editor-tip'
49383 insertorderedlist : {
49384 title: 'Numbered List',
49385 text: 'Start a numbered list.',
49386 cls: 'x-html-editor-tip'
49389 title: 'Hyperlink',
49390 text: 'Make the selected text a hyperlink.',
49391 cls: 'x-html-editor-tip'
49394 title: 'Source Edit',
49395 text: 'Switch to source editing mode.',
49396 cls: 'x-html-editor-tip'
49400 onDestroy : function(){
49403 this.tb.items.each(function(item){
49405 item.menu.removeAll();
49407 item.menu.el.destroy();
49415 onFirstFocus: function() {
49416 this.tb.items.each(function(item){
49425 // <script type="text/javascript">
49428 * Ext JS Library 1.1.1
49429 * Copyright(c) 2006-2007, Ext JS, LLC.
49436 * @class Roo.form.HtmlEditor.ToolbarContext
49441 new Roo.form.HtmlEditor({
49444 { xtype: 'ToolbarStandard', styles : {} }
49445 { xtype: 'ToolbarContext', disable : {} }
49451 * @config : {Object} disable List of elements to disable.. (not done yet.)
49452 * @config : {Object} styles Map of styles available.
49456 Roo.form.HtmlEditor.ToolbarContext = function(config)
49459 Roo.apply(this, config);
49460 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
49461 // dont call parent... till later.
49462 this.styles = this.styles || {};
49467 Roo.form.HtmlEditor.ToolbarContext.types = {
49482 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
49508 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
49579 name : 'selectoptions',
49585 // should we really allow this??
49586 // should this just be
49603 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
49604 Roo.form.HtmlEditor.ToolbarContext.stores = false;
49606 Roo.form.HtmlEditor.ToolbarContext.options = {
49608 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
49609 [ 'Courier New', 'Courier New'],
49610 [ 'Tahoma', 'Tahoma'],
49611 [ 'Times New Roman,serif', 'Times'],
49612 [ 'Verdana','Verdana' ]
49616 // fixme - these need to be configurable..
49619 //Roo.form.HtmlEditor.ToolbarContext.types
49622 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
49629 editorcore : false,
49631 * @cfg {Object} disable List of toolbar elements to disable
49636 * @cfg {Object} styles List of styles
49637 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
49639 * These must be defined in the page, so they get rendered correctly..
49650 init : function(editor)
49652 this.editor = editor;
49653 this.editorcore = editor.editorcore ? editor.editorcore : editor;
49654 var editorcore = this.editorcore;
49656 var fid = editorcore.frameId;
49658 function btn(id, toggle, handler){
49659 var xid = fid + '-'+ id ;
49663 cls : 'x-btn-icon x-edit-'+id,
49664 enableToggle:toggle !== false,
49665 scope: editorcore, // was editor...
49666 handler:handler||editorcore.relayBtnCmd,
49667 clickEvent:'mousedown',
49668 tooltip: etb.buttonTips[id] || undefined, ///tips ???
49672 // create a new element.
49673 var wdiv = editor.wrap.createChild({
49675 }, editor.wrap.dom.firstChild.nextSibling, true);
49677 // can we do this more than once??
49679 // stop form submits
49682 // disable everything...
49683 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
49684 this.toolbars = {};
49686 for (var i in ty) {
49688 this.toolbars[i] = this.buildToolbar(ty[i],i);
49690 this.tb = this.toolbars.BODY;
49692 this.buildFooter();
49693 this.footer.show();
49694 editor.on('hide', function( ) { this.footer.hide() }, this);
49695 editor.on('show', function( ) { this.footer.show() }, this);
49698 this.rendered = true;
49700 // the all the btns;
49701 editor.on('editorevent', this.updateToolbar, this);
49702 // other toolbars need to implement this..
49703 //editor.on('editmodechange', this.updateToolbar, this);
49709 * Protected method that will not generally be called directly. It triggers
49710 * a toolbar update by reading the markup state of the current selection in the editor.
49712 * Note you can force an update by calling on('editorevent', scope, false)
49714 updateToolbar: function(editor ,ev, sel)
49718 ev.stopEvent(); // se if we can stop this looping with mutiple events.
49722 // capture mouse up - this is handy for selecting images..
49723 // perhaps should go somewhere else...
49724 if(!this.editorcore.activated){
49725 this.editor.onFirstFocus();
49728 //Roo.log(ev ? ev.target : 'NOTARGET');
49731 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
49732 // selectNode - might want to handle IE?
49737 (ev.type == 'mouseup' || ev.type == 'click' ) &&
49738 ev.target && ev.target.tagName != 'BODY' ) { // && ev.target.tagName == 'IMG') {
49739 // they have click on an image...
49740 // let's see if we can change the selection...
49743 // this triggers looping?
49744 //this.editorcore.selectNode(sel);
49747 Roo.select('.roo-ed-selection', false, this.editorcore.doc).removeClass('roo-ed-selection');
49748 //Roo.get(node).addClass('roo-ed-selection');
49750 //var updateFooter = sel ? false : true;
49753 var ans = this.editorcore.getAllAncestors();
49756 var ty = Roo.form.HtmlEditor.ToolbarContext.types;
49759 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
49760 sel = sel ? sel : this.editorcore.doc.body;
49761 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
49765 var tn = sel.tagName.toUpperCase();
49766 var lastSel = this.tb.selectedNode;
49767 this.tb.selectedNode = sel;
49768 var left_label = tn;
49770 // ok see if we are editing a block?
49773 // you are not actually selecting the block.
49774 if (sel && sel.hasAttribute('data-block')) {
49776 } else if (sel && !sel.hasAttribute('contenteditable')) {
49777 var sel_el = Roo.get(sel);
49778 db = sel_el.findParent('[data-block]');
49779 var cepar = sel_el.findParent('[contenteditable=true]');
49780 if (db && cepar && cepar.tagName != 'BODY') {
49781 db = false; // we are inside an editable block.. = not sure how we are going to handle nested blocks!?
49787 //if (db && !sel.hasAttribute('contenteditable') && sel.getAttribute('contenteditable') != 'true' ) {
49789 block = Roo.htmleditor.Block.factory(db);
49793 db.className += ' roo-ed-selection'; // since we removed it earlier... its not there..
49794 tn = 'BLOCK.' + db.getAttribute('data-block');
49796 //this.editorcore.selectNode(db);
49797 if (typeof(this.toolbars[tn]) == 'undefined') {
49798 this.toolbars[tn] = this.buildToolbar( false ,tn ,block.friendly_name, block);
49800 this.toolbars[tn].selectedNode = db;
49801 left_label = block.friendly_name;
49802 ans = this.editorcore.getAllAncestors();
49810 if (this.tb.name == tn && lastSel == this.tb.selectedNode && ev !== false) {
49811 return; // no change?
49817 ///console.log("show: " + tn);
49818 this.tb = typeof(this.toolbars[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
49822 this.tb.items.first().el.innerHTML = left_label + ': ';
49825 // update attributes
49826 if (block && this.tb.fields) {
49828 this.tb.fields.each(function(e) {
49829 e.setValue(block[e.name]);
49833 } else if (this.tb.fields && this.tb.selectedNode) {
49834 this.tb.fields.each( function(e) {
49836 e.setValue(this.tb.selectedNode.style[e.stylename]);
49839 e.setValue(this.tb.selectedNode.getAttribute(e.attrname));
49841 this.updateToolbarStyles(this.tb.selectedNode);
49846 Roo.menu.MenuMgr.hideAll();
49851 // update the footer
49853 this.updateFooter(ans);
49857 updateToolbarStyles : function(sel)
49859 var hasStyles = false;
49860 for(var i in this.styles) {
49866 if (hasStyles && this.tb.hasStyles) {
49867 var st = this.tb.fields.item(0);
49869 st.store.removeAll();
49870 var cn = sel.className.split(/\s+/);
49873 if (this.styles['*']) {
49875 Roo.each(this.styles['*'], function(v) {
49876 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
49879 if (this.styles[tn]) {
49880 Roo.each(this.styles[tn], function(v) {
49881 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
49885 st.store.loadData(avs);
49892 updateFooter : function(ans)
49895 if (ans === false) {
49896 this.footDisp.dom.innerHTML = '';
49900 this.footerEls = ans.reverse();
49901 Roo.each(this.footerEls, function(a,i) {
49902 if (!a) { return; }
49903 html += html.length ? ' > ' : '';
49905 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
49910 var sz = this.footDisp.up('td').getSize();
49911 this.footDisp.dom.style.width = (sz.width -10) + 'px';
49912 this.footDisp.dom.style.marginLeft = '5px';
49914 this.footDisp.dom.style.overflow = 'hidden';
49916 this.footDisp.dom.innerHTML = html;
49923 onDestroy : function(){
49926 this.tb.items.each(function(item){
49928 item.menu.removeAll();
49930 item.menu.el.destroy();
49938 onFirstFocus: function() {
49939 // need to do this for all the toolbars..
49940 this.tb.items.each(function(item){
49944 buildToolbar: function(tlist, nm, friendly_name, block)
49946 var editor = this.editor;
49947 var editorcore = this.editorcore;
49948 // create a new element.
49949 var wdiv = editor.wrap.createChild({
49951 }, editor.wrap.dom.firstChild.nextSibling, true);
49954 var tb = new Roo.Toolbar(wdiv);
49955 ///this.tb = tb; // << this sets the active toolbar..
49956 if (tlist === false && block) {
49957 tlist = block.contextMenu(this);
49960 tb.hasStyles = false;
49963 tb.add((typeof(friendly_name) == 'undefined' ? nm : friendly_name) + ": ");
49965 var styles = Array.from(this.styles);
49969 if (styles && styles.length) {
49970 tb.hasStyles = true;
49971 // this needs a multi-select checkbox...
49972 tb.addField( new Roo.form.ComboBox({
49973 store: new Roo.data.SimpleStore({
49975 fields: ['val', 'selected'],
49978 name : '-roo-edit-className',
49979 attrname : 'className',
49980 displayField: 'val',
49984 triggerAction: 'all',
49985 emptyText:'Select Style',
49986 selectOnFocus:true,
49989 'select': function(c, r, i) {
49990 // initial support only for on class per el..
49991 tb.selectedNode.className = r ? r.get('val') : '';
49992 editorcore.syncValue();
49999 var tbc = Roo.form.HtmlEditor.ToolbarContext;
50002 for (var i = 0; i < tlist.length; i++) {
50004 // newer versions will use xtype cfg to create menus.
50005 if (typeof(tlist[i].xtype) != 'undefined') {
50007 tb[typeof(tlist[i].name)== 'undefined' ? 'add' : 'addField'](Roo.factory(tlist[i]));
50013 var item = tlist[i];
50014 tb.add(item.title + ": ");
50017 //optname == used so you can configure the options available..
50018 var opts = item.opts ? item.opts : false;
50019 if (item.optname) { // use the b
50020 opts = Roo.form.HtmlEditor.ToolbarContext.options[item.optname];
50025 // opts == pulldown..
50026 tb.addField( new Roo.form.ComboBox({
50027 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
50029 fields: ['val', 'display'],
50032 name : '-roo-edit-' + tlist[i].name,
50034 attrname : tlist[i].name,
50035 stylename : item.style ? item.style : false,
50037 displayField: item.displayField ? item.displayField : 'val',
50038 valueField : 'val',
50040 mode: typeof(tbc.stores[tlist[i].name]) != 'undefined' ? 'remote' : 'local',
50042 triggerAction: 'all',
50043 emptyText:'Select',
50044 selectOnFocus:true,
50045 width: item.width ? item.width : 130,
50047 'select': function(c, r, i) {
50048 if (tb.selectedNode.hasAttribute('data-block')) {
50049 var b = Roo.htmleditor.Block.factory(tb.selectedNode);
50050 b[c.attrname] = r.get('val');
50051 b.updateElement(tb.selectedNode);
50052 editorcore.syncValue();
50057 tb.selectedNode.style[c.stylename] = r.get('val');
50058 editorcore.syncValue();
50062 tb.selectedNode.removeAttribute(c.attrname);
50063 editorcore.syncValue();
50066 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
50067 editorcore.syncValue();
50076 tb.addField( new Roo.form.TextField({
50079 //allowBlank:false,
50085 tb.addField( new Roo.form.TextField({
50086 name: '-roo-edit-' + tlist[i].name,
50087 attrname : tlist[i].name,
50093 'change' : function(f, nv, ov) {
50095 if (tb.selectedNode.hasAttribute('data-block')) {
50096 var b = Roo.htmleditor.Block.factory(tb.selectedNode);
50097 b[f.attrname] = nv;
50098 b.updateElement(tb.selectedNode);
50099 editorcore.syncValue();
50103 tb.selectedNode.setAttribute(f.attrname, nv);
50104 editorcore.syncValue();
50117 text: 'Stylesheets',
50120 click : function ()
50122 _this.editor.fireEvent('stylesheetsclick', _this.editor);
50130 text: 'Remove Block or Formating', // remove the tag, and puts the children outside...
50133 click : function ()
50135 var sn = tb.selectedNode;
50137 sn = Roo.htmleditor.Block.factory(tb.selectedNode).removeNode();
50143 var stn = sn.childNodes[0] || sn.nextSibling || sn.previousSibling || sn.parentNode;
50144 if (sn.hasAttribute('data-block')) {
50145 stn = sn.nextSibling || sn.previousSibling || sn.parentNode;
50146 sn.parentNode.removeChild(sn);
50148 } else if (sn && sn.tagName != 'BODY') {
50149 // remove and keep parents.
50150 a = new Roo.htmleditor.FilterKeepChildren({tag : false});
50155 var range = editorcore.createRange();
50157 range.setStart(stn,0);
50158 range.setEnd(stn,0);
50159 var selection = editorcore.getSelection();
50160 selection.removeAllRanges();
50161 selection.addRange(range);
50164 //_this.updateToolbar(null, null, pn);
50165 _this.updateToolbar(null, null, null);
50166 _this.updateFooter(false);
50177 tb.el.on('click', function(e){
50178 e.preventDefault(); // what does this do?
50180 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
50183 // dont need to disable them... as they will get hidden
50188 buildFooter : function()
50191 var fel = this.editor.wrap.createChild();
50192 this.footer = new Roo.Toolbar(fel);
50193 // toolbar has scrolly on left / right?
50194 var footDisp= new Roo.Toolbar.Fill();
50200 handler : function() {
50201 _t.footDisp.scrollTo('left',0,true)
50205 this.footer.add( footDisp );
50210 handler : function() {
50212 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
50216 var fel = Roo.get(footDisp.el);
50217 fel.addClass('x-editor-context');
50218 this.footDispWrap = fel;
50219 this.footDispWrap.overflow = 'hidden';
50221 this.footDisp = fel.createChild();
50222 this.footDispWrap.on('click', this.onContextClick, this)
50226 // when the footer contect changes
50227 onContextClick : function (ev,dom)
50229 ev.preventDefault();
50230 var cn = dom.className;
50232 if (!cn.match(/x-ed-loc-/)) {
50235 var n = cn.split('-').pop();
50236 var ans = this.footerEls;
50239 this.editorcore.selectNode(sel);
50242 this.updateToolbar(null, null, sel);
50259 * Ext JS Library 1.1.1
50260 * Copyright(c) 2006-2007, Ext JS, LLC.
50262 * Originally Released Under LGPL - original licence link has changed is not relivant.
50265 * <script type="text/javascript">
50269 * @class Roo.form.BasicForm
50270 * @extends Roo.util.Observable
50271 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
50273 * @param {String/HTMLElement/Roo.Element} el The form element or its id
50274 * @param {Object} config Configuration options
50276 Roo.form.BasicForm = function(el, config){
50277 this.allItems = [];
50278 this.childForms = [];
50279 Roo.apply(this, config);
50281 * The Roo.form.Field items in this form.
50282 * @type MixedCollection
50286 this.items = new Roo.util.MixedCollection(false, function(o){
50287 return o.id || (o.id = Roo.id());
50291 * @event beforeaction
50292 * Fires before any action is performed. Return false to cancel the action.
50293 * @param {Form} this
50294 * @param {Action} action The action to be performed
50296 beforeaction: true,
50298 * @event actionfailed
50299 * Fires when an action fails.
50300 * @param {Form} this
50301 * @param {Action} action The action that failed
50303 actionfailed : true,
50305 * @event actioncomplete
50306 * Fires when an action is completed.
50307 * @param {Form} this
50308 * @param {Action} action The action that completed
50310 actioncomplete : true
50315 Roo.form.BasicForm.superclass.constructor.call(this);
50317 Roo.form.BasicForm.popover.apply();
50320 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
50322 * @cfg {String} method
50323 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
50326 * @cfg {DataReader} reader
50327 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
50328 * This is optional as there is built-in support for processing JSON.
50331 * @cfg {DataReader} errorReader
50332 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
50333 * This is completely optional as there is built-in support for processing JSON.
50336 * @cfg {String} url
50337 * The URL to use for form actions if one isn't supplied in the action options.
50340 * @cfg {Boolean} fileUpload
50341 * Set to true if this form is a file upload.
50345 * @cfg {Object} baseParams
50346 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
50351 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
50356 activeAction : null,
50359 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
50360 * or setValues() data instead of when the form was first created.
50362 trackResetOnLoad : false,
50366 * childForms - used for multi-tab forms
50369 childForms : false,
50372 * allItems - full list of fields.
50378 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
50379 * element by passing it or its id or mask the form itself by passing in true.
50382 waitMsgTarget : false,
50387 disableMask : false,
50390 * @cfg {Boolean} errorMask (true|false) default false
50395 * @cfg {Number} maskOffset Default 100
50400 initEl : function(el){
50401 this.el = Roo.get(el);
50402 this.id = this.el.id || Roo.id();
50403 this.el.on('submit', this.onSubmit, this);
50404 this.el.addClass('x-form');
50408 onSubmit : function(e){
50413 * Returns true if client-side validation on the form is successful.
50416 isValid : function(){
50418 var target = false;
50419 this.items.each(function(f){
50426 if(!target && f.el.isVisible(true)){
50431 if(this.errorMask && !valid){
50432 Roo.form.BasicForm.popover.mask(this, target);
50438 * Returns array of invalid form fields.
50442 invalidFields : function()
50445 this.items.each(function(f){
50458 * DEPRICATED Returns true if any fields in this form have changed since their original load.
50461 isDirty : function(){
50463 this.items.each(function(f){
50473 * Returns true if any fields in this form have changed since their original load. (New version)
50477 hasChanged : function()
50480 this.items.each(function(f){
50481 if(f.hasChanged()){
50490 * Resets all hasChanged to 'false' -
50491 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
50492 * So hasChanged storage is only to be used for this purpose
50495 resetHasChanged : function()
50497 this.items.each(function(f){
50498 f.resetHasChanged();
50505 * Performs a predefined action (submit or load) or custom actions you define on this form.
50506 * @param {String} actionName The name of the action type
50507 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
50508 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
50509 * accept other config options):
50511 Property Type Description
50512 ---------------- --------------- ----------------------------------------------------------------------------------
50513 url String The url for the action (defaults to the form's url)
50514 method String The form method to use (defaults to the form's method, or POST if not defined)
50515 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
50516 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
50517 validate the form on the client (defaults to false)
50519 * @return {BasicForm} this
50521 doAction : function(action, options){
50522 if(typeof action == 'string'){
50523 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
50525 if(this.fireEvent('beforeaction', this, action) !== false){
50526 this.beforeAction(action);
50527 action.run.defer(100, action);
50533 * Shortcut to do a submit action.
50534 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
50535 * @return {BasicForm} this
50537 submit : function(options){
50538 this.doAction('submit', options);
50543 * Shortcut to do a load action.
50544 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
50545 * @return {BasicForm} this
50547 load : function(options){
50548 this.doAction('load', options);
50553 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
50554 * @param {Record} record The record to edit
50555 * @return {BasicForm} this
50557 updateRecord : function(record){
50558 record.beginEdit();
50559 var fs = record.fields;
50560 fs.each(function(f){
50561 var field = this.findField(f.name);
50563 record.set(f.name, field.getValue());
50571 * Loads an Roo.data.Record into this form.
50572 * @param {Record} record The record to load
50573 * @return {BasicForm} this
50575 loadRecord : function(record){
50576 this.setValues(record.data);
50581 beforeAction : function(action){
50582 var o = action.options;
50584 if(!this.disableMask) {
50585 if(this.waitMsgTarget === true){
50586 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
50587 }else if(this.waitMsgTarget){
50588 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
50589 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
50591 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
50599 afterAction : function(action, success){
50600 this.activeAction = null;
50601 var o = action.options;
50603 if(!this.disableMask) {
50604 if(this.waitMsgTarget === true){
50606 }else if(this.waitMsgTarget){
50607 this.waitMsgTarget.unmask();
50609 Roo.MessageBox.updateProgress(1);
50610 Roo.MessageBox.hide();
50618 Roo.callback(o.success, o.scope, [this, action]);
50619 this.fireEvent('actioncomplete', this, action);
50623 // failure condition..
50624 // we have a scenario where updates need confirming.
50625 // eg. if a locking scenario exists..
50626 // we look for { errors : { needs_confirm : true }} in the response.
50628 (typeof(action.result) != 'undefined') &&
50629 (typeof(action.result.errors) != 'undefined') &&
50630 (typeof(action.result.errors.needs_confirm) != 'undefined')
50633 Roo.MessageBox.confirm(
50634 "Change requires confirmation",
50635 action.result.errorMsg,
50640 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
50650 Roo.callback(o.failure, o.scope, [this, action]);
50651 // show an error message if no failed handler is set..
50652 if (!this.hasListener('actionfailed')) {
50653 Roo.MessageBox.alert("Error",
50654 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
50655 action.result.errorMsg :
50656 "Saving Failed, please check your entries or try again"
50660 this.fireEvent('actionfailed', this, action);
50666 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
50667 * @param {String} id The value to search for
50670 findField : function(id){
50671 var field = this.items.get(id);
50673 this.items.each(function(f){
50674 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
50680 return field || null;
50684 * Add a secondary form to this one,
50685 * Used to provide tabbed forms. One form is primary, with hidden values
50686 * which mirror the elements from the other forms.
50688 * @param {Roo.form.Form} form to add.
50691 addForm : function(form)
50694 if (this.childForms.indexOf(form) > -1) {
50698 this.childForms.push(form);
50700 Roo.each(form.allItems, function (fe) {
50702 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
50703 if (this.findField(n)) { // already added..
50706 var add = new Roo.form.Hidden({
50709 add.render(this.el);
50716 * Mark fields in this form invalid in bulk.
50717 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
50718 * @return {BasicForm} this
50720 markInvalid : function(errors){
50721 if(errors instanceof Array){
50722 for(var i = 0, len = errors.length; i < len; i++){
50723 var fieldError = errors[i];
50724 var f = this.findField(fieldError.id);
50726 f.markInvalid(fieldError.msg);
50732 if(typeof errors[id] != 'function' && (field = this.findField(id))){
50733 field.markInvalid(errors[id]);
50737 Roo.each(this.childForms || [], function (f) {
50738 f.markInvalid(errors);
50745 * Set values for fields in this form in bulk.
50746 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
50747 * @return {BasicForm} this
50749 setValues : function(values){
50750 if(values instanceof Array){ // array of objects
50751 for(var i = 0, len = values.length; i < len; i++){
50753 var f = this.findField(v.id);
50755 f.setValue(v.value);
50756 if(this.trackResetOnLoad){
50757 f.originalValue = f.getValue();
50761 }else{ // object hash
50764 if(typeof values[id] != 'function' && (field = this.findField(id))){
50766 if (field.setFromData &&
50767 field.valueField &&
50768 field.displayField &&
50769 // combos' with local stores can
50770 // be queried via setValue()
50771 // to set their value..
50772 (field.store && !field.store.isLocal)
50776 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
50777 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
50778 field.setFromData(sd);
50781 field.setValue(values[id]);
50785 if(this.trackResetOnLoad){
50786 field.originalValue = field.getValue();
50791 this.resetHasChanged();
50794 Roo.each(this.childForms || [], function (f) {
50795 f.setValues(values);
50796 f.resetHasChanged();
50803 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
50804 * they are returned as an array.
50805 * @param {Boolean} asString
50808 getValues : function(asString)
50810 if (this.childForms) {
50811 // copy values from the child forms
50812 Roo.each(this.childForms, function (f) {
50813 this.setValues(f.getFieldValues()); // get the full set of data, as we might be copying comboboxes from external into this one.
50818 if (typeof(FormData) != 'undefined' && asString !== true) {
50819 // this relies on a 'recent' version of chrome apparently...
50821 var fd = (new FormData(this.el.dom)).entries();
50823 var ent = fd.next();
50824 while (!ent.done) {
50825 ret[ent.value[0]] = ent.value[1]; // not sure how this will handle duplicates..
50836 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
50837 if(asString === true){
50840 return Roo.urlDecode(fs);
50844 * Returns the fields in this form as an object with key/value pairs.
50845 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
50846 * Normally this will not return readOnly data
50847 * @param {Boolean} with_readonly return readonly field data.
50850 getFieldValues : function(with_readonly)
50852 if (this.childForms) {
50853 // copy values from the child forms
50854 // should this call getFieldValues - probably not as we do not currently copy
50855 // hidden fields when we generate..
50856 Roo.each(this.childForms, function (f) {
50857 this.setValues(f.getFieldValues());
50862 this.items.each(function(f){
50864 if (f.readOnly && with_readonly !== true) {
50865 return; // skip read only values. - this is in theory to stop 'old' values being copied over new ones
50866 // if a subform contains a copy of them.
50867 // if you have subforms with the same editable data, you will need to copy the data back
50871 if (!f.getName()) {
50874 var v = f.getValue();
50875 if (f.inputType =='radio') {
50876 if (typeof(ret[f.getName()]) == 'undefined') {
50877 ret[f.getName()] = ''; // empty..
50880 if (!f.el.dom.checked) {
50884 v = f.el.dom.value;
50888 // not sure if this supported any more..
50889 if ((typeof(v) == 'object') && f.getRawValue) {
50890 v = f.getRawValue() ; // dates..
50892 // combo boxes where name != hiddenName...
50893 if (f.name != f.getName()) {
50894 ret[f.name] = f.getRawValue();
50896 ret[f.getName()] = v;
50903 * Clears all invalid messages in this form.
50904 * @return {BasicForm} this
50906 clearInvalid : function(){
50907 this.items.each(function(f){
50911 Roo.each(this.childForms || [], function (f) {
50920 * Resets this form.
50921 * @return {BasicForm} this
50923 reset : function(){
50924 this.items.each(function(f){
50928 Roo.each(this.childForms || [], function (f) {
50931 this.resetHasChanged();
50937 * Add Roo.form components to this form.
50938 * @param {Field} field1
50939 * @param {Field} field2 (optional)
50940 * @param {Field} etc (optional)
50941 * @return {BasicForm} this
50944 this.items.addAll(Array.prototype.slice.call(arguments, 0));
50950 * Removes a field from the items collection (does NOT remove its markup).
50951 * @param {Field} field
50952 * @return {BasicForm} this
50954 remove : function(field){
50955 this.items.remove(field);
50960 * Looks at the fields in this form, checks them for an id attribute,
50961 * and calls applyTo on the existing dom element with that id.
50962 * @return {BasicForm} this
50964 render : function(){
50965 this.items.each(function(f){
50966 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
50974 * Calls {@link Ext#apply} for all fields in this form with the passed object.
50975 * @param {Object} values
50976 * @return {BasicForm} this
50978 applyToFields : function(o){
50979 this.items.each(function(f){
50986 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
50987 * @param {Object} values
50988 * @return {BasicForm} this
50990 applyIfToFields : function(o){
50991 this.items.each(function(f){
50999 Roo.BasicForm = Roo.form.BasicForm;
51001 Roo.apply(Roo.form.BasicForm, {
51015 intervalID : false,
51021 if(this.isApplied){
51026 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
51027 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
51028 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
51029 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
51032 this.maskEl.top.enableDisplayMode("block");
51033 this.maskEl.left.enableDisplayMode("block");
51034 this.maskEl.bottom.enableDisplayMode("block");
51035 this.maskEl.right.enableDisplayMode("block");
51037 Roo.get(document.body).on('click', function(){
51041 Roo.get(document.body).on('touchstart', function(){
51045 this.isApplied = true
51048 mask : function(form, target)
51052 this.target = target;
51054 if(!this.form.errorMask || !target.el){
51058 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.x-layout-active-content', 100, true) || Roo.get(document.body);
51060 var ot = this.target.el.calcOffsetsTo(scrollable);
51062 var scrollTo = ot[1] - this.form.maskOffset;
51064 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
51066 scrollable.scrollTo('top', scrollTo);
51068 var el = this.target.wrap || this.target.el;
51070 var box = el.getBox();
51072 this.maskEl.top.setStyle('position', 'absolute');
51073 this.maskEl.top.setStyle('z-index', 10000);
51074 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
51075 this.maskEl.top.setLeft(0);
51076 this.maskEl.top.setTop(0);
51077 this.maskEl.top.show();
51079 this.maskEl.left.setStyle('position', 'absolute');
51080 this.maskEl.left.setStyle('z-index', 10000);
51081 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
51082 this.maskEl.left.setLeft(0);
51083 this.maskEl.left.setTop(box.y - this.padding);
51084 this.maskEl.left.show();
51086 this.maskEl.bottom.setStyle('position', 'absolute');
51087 this.maskEl.bottom.setStyle('z-index', 10000);
51088 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
51089 this.maskEl.bottom.setLeft(0);
51090 this.maskEl.bottom.setTop(box.bottom + this.padding);
51091 this.maskEl.bottom.show();
51093 this.maskEl.right.setStyle('position', 'absolute');
51094 this.maskEl.right.setStyle('z-index', 10000);
51095 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
51096 this.maskEl.right.setLeft(box.right + this.padding);
51097 this.maskEl.right.setTop(box.y - this.padding);
51098 this.maskEl.right.show();
51100 this.intervalID = window.setInterval(function() {
51101 Roo.form.BasicForm.popover.unmask();
51104 window.onwheel = function(){ return false;};
51106 (function(){ this.isMasked = true; }).defer(500, this);
51110 unmask : function()
51112 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
51116 this.maskEl.top.setStyle('position', 'absolute');
51117 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
51118 this.maskEl.top.hide();
51120 this.maskEl.left.setStyle('position', 'absolute');
51121 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
51122 this.maskEl.left.hide();
51124 this.maskEl.bottom.setStyle('position', 'absolute');
51125 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
51126 this.maskEl.bottom.hide();
51128 this.maskEl.right.setStyle('position', 'absolute');
51129 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
51130 this.maskEl.right.hide();
51132 window.onwheel = function(){ return true;};
51134 if(this.intervalID){
51135 window.clearInterval(this.intervalID);
51136 this.intervalID = false;
51139 this.isMasked = false;
51147 * Ext JS Library 1.1.1
51148 * Copyright(c) 2006-2007, Ext JS, LLC.
51150 * Originally Released Under LGPL - original licence link has changed is not relivant.
51153 * <script type="text/javascript">
51157 * @class Roo.form.Form
51158 * @extends Roo.form.BasicForm
51159 * @children Roo.form.Column Roo.form.FieldSet Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
51160 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
51162 * @param {Object} config Configuration options
51164 Roo.form.Form = function(config){
51166 if (config.items) {
51167 xitems = config.items;
51168 delete config.items;
51172 Roo.form.Form.superclass.constructor.call(this, null, config);
51173 this.url = this.url || this.action;
51175 this.root = new Roo.form.Layout(Roo.applyIf({
51179 this.active = this.root;
51181 * Array of all the buttons that have been added to this form via {@link addButton}
51185 this.allItems = [];
51188 * @event clientvalidation
51189 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
51190 * @param {Form} this
51191 * @param {Boolean} valid true if the form has passed client-side validation
51193 clientvalidation: true,
51196 * Fires when the form is rendered
51197 * @param {Roo.form.Form} form
51202 if (this.progressUrl) {
51203 // push a hidden field onto the list of fields..
51207 name : 'UPLOAD_IDENTIFIER'
51212 Roo.each(xitems, this.addxtype, this);
51216 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
51218 * @cfg {Roo.Button} buttons[] buttons at bottom of form
51222 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
51225 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
51228 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
51230 buttonAlign:'center',
51233 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
51238 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
51239 * This property cascades to child containers if not set.
51244 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
51245 * fires a looping event with that state. This is required to bind buttons to the valid
51246 * state using the config value formBind:true on the button.
51248 monitorValid : false,
51251 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
51256 * @cfg {String} progressUrl - Url to return progress data
51259 progressUrl : false,
51261 * @cfg {boolean|FormData} formData - true to use new 'FormData' post, or set to a new FormData({dom form}) Object, if
51262 * sending a formdata with extra parameters - eg uploaded elements.
51268 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
51269 * fields are added and the column is closed. If no fields are passed the column remains open
51270 * until end() is called.
51271 * @param {Object} config The config to pass to the column
51272 * @param {Field} field1 (optional)
51273 * @param {Field} field2 (optional)
51274 * @param {Field} etc (optional)
51275 * @return Column The column container object
51277 column : function(c){
51278 var col = new Roo.form.Column(c);
51280 if(arguments.length > 1){ // duplicate code required because of Opera
51281 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
51288 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
51289 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
51290 * until end() is called.
51291 * @param {Object} config The config to pass to the fieldset
51292 * @param {Field} field1 (optional)
51293 * @param {Field} field2 (optional)
51294 * @param {Field} etc (optional)
51295 * @return FieldSet The fieldset container object
51297 fieldset : function(c){
51298 var fs = new Roo.form.FieldSet(c);
51300 if(arguments.length > 1){ // duplicate code required because of Opera
51301 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
51308 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
51309 * fields are added and the container is closed. If no fields are passed the container remains open
51310 * until end() is called.
51311 * @param {Object} config The config to pass to the Layout
51312 * @param {Field} field1 (optional)
51313 * @param {Field} field2 (optional)
51314 * @param {Field} etc (optional)
51315 * @return Layout The container object
51317 container : function(c){
51318 var l = new Roo.form.Layout(c);
51320 if(arguments.length > 1){ // duplicate code required because of Opera
51321 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
51328 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
51329 * @param {Object} container A Roo.form.Layout or subclass of Layout
51330 * @return {Form} this
51332 start : function(c){
51333 // cascade label info
51334 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
51335 this.active.stack.push(c);
51336 c.ownerCt = this.active;
51342 * Closes the current open container
51343 * @return {Form} this
51346 if(this.active == this.root){
51349 this.active = this.active.ownerCt;
51354 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
51355 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
51356 * as the label of the field.
51357 * @param {Field} field1
51358 * @param {Field} field2 (optional)
51359 * @param {Field} etc. (optional)
51360 * @return {Form} this
51363 this.active.stack.push.apply(this.active.stack, arguments);
51364 this.allItems.push.apply(this.allItems,arguments);
51366 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
51367 if(a[i].isFormField){
51372 Roo.form.Form.superclass.add.apply(this, r);
51382 * Find any element that has been added to a form, using it's ID or name
51383 * This can include framesets, columns etc. along with regular fields..
51384 * @param {String} id - id or name to find.
51386 * @return {Element} e - or false if nothing found.
51388 findbyId : function(id)
51394 Roo.each(this.allItems, function(f){
51395 if (f.id == id || f.name == id ){
51406 * Render this form into the passed container. This should only be called once!
51407 * @param {String/HTMLElement/Element} container The element this component should be rendered into
51408 * @return {Form} this
51410 render : function(ct)
51416 var o = this.autoCreate || {
51418 method : this.method || 'POST',
51419 id : this.id || Roo.id()
51421 this.initEl(ct.createChild(o));
51423 this.root.render(this.el);
51427 this.items.each(function(f){
51428 f.render('x-form-el-'+f.id);
51431 if(this.buttons.length > 0){
51432 // tables are required to maintain order and for correct IE layout
51433 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
51434 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
51435 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
51437 var tr = tb.getElementsByTagName('tr')[0];
51438 for(var i = 0, len = this.buttons.length; i < len; i++) {
51439 var b = this.buttons[i];
51440 var td = document.createElement('td');
51441 td.className = 'x-form-btn-td';
51442 b.render(tr.appendChild(td));
51445 if(this.monitorValid){ // initialize after render
51446 this.startMonitoring();
51448 this.fireEvent('rendered', this);
51453 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
51454 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
51455 * object or a valid Roo.DomHelper element config
51456 * @param {Function} handler The function called when the button is clicked
51457 * @param {Object} scope (optional) The scope of the handler function
51458 * @return {Roo.Button}
51460 addButton : function(config, handler, scope){
51464 minWidth: this.minButtonWidth,
51467 if(typeof config == "string"){
51470 Roo.apply(bc, config);
51472 var btn = new Roo.Button(null, bc);
51473 this.buttons.push(btn);
51478 * Adds a series of form elements (using the xtype property as the factory method.
51479 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
51480 * @param {Object} config
51483 addxtype : function()
51485 var ar = Array.prototype.slice.call(arguments, 0);
51487 for(var i = 0; i < ar.length; i++) {
51489 continue; // skip -- if this happends something invalid got sent, we
51490 // should ignore it, as basically that interface element will not show up
51491 // and that should be pretty obvious!!
51494 if (Roo.form[ar[i].xtype]) {
51496 var fe = Roo.factory(ar[i], Roo.form);
51502 fe.store.form = this;
51507 this.allItems.push(fe);
51508 if (fe.items && fe.addxtype) {
51509 fe.addxtype.apply(fe, fe.items);
51519 // console.log('adding ' + ar[i].xtype);
51521 if (ar[i].xtype == 'Button') {
51522 //console.log('adding button');
51523 //console.log(ar[i]);
51524 this.addButton(ar[i]);
51525 this.allItems.push(fe);
51529 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
51530 alert('end is not supported on xtype any more, use items');
51532 // //console.log('adding end');
51540 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
51541 * option "monitorValid"
51543 startMonitoring : function(){
51546 Roo.TaskMgr.start({
51547 run : this.bindHandler,
51548 interval : this.monitorPoll || 200,
51555 * Stops monitoring of the valid state of this form
51557 stopMonitoring : function(){
51558 this.bound = false;
51562 bindHandler : function(){
51564 return false; // stops binding
51567 this.items.each(function(f){
51568 if(!f.isValid(true)){
51573 for(var i = 0, len = this.buttons.length; i < len; i++){
51574 var btn = this.buttons[i];
51575 if(btn.formBind === true && btn.disabled === valid){
51576 btn.setDisabled(!valid);
51579 this.fireEvent('clientvalidation', this, valid);
51593 Roo.Form = Roo.form.Form;
51596 * Ext JS Library 1.1.1
51597 * Copyright(c) 2006-2007, Ext JS, LLC.
51599 * Originally Released Under LGPL - original licence link has changed is not relivant.
51602 * <script type="text/javascript">
51605 // as we use this in bootstrap.
51606 Roo.namespace('Roo.form');
51608 * @class Roo.form.Action
51609 * Internal Class used to handle form actions
51611 * @param {Roo.form.BasicForm} el The form element or its id
51612 * @param {Object} config Configuration options
51617 // define the action interface
51618 Roo.form.Action = function(form, options){
51620 this.options = options || {};
51623 * Client Validation Failed
51626 Roo.form.Action.CLIENT_INVALID = 'client';
51628 * Server Validation Failed
51631 Roo.form.Action.SERVER_INVALID = 'server';
51633 * Connect to Server Failed
51636 Roo.form.Action.CONNECT_FAILURE = 'connect';
51638 * Reading Data from Server Failed
51641 Roo.form.Action.LOAD_FAILURE = 'load';
51643 Roo.form.Action.prototype = {
51645 failureType : undefined,
51646 response : undefined,
51647 result : undefined,
51649 // interface method
51650 run : function(options){
51654 // interface method
51655 success : function(response){
51659 // interface method
51660 handleResponse : function(response){
51664 // default connection failure
51665 failure : function(response){
51667 this.response = response;
51668 this.failureType = Roo.form.Action.CONNECT_FAILURE;
51669 this.form.afterAction(this, false);
51672 processResponse : function(response){
51673 this.response = response;
51674 if(!response.responseText){
51677 this.result = this.handleResponse(response);
51678 return this.result;
51681 // utility functions used internally
51682 getUrl : function(appendParams){
51683 var url = this.options.url || this.form.url || this.form.el.dom.action;
51685 var p = this.getParams();
51687 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
51693 getMethod : function(){
51694 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
51697 getParams : function(){
51698 var bp = this.form.baseParams;
51699 var p = this.options.params;
51701 if(typeof p == "object"){
51702 p = Roo.urlEncode(Roo.applyIf(p, bp));
51703 }else if(typeof p == 'string' && bp){
51704 p += '&' + Roo.urlEncode(bp);
51707 p = Roo.urlEncode(bp);
51712 createCallback : function(){
51714 success: this.success,
51715 failure: this.failure,
51717 timeout: (this.form.timeout*1000),
51718 upload: this.form.fileUpload ? this.success : undefined
51723 Roo.form.Action.Submit = function(form, options){
51724 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
51727 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
51730 haveProgress : false,
51731 uploadComplete : false,
51733 // uploadProgress indicator.
51734 uploadProgress : function()
51736 if (!this.form.progressUrl) {
51740 if (!this.haveProgress) {
51741 Roo.MessageBox.progress("Uploading", "Uploading");
51743 if (this.uploadComplete) {
51744 Roo.MessageBox.hide();
51748 this.haveProgress = true;
51750 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
51752 var c = new Roo.data.Connection();
51754 url : this.form.progressUrl,
51759 success : function(req){
51760 //console.log(data);
51764 rdata = Roo.decode(req.responseText)
51766 Roo.log("Invalid data from server..");
51770 if (!rdata || !rdata.success) {
51772 Roo.MessageBox.alert(Roo.encode(rdata));
51775 var data = rdata.data;
51777 if (this.uploadComplete) {
51778 Roo.MessageBox.hide();
51783 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
51784 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
51787 this.uploadProgress.defer(2000,this);
51790 failure: function(data) {
51791 Roo.log('progress url failed ');
51802 // run get Values on the form, so it syncs any secondary forms.
51803 this.form.getValues();
51805 var o = this.options;
51806 var method = this.getMethod();
51807 var isPost = method == 'POST';
51808 if(o.clientValidation === false || this.form.isValid()){
51810 if (this.form.progressUrl) {
51811 this.form.findField('UPLOAD_IDENTIFIER').setValue(
51812 (new Date() * 1) + '' + Math.random());
51817 Roo.Ajax.request(Roo.apply(this.createCallback(), {
51818 form:this.form.el.dom,
51819 url:this.getUrl(!isPost),
51821 params:isPost ? this.getParams() : null,
51822 isUpload: this.form.fileUpload,
51823 formData : this.form.formData
51826 this.uploadProgress();
51828 }else if (o.clientValidation !== false){ // client validation failed
51829 this.failureType = Roo.form.Action.CLIENT_INVALID;
51830 this.form.afterAction(this, false);
51834 success : function(response)
51836 this.uploadComplete= true;
51837 if (this.haveProgress) {
51838 Roo.MessageBox.hide();
51842 var result = this.processResponse(response);
51843 if(result === true || result.success){
51844 this.form.afterAction(this, true);
51848 this.form.markInvalid(result.errors);
51849 this.failureType = Roo.form.Action.SERVER_INVALID;
51851 this.form.afterAction(this, false);
51853 failure : function(response)
51855 this.uploadComplete= true;
51856 if (this.haveProgress) {
51857 Roo.MessageBox.hide();
51860 this.response = response;
51861 this.failureType = Roo.form.Action.CONNECT_FAILURE;
51862 this.form.afterAction(this, false);
51865 handleResponse : function(response){
51866 if(this.form.errorReader){
51867 var rs = this.form.errorReader.read(response);
51870 for(var i = 0, len = rs.records.length; i < len; i++) {
51871 var r = rs.records[i];
51872 errors[i] = r.data;
51875 if(errors.length < 1){
51879 success : rs.success,
51885 ret = Roo.decode(response.responseText);
51889 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
51899 Roo.form.Action.Load = function(form, options){
51900 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
51901 this.reader = this.form.reader;
51904 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
51909 Roo.Ajax.request(Roo.apply(
51910 this.createCallback(), {
51911 method:this.getMethod(),
51912 url:this.getUrl(false),
51913 params:this.getParams()
51917 success : function(response){
51919 var result = this.processResponse(response);
51920 if(result === true || !result.success || !result.data){
51921 this.failureType = Roo.form.Action.LOAD_FAILURE;
51922 this.form.afterAction(this, false);
51925 this.form.clearInvalid();
51926 this.form.setValues(result.data);
51927 this.form.afterAction(this, true);
51930 handleResponse : function(response){
51931 if(this.form.reader){
51932 var rs = this.form.reader.read(response);
51933 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
51935 success : rs.success,
51939 return Roo.decode(response.responseText);
51943 Roo.form.Action.ACTION_TYPES = {
51944 'load' : Roo.form.Action.Load,
51945 'submit' : Roo.form.Action.Submit
51948 * Ext JS Library 1.1.1
51949 * Copyright(c) 2006-2007, Ext JS, LLC.
51951 * Originally Released Under LGPL - original licence link has changed is not relivant.
51954 * <script type="text/javascript">
51958 * @class Roo.form.Layout
51959 * @extends Roo.Component
51960 * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem Roo.form.FieldSet
51961 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
51963 * @param {Object} config Configuration options
51965 Roo.form.Layout = function(config){
51967 if (config.items) {
51968 xitems = config.items;
51969 delete config.items;
51971 Roo.form.Layout.superclass.constructor.call(this, config);
51973 Roo.each(xitems, this.addxtype, this);
51977 Roo.extend(Roo.form.Layout, Roo.Component, {
51979 * @cfg {String/Object} autoCreate
51980 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
51983 * @cfg {String/Object/Function} style
51984 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
51985 * a function which returns such a specification.
51988 * @cfg {String} labelAlign
51989 * Valid values are "left," "top" and "right" (defaults to "left")
51992 * @cfg {Number} labelWidth
51993 * Fixed width in pixels of all field labels (defaults to undefined)
51996 * @cfg {Boolean} clear
51997 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
52001 * @cfg {String} labelSeparator
52002 * The separator to use after field labels (defaults to ':')
52004 labelSeparator : ':',
52006 * @cfg {Boolean} hideLabels
52007 * True to suppress the display of field labels in this layout (defaults to false)
52009 hideLabels : false,
52012 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
52017 onRender : function(ct, position){
52018 if(this.el){ // from markup
52019 this.el = Roo.get(this.el);
52020 }else { // generate
52021 var cfg = this.getAutoCreate();
52022 this.el = ct.createChild(cfg, position);
52025 this.el.applyStyles(this.style);
52027 if(this.labelAlign){
52028 this.el.addClass('x-form-label-'+this.labelAlign);
52030 if(this.hideLabels){
52031 this.labelStyle = "display:none";
52032 this.elementStyle = "padding-left:0;";
52034 if(typeof this.labelWidth == 'number'){
52035 this.labelStyle = "width:"+this.labelWidth+"px;";
52036 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
52038 if(this.labelAlign == 'top'){
52039 this.labelStyle = "width:auto;";
52040 this.elementStyle = "padding-left:0;";
52043 var stack = this.stack;
52044 var slen = stack.length;
52046 if(!this.fieldTpl){
52047 var t = new Roo.Template(
52048 '<div class="x-form-item {5}">',
52049 '<label for="{0}" style="{2}">{1}{4}</label>',
52050 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
52052 '</div><div class="x-form-clear-left"></div>'
52054 t.disableFormats = true;
52056 Roo.form.Layout.prototype.fieldTpl = t;
52058 for(var i = 0; i < slen; i++) {
52059 if(stack[i].isFormField){
52060 this.renderField(stack[i]);
52062 this.renderComponent(stack[i]);
52067 this.el.createChild({cls:'x-form-clear'});
52072 renderField : function(f){
52073 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
52076 f.labelStyle||this.labelStyle||'', //2
52077 this.elementStyle||'', //3
52078 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
52079 f.itemCls||this.itemCls||'' //5
52080 ], true).getPrevSibling());
52084 renderComponent : function(c){
52085 c.render(c.isLayout ? this.el : this.el.createChild());
52088 * Adds a object form elements (using the xtype property as the factory method.)
52089 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
52090 * @param {Object} config
52092 addxtype : function(o)
52094 // create the lement.
52095 o.form = this.form;
52096 var fe = Roo.factory(o, Roo.form);
52097 this.form.allItems.push(fe);
52098 this.stack.push(fe);
52100 if (fe.isFormField) {
52101 this.form.items.add(fe);
52109 * @class Roo.form.Column
52110 * @extends Roo.form.Layout
52111 * @children Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem Roo.form.FieldSet
52112 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
52114 * @param {Object} config Configuration options
52116 Roo.form.Column = function(config){
52117 Roo.form.Column.superclass.constructor.call(this, config);
52120 Roo.extend(Roo.form.Column, Roo.form.Layout, {
52122 * @cfg {Number/String} width
52123 * The fixed width of the column in pixels or CSS value (defaults to "auto")
52126 * @cfg {String/Object} autoCreate
52127 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
52131 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
52134 onRender : function(ct, position){
52135 Roo.form.Column.superclass.onRender.call(this, ct, position);
52137 this.el.setWidth(this.width);
52144 * @class Roo.form.Row
52145 * @extends Roo.form.Layout
52146 * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem Roo.form.FieldSet
52147 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
52149 * @param {Object} config Configuration options
52153 Roo.form.Row = function(config){
52154 Roo.form.Row.superclass.constructor.call(this, config);
52157 Roo.extend(Roo.form.Row, Roo.form.Layout, {
52159 * @cfg {Number/String} width
52160 * The fixed width of the column in pixels or CSS value (defaults to "auto")
52163 * @cfg {Number/String} height
52164 * The fixed height of the column in pixels or CSS value (defaults to "auto")
52166 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
52170 onRender : function(ct, position){
52171 //console.log('row render');
52173 var t = new Roo.Template(
52174 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
52175 '<label for="{0}" style="{2}">{1}{4}</label>',
52176 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
52180 t.disableFormats = true;
52182 Roo.form.Layout.prototype.rowTpl = t;
52184 this.fieldTpl = this.rowTpl;
52186 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
52187 var labelWidth = 100;
52189 if ((this.labelAlign != 'top')) {
52190 if (typeof this.labelWidth == 'number') {
52191 labelWidth = this.labelWidth
52193 this.padWidth = 20 + labelWidth;
52197 Roo.form.Column.superclass.onRender.call(this, ct, position);
52199 this.el.setWidth(this.width);
52202 this.el.setHeight(this.height);
52207 renderField : function(f){
52208 f.fieldEl = this.fieldTpl.append(this.el, [
52209 f.id, f.fieldLabel,
52210 f.labelStyle||this.labelStyle||'',
52211 this.elementStyle||'',
52212 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
52213 f.itemCls||this.itemCls||'',
52214 f.width ? f.width + this.padWidth : 160 + this.padWidth
52221 * @class Roo.form.FieldSet
52222 * @extends Roo.form.Layout
52223 * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
52224 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
52226 * @param {Object} config Configuration options
52228 Roo.form.FieldSet = function(config){
52229 Roo.form.FieldSet.superclass.constructor.call(this, config);
52232 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
52234 * @cfg {String} legend
52235 * The text to display as the legend for the FieldSet (defaults to '')
52238 * @cfg {String/Object} autoCreate
52239 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
52243 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
52246 onRender : function(ct, position){
52247 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
52249 this.setLegend(this.legend);
52254 setLegend : function(text){
52256 this.el.child('legend').update(text);
52261 * Ext JS Library 1.1.1
52262 * Copyright(c) 2006-2007, Ext JS, LLC.
52264 * Originally Released Under LGPL - original licence link has changed is not relivant.
52267 * <script type="text/javascript">
52270 * @class Roo.form.VTypes
52271 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
52274 Roo.form.VTypes = function(){
52275 // closure these in so they are only created once.
52276 var alpha = /^[a-zA-Z_]+$/;
52277 var alphanum = /^[a-zA-Z0-9_]+$/;
52278 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
52279 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
52281 // All these messages and functions are configurable
52284 * The function used to validate email addresses
52285 * @param {String} value The email address
52287 'email' : function(v){
52288 return email.test(v);
52291 * The error text to display when the email validation function returns false
52294 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
52296 * The keystroke filter mask to be applied on email input
52299 'emailMask' : /[a-z0-9_\.\-@]/i,
52302 * The function used to validate URLs
52303 * @param {String} value The URL
52305 'url' : function(v){
52306 return url.test(v);
52309 * The error text to display when the url validation function returns false
52312 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
52315 * The function used to validate alpha values
52316 * @param {String} value The value
52318 'alpha' : function(v){
52319 return alpha.test(v);
52322 * The error text to display when the alpha validation function returns false
52325 'alphaText' : 'This field should only contain letters and _',
52327 * The keystroke filter mask to be applied on alpha input
52330 'alphaMask' : /[a-z_]/i,
52333 * The function used to validate alphanumeric values
52334 * @param {String} value The value
52336 'alphanum' : function(v){
52337 return alphanum.test(v);
52340 * The error text to display when the alphanumeric validation function returns false
52343 'alphanumText' : 'This field should only contain letters, numbers and _',
52345 * The keystroke filter mask to be applied on alphanumeric input
52348 'alphanumMask' : /[a-z0-9_]/i
52350 }();//<script type="text/javascript">
52353 * @class Roo.form.FCKeditor
52354 * @extends Roo.form.TextArea
52355 * Wrapper around the FCKEditor http://www.fckeditor.net
52357 * Creates a new FCKeditor
52358 * @param {Object} config Configuration options
52360 Roo.form.FCKeditor = function(config){
52361 Roo.form.FCKeditor.superclass.constructor.call(this, config);
52364 * @event editorinit
52365 * Fired when the editor is initialized - you can add extra handlers here..
52366 * @param {FCKeditor} this
52367 * @param {Object} the FCK object.
52374 Roo.form.FCKeditor.editors = { };
52375 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
52377 //defaultAutoCreate : {
52378 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
52382 * @cfg {Object} fck options - see fck manual for details.
52387 * @cfg {Object} fck toolbar set (Basic or Default)
52389 toolbarSet : 'Basic',
52391 * @cfg {Object} fck BasePath
52393 basePath : '/fckeditor/',
52401 onRender : function(ct, position)
52404 this.defaultAutoCreate = {
52406 style:"width:300px;height:60px;",
52407 autocomplete: "new-password"
52410 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
52413 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
52414 if(this.preventScrollbars){
52415 this.el.setStyle("overflow", "hidden");
52417 this.el.setHeight(this.growMin);
52420 //console.log('onrender' + this.getId() );
52421 Roo.form.FCKeditor.editors[this.getId()] = this;
52424 this.replaceTextarea() ;
52428 getEditor : function() {
52429 return this.fckEditor;
52432 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
52433 * @param {Mixed} value The value to set
52437 setValue : function(value)
52439 //console.log('setValue: ' + value);
52441 if(typeof(value) == 'undefined') { // not sure why this is happending...
52444 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
52446 //if(!this.el || !this.getEditor()) {
52447 // this.value = value;
52448 //this.setValue.defer(100,this,[value]);
52452 if(!this.getEditor()) {
52456 this.getEditor().SetData(value);
52463 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
52464 * @return {Mixed} value The field value
52466 getValue : function()
52469 if (this.frame && this.frame.dom.style.display == 'none') {
52470 return Roo.form.FCKeditor.superclass.getValue.call(this);
52473 if(!this.el || !this.getEditor()) {
52475 // this.getValue.defer(100,this);
52480 var value=this.getEditor().GetData();
52481 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
52482 return Roo.form.FCKeditor.superclass.getValue.call(this);
52488 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
52489 * @return {Mixed} value The field value
52491 getRawValue : function()
52493 if (this.frame && this.frame.dom.style.display == 'none') {
52494 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
52497 if(!this.el || !this.getEditor()) {
52498 //this.getRawValue.defer(100,this);
52505 var value=this.getEditor().GetData();
52506 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
52507 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
52511 setSize : function(w,h) {
52515 //if (this.frame && this.frame.dom.style.display == 'none') {
52516 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
52519 //if(!this.el || !this.getEditor()) {
52520 // this.setSize.defer(100,this, [w,h]);
52526 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
52528 this.frame.dom.setAttribute('width', w);
52529 this.frame.dom.setAttribute('height', h);
52530 this.frame.setSize(w,h);
52534 toggleSourceEdit : function(value) {
52538 this.el.dom.style.display = value ? '' : 'none';
52539 this.frame.dom.style.display = value ? 'none' : '';
52544 focus: function(tag)
52546 if (this.frame.dom.style.display == 'none') {
52547 return Roo.form.FCKeditor.superclass.focus.call(this);
52549 if(!this.el || !this.getEditor()) {
52550 this.focus.defer(100,this, [tag]);
52557 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
52558 this.getEditor().Focus();
52560 if (!this.getEditor().Selection.GetSelection()) {
52561 this.focus.defer(100,this, [tag]);
52566 var r = this.getEditor().EditorDocument.createRange();
52567 r.setStart(tgs[0],0);
52568 r.setEnd(tgs[0],0);
52569 this.getEditor().Selection.GetSelection().removeAllRanges();
52570 this.getEditor().Selection.GetSelection().addRange(r);
52571 this.getEditor().Focus();
52578 replaceTextarea : function()
52580 if ( document.getElementById( this.getId() + '___Frame' ) ) {
52583 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
52585 // We must check the elements firstly using the Id and then the name.
52586 var oTextarea = document.getElementById( this.getId() );
52588 var colElementsByName = document.getElementsByName( this.getId() ) ;
52590 oTextarea.style.display = 'none' ;
52592 if ( oTextarea.tabIndex ) {
52593 this.TabIndex = oTextarea.tabIndex ;
52596 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
52597 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
52598 this.frame = Roo.get(this.getId() + '___Frame')
52601 _getConfigHtml : function()
52605 for ( var o in this.fckconfig ) {
52606 sConfig += sConfig.length > 0 ? '&' : '';
52607 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
52610 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
52614 _getIFrameHtml : function()
52616 var sFile = 'fckeditor.html' ;
52617 /* no idea what this is about..
52620 if ( (/fcksource=true/i).test( window.top.location.search ) )
52621 sFile = 'fckeditor.original.html' ;
52626 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
52627 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
52630 var html = '<iframe id="' + this.getId() +
52631 '___Frame" src="' + sLink +
52632 '" width="' + this.width +
52633 '" height="' + this.height + '"' +
52634 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
52635 ' frameborder="0" scrolling="no"></iframe>' ;
52640 _insertHtmlBefore : function( html, element )
52642 if ( element.insertAdjacentHTML ) {
52644 element.insertAdjacentHTML( 'beforeBegin', html ) ;
52646 var oRange = document.createRange() ;
52647 oRange.setStartBefore( element ) ;
52648 var oFragment = oRange.createContextualFragment( html );
52649 element.parentNode.insertBefore( oFragment, element ) ;
52662 //Roo.reg('fckeditor', Roo.form.FCKeditor);
52664 function FCKeditor_OnComplete(editorInstance){
52665 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
52666 f.fckEditor = editorInstance;
52667 //console.log("loaded");
52668 f.fireEvent('editorinit', f, editorInstance);
52688 //<script type="text/javascript">
52690 * @class Roo.form.GridField
52691 * @extends Roo.form.Field
52692 * Embed a grid (or editable grid into a form)
52695 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
52697 * xgrid.store = Roo.data.Store
52698 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
52699 * xgrid.store.reader = Roo.data.JsonReader
52703 * Creates a new GridField
52704 * @param {Object} config Configuration options
52706 Roo.form.GridField = function(config){
52707 Roo.form.GridField.superclass.constructor.call(this, config);
52711 Roo.extend(Roo.form.GridField, Roo.form.Field, {
52713 * @cfg {Number} width - used to restrict width of grid..
52717 * @cfg {Number} height - used to restrict height of grid..
52721 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
52727 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
52728 * {tag: "input", type: "checkbox", autocomplete: "off"})
52730 // defaultAutoCreate : { tag: 'div' },
52731 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
52733 * @cfg {String} addTitle Text to include for adding a title.
52737 onResize : function(){
52738 Roo.form.Field.superclass.onResize.apply(this, arguments);
52741 initEvents : function(){
52742 // Roo.form.Checkbox.superclass.initEvents.call(this);
52743 // has no events...
52748 getResizeEl : function(){
52752 getPositionEl : function(){
52757 onRender : function(ct, position){
52759 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
52760 var style = this.style;
52763 Roo.form.GridField.superclass.onRender.call(this, ct, position);
52764 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
52765 this.viewEl = this.wrap.createChild({ tag: 'div' });
52767 this.viewEl.applyStyles(style);
52770 this.viewEl.setWidth(this.width);
52773 this.viewEl.setHeight(this.height);
52775 //if(this.inputValue !== undefined){
52776 //this.setValue(this.value);
52779 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
52782 this.grid.render();
52783 this.grid.getDataSource().on('remove', this.refreshValue, this);
52784 this.grid.getDataSource().on('update', this.refreshValue, this);
52785 this.grid.on('afteredit', this.refreshValue, this);
52791 * Sets the value of the item.
52792 * @param {String} either an object or a string..
52794 setValue : function(v){
52796 v = v || []; // empty set..
52797 // this does not seem smart - it really only affects memoryproxy grids..
52798 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
52799 var ds = this.grid.getDataSource();
52800 // assumes a json reader..
52802 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
52803 ds.loadData( data);
52805 // clear selection so it does not get stale.
52806 if (this.grid.sm) {
52807 this.grid.sm.clearSelections();
52810 Roo.form.GridField.superclass.setValue.call(this, v);
52811 this.refreshValue();
52812 // should load data in the grid really....
52816 refreshValue: function() {
52818 this.grid.getDataSource().each(function(r) {
52821 this.el.dom.value = Roo.encode(val);
52829 * Ext JS Library 1.1.1
52830 * Copyright(c) 2006-2007, Ext JS, LLC.
52832 * Originally Released Under LGPL - original licence link has changed is not relivant.
52835 * <script type="text/javascript">
52838 * @class Roo.form.DisplayField
52839 * @extends Roo.form.Field
52840 * A generic Field to display non-editable data.
52841 * @cfg {Boolean} closable (true|false) default false
52843 * Creates a new Display Field item.
52844 * @param {Object} config Configuration options
52846 Roo.form.DisplayField = function(config){
52847 Roo.form.DisplayField.superclass.constructor.call(this, config);
52852 * Fires after the click the close btn
52853 * @param {Roo.form.DisplayField} this
52859 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
52860 inputType: 'hidden',
52866 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
52868 focusClass : undefined,
52870 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
52872 fieldClass: 'x-form-field',
52875 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
52877 valueRenderer: undefined,
52881 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
52882 * {tag: "input", type: "checkbox", autocomplete: "off"})
52885 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
52889 onResize : function(){
52890 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
52894 initEvents : function(){
52895 // Roo.form.Checkbox.superclass.initEvents.call(this);
52896 // has no events...
52899 this.closeEl.on('click', this.onClose, this);
52905 getResizeEl : function(){
52909 getPositionEl : function(){
52914 onRender : function(ct, position){
52916 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
52917 //if(this.inputValue !== undefined){
52918 this.wrap = this.el.wrap();
52920 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
52923 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
52926 if (this.bodyStyle) {
52927 this.viewEl.applyStyles(this.bodyStyle);
52929 //this.viewEl.setStyle('padding', '2px');
52931 this.setValue(this.value);
52936 initValue : Roo.emptyFn,
52941 onClick : function(){
52946 * Sets the checked state of the checkbox.
52947 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
52949 setValue : function(v){
52951 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
52952 // this might be called before we have a dom element..
52953 if (!this.viewEl) {
52956 this.viewEl.dom.innerHTML = html;
52957 Roo.form.DisplayField.superclass.setValue.call(this, v);
52961 onClose : function(e)
52963 e.preventDefault();
52965 this.fireEvent('close', this);
52974 * @class Roo.form.DayPicker
52975 * @extends Roo.form.Field
52976 * A Day picker show [M] [T] [W] ....
52978 * Creates a new Day Picker
52979 * @param {Object} config Configuration options
52981 Roo.form.DayPicker= function(config){
52982 Roo.form.DayPicker.superclass.constructor.call(this, config);
52986 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
52988 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
52990 focusClass : undefined,
52992 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
52994 fieldClass: "x-form-field",
52997 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
52998 * {tag: "input", type: "checkbox", autocomplete: "off"})
53000 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
53003 actionMode : 'viewEl',
53007 inputType : 'hidden',
53010 inputElement: false, // real input element?
53011 basedOn: false, // ????
53013 isFormField: true, // not sure where this is needed!!!!
53015 onResize : function(){
53016 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
53017 if(!this.boxLabel){
53018 this.el.alignTo(this.wrap, 'c-c');
53022 initEvents : function(){
53023 Roo.form.Checkbox.superclass.initEvents.call(this);
53024 this.el.on("click", this.onClick, this);
53025 this.el.on("change", this.onClick, this);
53029 getResizeEl : function(){
53033 getPositionEl : function(){
53039 onRender : function(ct, position){
53040 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
53042 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
53044 var r1 = '<table><tr>';
53045 var r2 = '<tr class="x-form-daypick-icons">';
53046 for (var i=0; i < 7; i++) {
53047 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
53048 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
53051 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
53052 viewEl.select('img').on('click', this.onClick, this);
53053 this.viewEl = viewEl;
53056 // this will not work on Chrome!!!
53057 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
53058 this.el.on('propertychange', this.setFromHidden, this); //ie
53066 initValue : Roo.emptyFn,
53069 * Returns the checked state of the checkbox.
53070 * @return {Boolean} True if checked, else false
53072 getValue : function(){
53073 return this.el.dom.value;
53078 onClick : function(e){
53079 //this.setChecked(!this.checked);
53080 Roo.get(e.target).toggleClass('x-menu-item-checked');
53081 this.refreshValue();
53082 //if(this.el.dom.checked != this.checked){
53083 // this.setValue(this.el.dom.checked);
53088 refreshValue : function()
53091 this.viewEl.select('img',true).each(function(e,i,n) {
53092 val += e.is(".x-menu-item-checked") ? String(n) : '';
53094 this.setValue(val, true);
53098 * Sets the checked state of the checkbox.
53099 * On is always based on a string comparison between inputValue and the param.
53100 * @param {Boolean/String} value - the value to set
53101 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
53103 setValue : function(v,suppressEvent){
53104 if (!this.el.dom) {
53107 var old = this.el.dom.value ;
53108 this.el.dom.value = v;
53109 if (suppressEvent) {
53113 // update display..
53114 this.viewEl.select('img',true).each(function(e,i,n) {
53116 var on = e.is(".x-menu-item-checked");
53117 var newv = v.indexOf(String(n)) > -1;
53119 e.toggleClass('x-menu-item-checked');
53125 this.fireEvent('change', this, v, old);
53130 // handle setting of hidden value by some other method!!?!?
53131 setFromHidden: function()
53136 //console.log("SET FROM HIDDEN");
53137 //alert('setFrom hidden');
53138 this.setValue(this.el.dom.value);
53141 onDestroy : function()
53144 Roo.get(this.viewEl).remove();
53147 Roo.form.DayPicker.superclass.onDestroy.call(this);
53151 * RooJS Library 1.1.1
53152 * Copyright(c) 2008-2011 Alan Knowles
53159 * @class Roo.form.ComboCheck
53160 * @extends Roo.form.ComboBox
53161 * A combobox for multiple select items.
53163 * FIXME - could do with a reset button..
53166 * Create a new ComboCheck
53167 * @param {Object} config Configuration options
53169 Roo.form.ComboCheck = function(config){
53170 Roo.form.ComboCheck.superclass.constructor.call(this, config);
53171 // should verify some data...
53173 // hiddenName = required..
53174 // displayField = required
53175 // valudField == required
53176 var req= [ 'hiddenName', 'displayField', 'valueField' ];
53178 Roo.each(req, function(e) {
53179 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
53180 throw "Roo.form.ComboCheck : missing value for: " + e;
53187 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
53192 selectedClass: 'x-menu-item-checked',
53195 onRender : function(ct, position){
53201 var cls = 'x-combo-list';
53204 this.tpl = new Roo.Template({
53205 html : '<div class="'+cls+'-item x-menu-check-item">' +
53206 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
53207 '<span>{' + this.displayField + '}</span>' +
53214 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
53215 this.view.singleSelect = false;
53216 this.view.multiSelect = true;
53217 this.view.toggleSelect = true;
53218 this.pageTb.add(new Roo.Toolbar.Fill(), {
53221 handler: function()
53228 onViewOver : function(e, t){
53234 onViewClick : function(doFocus,index){
53238 select: function () {
53239 //Roo.log("SELECT CALLED");
53242 selectByValue : function(xv, scrollIntoView){
53243 var ar = this.getValueArray();
53246 Roo.each(ar, function(v) {
53247 if(v === undefined || v === null){
53250 var r = this.findRecord(this.valueField, v);
53252 sels.push(this.store.indexOf(r))
53256 this.view.select(sels);
53262 onSelect : function(record, index){
53263 // Roo.log("onselect Called");
53264 // this is only called by the clear button now..
53265 this.view.clearSelections();
53266 this.setValue('[]');
53267 if (this.value != this.valueBefore) {
53268 this.fireEvent('change', this, this.value, this.valueBefore);
53269 this.valueBefore = this.value;
53272 getValueArray : function()
53277 //Roo.log(this.value);
53278 if (typeof(this.value) == 'undefined') {
53281 var ar = Roo.decode(this.value);
53282 return ar instanceof Array ? ar : []; //?? valid?
53285 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
53290 expand : function ()
53293 Roo.form.ComboCheck.superclass.expand.call(this);
53294 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
53295 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
53300 collapse : function(){
53301 Roo.form.ComboCheck.superclass.collapse.call(this);
53302 var sl = this.view.getSelectedIndexes();
53303 var st = this.store;
53307 Roo.each(sl, function(i) {
53309 nv.push(r.get(this.valueField));
53311 this.setValue(Roo.encode(nv));
53312 if (this.value != this.valueBefore) {
53314 this.fireEvent('change', this, this.value, this.valueBefore);
53315 this.valueBefore = this.value;
53320 setValue : function(v){
53324 var vals = this.getValueArray();
53326 Roo.each(vals, function(k) {
53327 var r = this.findRecord(this.valueField, k);
53329 tv.push(r.data[this.displayField]);
53330 }else if(this.valueNotFoundText !== undefined){
53331 tv.push( this.valueNotFoundText );
53336 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
53337 this.hiddenField.value = v;
53343 * Ext JS Library 1.1.1
53344 * Copyright(c) 2006-2007, Ext JS, LLC.
53346 * Originally Released Under LGPL - original licence link has changed is not relivant.
53349 * <script type="text/javascript">
53353 * @class Roo.form.Signature
53354 * @extends Roo.form.Field
53358 * @param {Object} config Configuration options
53361 Roo.form.Signature = function(config){
53362 Roo.form.Signature.superclass.constructor.call(this, config);
53364 this.addEvents({// not in used??
53367 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
53368 * @param {Roo.form.Signature} combo This combo box
53373 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
53374 * @param {Roo.form.ComboBox} combo This combo box
53375 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
53381 Roo.extend(Roo.form.Signature, Roo.form.Field, {
53383 * @cfg {Object} labels Label to use when rendering a form.
53387 * confirm : "Confirm"
53392 confirm : "Confirm"
53395 * @cfg {Number} width The signature panel width (defaults to 300)
53399 * @cfg {Number} height The signature panel height (defaults to 100)
53403 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
53405 allowBlank : false,
53408 // {Object} signPanel The signature SVG panel element (defaults to {})
53410 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
53411 isMouseDown : false,
53412 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
53413 isConfirmed : false,
53414 // {String} signatureTmp SVG mapping string (defaults to empty string)
53418 defaultAutoCreate : { // modified by initCompnoent..
53424 onRender : function(ct, position){
53426 Roo.form.Signature.superclass.onRender.call(this, ct, position);
53428 this.wrap = this.el.wrap({
53429 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
53432 this.createToolbar(this);
53433 this.signPanel = this.wrap.createChild({
53435 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
53439 this.svgID = Roo.id();
53440 this.svgEl = this.signPanel.createChild({
53441 xmlns : 'http://www.w3.org/2000/svg',
53443 id : this.svgID + "-svg",
53445 height: this.height,
53446 viewBox: '0 0 '+this.width+' '+this.height,
53450 id: this.svgID + "-svg-r",
53452 height: this.height,
53457 id: this.svgID + "-svg-l",
53459 y1: (this.height*0.8), // start set the line in 80% of height
53460 x2: this.width, // end
53461 y2: (this.height*0.8), // end set the line in 80% of height
53463 'stroke-width': "1",
53464 'stroke-dasharray': "3",
53465 'shape-rendering': "crispEdges",
53466 'pointer-events': "none"
53470 id: this.svgID + "-svg-p",
53472 'stroke-width': "3",
53474 'pointer-events': 'none'
53479 this.svgBox = this.svgEl.dom.getScreenCTM();
53481 createSVG : function(){
53482 var svg = this.signPanel;
53483 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
53486 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
53487 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
53488 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
53489 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
53490 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
53491 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
53492 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
53495 isTouchEvent : function(e){
53496 return e.type.match(/^touch/);
53498 getCoords : function (e) {
53499 var pt = this.svgEl.dom.createSVGPoint();
53502 if (this.isTouchEvent(e)) {
53503 pt.x = e.targetTouches[0].clientX;
53504 pt.y = e.targetTouches[0].clientY;
53506 var a = this.svgEl.dom.getScreenCTM();
53507 var b = a.inverse();
53508 var mx = pt.matrixTransform(b);
53509 return mx.x + ',' + mx.y;
53511 //mouse event headler
53512 down : function (e) {
53513 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
53514 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
53516 this.isMouseDown = true;
53518 e.preventDefault();
53520 move : function (e) {
53521 if (this.isMouseDown) {
53522 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
53523 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
53526 e.preventDefault();
53528 up : function (e) {
53529 this.isMouseDown = false;
53530 var sp = this.signatureTmp.split(' ');
53533 if(!sp[sp.length-2].match(/^L/)){
53537 this.signatureTmp = sp.join(" ");
53540 if(this.getValue() != this.signatureTmp){
53541 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
53542 this.isConfirmed = false;
53544 e.preventDefault();
53548 * Protected method that will not generally be called directly. It
53549 * is called when the editor creates its toolbar. Override this method if you need to
53550 * add custom toolbar buttons.
53551 * @param {HtmlEditor} editor
53553 createToolbar : function(editor){
53554 function btn(id, toggle, handler){
53555 var xid = fid + '-'+ id ;
53559 cls : 'x-btn-icon x-edit-'+id,
53560 enableToggle:toggle !== false,
53561 scope: editor, // was editor...
53562 handler:handler||editor.relayBtnCmd,
53563 clickEvent:'mousedown',
53564 tooltip: etb.buttonTips[id] || undefined, ///tips ???
53570 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
53574 cls : ' x-signature-btn x-signature-'+id,
53575 scope: editor, // was editor...
53576 handler: this.reset,
53577 clickEvent:'mousedown',
53578 text: this.labels.clear
53585 cls : ' x-signature-btn x-signature-'+id,
53586 scope: editor, // was editor...
53587 handler: this.confirmHandler,
53588 clickEvent:'mousedown',
53589 text: this.labels.confirm
53596 * when user is clicked confirm then show this image.....
53598 * @return {String} Image Data URI
53600 getImageDataURI : function(){
53601 var svg = this.svgEl.dom.parentNode.innerHTML;
53602 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
53607 * @return {Boolean} this.isConfirmed
53609 getConfirmed : function(){
53610 return this.isConfirmed;
53614 * @return {Number} this.width
53616 getWidth : function(){
53621 * @return {Number} this.height
53623 getHeight : function(){
53624 return this.height;
53627 getSignature : function(){
53628 return this.signatureTmp;
53631 reset : function(){
53632 this.signatureTmp = '';
53633 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
53634 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
53635 this.isConfirmed = false;
53636 Roo.form.Signature.superclass.reset.call(this);
53638 setSignature : function(s){
53639 this.signatureTmp = s;
53640 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
53641 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
53643 this.isConfirmed = false;
53644 Roo.form.Signature.superclass.reset.call(this);
53647 // Roo.log(this.signPanel.dom.contentWindow.up())
53650 setConfirmed : function(){
53654 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
53657 confirmHandler : function(){
53658 if(!this.getSignature()){
53662 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
53663 this.setValue(this.getSignature());
53664 this.isConfirmed = true;
53666 this.fireEvent('confirm', this);
53669 // Subclasses should provide the validation implementation by overriding this
53670 validateValue : function(value){
53671 if(this.allowBlank){
53675 if(this.isConfirmed){
53682 * Ext JS Library 1.1.1
53683 * Copyright(c) 2006-2007, Ext JS, LLC.
53685 * Originally Released Under LGPL - original licence link has changed is not relivant.
53688 * <script type="text/javascript">
53693 * @class Roo.form.ComboBox
53694 * @extends Roo.form.TriggerField
53695 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
53697 * Create a new ComboBox.
53698 * @param {Object} config Configuration options
53700 Roo.form.Select = function(config){
53701 Roo.form.Select.superclass.constructor.call(this, config);
53705 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
53707 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
53710 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
53711 * rendering into an Roo.Editor, defaults to false)
53714 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
53715 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
53718 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
53721 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
53722 * the dropdown list (defaults to undefined, with no header element)
53726 * @cfg {String/Roo.Template} tpl The template to use to render the output
53730 defaultAutoCreate : {tag: "select" },
53732 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
53734 listWidth: undefined,
53736 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
53737 * mode = 'remote' or 'text' if mode = 'local')
53739 displayField: undefined,
53741 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
53742 * mode = 'remote' or 'value' if mode = 'local').
53743 * Note: use of a valueField requires the user make a selection
53744 * in order for a value to be mapped.
53746 valueField: undefined,
53750 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
53751 * field's data value (defaults to the underlying DOM element's name)
53753 hiddenName: undefined,
53755 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
53759 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
53761 selectedClass: 'x-combo-selected',
53763 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
53764 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
53765 * which displays a downward arrow icon).
53767 triggerClass : 'x-form-arrow-trigger',
53769 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
53773 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
53774 * anchor positions (defaults to 'tl-bl')
53776 listAlign: 'tl-bl?',
53778 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
53782 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
53783 * query specified by the allQuery config option (defaults to 'query')
53785 triggerAction: 'query',
53787 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
53788 * (defaults to 4, does not apply if editable = false)
53792 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
53793 * delay (typeAheadDelay) if it matches a known value (defaults to false)
53797 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
53798 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
53802 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
53803 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
53807 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
53808 * when editable = true (defaults to false)
53810 selectOnFocus:false,
53812 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
53814 queryParam: 'query',
53816 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
53817 * when mode = 'remote' (defaults to 'Loading...')
53819 loadingText: 'Loading...',
53821 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
53825 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
53829 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
53830 * traditional select (defaults to true)
53834 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
53838 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
53842 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
53843 * listWidth has a higher value)
53847 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
53848 * allow the user to set arbitrary text into the field (defaults to false)
53850 forceSelection:false,
53852 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
53853 * if typeAhead = true (defaults to 250)
53855 typeAheadDelay : 250,
53857 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
53858 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
53860 valueNotFoundText : undefined,
53863 * @cfg {String} defaultValue The value displayed after loading the store.
53868 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
53870 blockFocus : false,
53873 * @cfg {Boolean} disableClear Disable showing of clear button.
53875 disableClear : false,
53877 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
53879 alwaysQuery : false,
53885 // element that contains real text value.. (when hidden is used..)
53888 onRender : function(ct, position){
53889 Roo.form.Field.prototype.onRender.call(this, ct, position);
53892 this.store.on('beforeload', this.onBeforeLoad, this);
53893 this.store.on('load', this.onLoad, this);
53894 this.store.on('loadexception', this.onLoadException, this);
53895 this.store.load({});
53903 initEvents : function(){
53904 //Roo.form.ComboBox.superclass.initEvents.call(this);
53908 onDestroy : function(){
53911 this.store.un('beforeload', this.onBeforeLoad, this);
53912 this.store.un('load', this.onLoad, this);
53913 this.store.un('loadexception', this.onLoadException, this);
53915 //Roo.form.ComboBox.superclass.onDestroy.call(this);
53919 fireKey : function(e){
53920 if(e.isNavKeyPress() && !this.list.isVisible()){
53921 this.fireEvent("specialkey", this, e);
53926 onResize: function(w, h){
53934 * Allow or prevent the user from directly editing the field text. If false is passed,
53935 * the user will only be able to select from the items defined in the dropdown list. This method
53936 * is the runtime equivalent of setting the 'editable' config option at config time.
53937 * @param {Boolean} value True to allow the user to directly edit the field text
53939 setEditable : function(value){
53944 onBeforeLoad : function(){
53946 Roo.log("Select before load");
53949 this.innerList.update(this.loadingText ?
53950 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
53951 //this.restrictHeight();
53952 this.selectedIndex = -1;
53956 onLoad : function(){
53959 var dom = this.el.dom;
53960 dom.innerHTML = '';
53961 var od = dom.ownerDocument;
53963 if (this.emptyText) {
53964 var op = od.createElement('option');
53965 op.setAttribute('value', '');
53966 op.innerHTML = String.format('{0}', this.emptyText);
53967 dom.appendChild(op);
53969 if(this.store.getCount() > 0){
53971 var vf = this.valueField;
53972 var df = this.displayField;
53973 this.store.data.each(function(r) {
53974 // which colmsn to use... testing - cdoe / title..
53975 var op = od.createElement('option');
53976 op.setAttribute('value', r.data[vf]);
53977 op.innerHTML = String.format('{0}', r.data[df]);
53978 dom.appendChild(op);
53980 if (typeof(this.defaultValue != 'undefined')) {
53981 this.setValue(this.defaultValue);
53986 //this.onEmptyResults();
53991 onLoadException : function()
53993 dom.innerHTML = '';
53995 Roo.log("Select on load exception");
53999 Roo.log(this.store.reader.jsonData);
54000 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
54001 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
54007 onTypeAhead : function(){
54012 onSelect : function(record, index){
54013 Roo.log('on select?');
54015 if(this.fireEvent('beforeselect', this, record, index) !== false){
54016 this.setFromData(index > -1 ? record.data : false);
54018 this.fireEvent('select', this, record, index);
54023 * Returns the currently selected field value or empty string if no value is set.
54024 * @return {String} value The selected value
54026 getValue : function(){
54027 var dom = this.el.dom;
54028 this.value = dom.options[dom.selectedIndex].value;
54034 * Clears any text/value currently set in the field
54036 clearValue : function(){
54038 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
54043 * Sets the specified value into the field. If the value finds a match, the corresponding record text
54044 * will be displayed in the field. If the value does not match the data value of an existing item,
54045 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
54046 * Otherwise the field will be blank (although the value will still be set).
54047 * @param {String} value The value to match
54049 setValue : function(v){
54050 var d = this.el.dom;
54051 for (var i =0; i < d.options.length;i++) {
54052 if (v == d.options[i].value) {
54053 d.selectedIndex = i;
54061 * @property {Object} the last set data for the element
54066 * Sets the value of the field based on a object which is related to the record format for the store.
54067 * @param {Object} value the value to set as. or false on reset?
54069 setFromData : function(o){
54070 Roo.log('setfrom data?');
54076 reset : function(){
54080 findRecord : function(prop, value){
54085 if(this.store.getCount() > 0){
54086 this.store.each(function(r){
54087 if(r.data[prop] == value){
54097 getName: function()
54099 // returns hidden if it's set..
54100 if (!this.rendered) {return ''};
54101 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
54109 onEmptyResults : function(){
54110 Roo.log('empty results');
54115 * Returns true if the dropdown list is expanded, else false.
54117 isExpanded : function(){
54122 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
54123 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
54124 * @param {String} value The data value of the item to select
54125 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
54126 * selected item if it is not currently in view (defaults to true)
54127 * @return {Boolean} True if the value matched an item in the list, else false
54129 selectByValue : function(v, scrollIntoView){
54130 Roo.log('select By Value');
54133 if(v !== undefined && v !== null){
54134 var r = this.findRecord(this.valueField || this.displayField, v);
54136 this.select(this.store.indexOf(r), scrollIntoView);
54144 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
54145 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
54146 * @param {Number} index The zero-based index of the list item to select
54147 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
54148 * selected item if it is not currently in view (defaults to true)
54150 select : function(index, scrollIntoView){
54151 Roo.log('select ');
54154 this.selectedIndex = index;
54155 this.view.select(index);
54156 if(scrollIntoView !== false){
54157 var el = this.view.getNode(index);
54159 this.innerList.scrollChildIntoView(el, false);
54167 validateBlur : function(){
54174 initQuery : function(){
54175 this.doQuery(this.getRawValue());
54179 doForce : function(){
54180 if(this.el.dom.value.length > 0){
54181 this.el.dom.value =
54182 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
54188 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
54189 * query allowing the query action to be canceled if needed.
54190 * @param {String} query The SQL query to execute
54191 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
54192 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
54193 * saved in the current store (defaults to false)
54195 doQuery : function(q, forceAll){
54197 Roo.log('doQuery?');
54198 if(q === undefined || q === null){
54203 forceAll: forceAll,
54207 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
54211 forceAll = qe.forceAll;
54212 if(forceAll === true || (q.length >= this.minChars)){
54213 if(this.lastQuery != q || this.alwaysQuery){
54214 this.lastQuery = q;
54215 if(this.mode == 'local'){
54216 this.selectedIndex = -1;
54218 this.store.clearFilter();
54220 this.store.filter(this.displayField, q);
54224 this.store.baseParams[this.queryParam] = q;
54226 params: this.getParams(q)
54231 this.selectedIndex = -1;
54238 getParams : function(q){
54240 //p[this.queryParam] = q;
54243 p.limit = this.pageSize;
54249 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
54251 collapse : function(){
54256 collapseIf : function(e){
54261 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
54263 expand : function(){
54271 * @cfg {Boolean} grow
54275 * @cfg {Number} growMin
54279 * @cfg {Number} growMax
54287 setWidth : function()
54291 getResizeEl : function(){
54294 });//<script type="text/javasscript">
54298 * @class Roo.DDView
54299 * A DnD enabled version of Roo.View.
54300 * @param {Element/String} container The Element in which to create the View.
54301 * @param {String} tpl The template string used to create the markup for each element of the View
54302 * @param {Object} config The configuration properties. These include all the config options of
54303 * {@link Roo.View} plus some specific to this class.<br>
54305 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
54306 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
54308 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
54309 .x-view-drag-insert-above {
54310 border-top:1px dotted #3366cc;
54312 .x-view-drag-insert-below {
54313 border-bottom:1px dotted #3366cc;
54319 Roo.DDView = function(container, tpl, config) {
54320 Roo.DDView.superclass.constructor.apply(this, arguments);
54321 this.getEl().setStyle("outline", "0px none");
54322 this.getEl().unselectable();
54323 if (this.dragGroup) {
54324 this.setDraggable(this.dragGroup.split(","));
54326 if (this.dropGroup) {
54327 this.setDroppable(this.dropGroup.split(","));
54329 if (this.deletable) {
54330 this.setDeletable();
54332 this.isDirtyFlag = false;
54338 Roo.extend(Roo.DDView, Roo.View, {
54339 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
54340 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
54341 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
54342 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
54346 reset: Roo.emptyFn,
54348 clearInvalid: Roo.form.Field.prototype.clearInvalid,
54350 validate: function() {
54354 destroy: function() {
54355 this.purgeListeners();
54356 this.getEl.removeAllListeners();
54357 this.getEl().remove();
54358 if (this.dragZone) {
54359 if (this.dragZone.destroy) {
54360 this.dragZone.destroy();
54363 if (this.dropZone) {
54364 if (this.dropZone.destroy) {
54365 this.dropZone.destroy();
54370 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
54371 getName: function() {
54375 /** Loads the View from a JSON string representing the Records to put into the Store. */
54376 setValue: function(v) {
54378 throw "DDView.setValue(). DDView must be constructed with a valid Store";
54381 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
54382 this.store.proxy = new Roo.data.MemoryProxy(data);
54386 /** @return {String} a parenthesised list of the ids of the Records in the View. */
54387 getValue: function() {
54389 this.store.each(function(rec) {
54390 result += rec.id + ',';
54392 return result.substr(0, result.length - 1) + ')';
54395 getIds: function() {
54396 var i = 0, result = new Array(this.store.getCount());
54397 this.store.each(function(rec) {
54398 result[i++] = rec.id;
54403 isDirty: function() {
54404 return this.isDirtyFlag;
54408 * Part of the Roo.dd.DropZone interface. If no target node is found, the
54409 * whole Element becomes the target, and this causes the drop gesture to append.
54411 getTargetFromEvent : function(e) {
54412 var target = e.getTarget();
54413 while ((target !== null) && (target.parentNode != this.el.dom)) {
54414 target = target.parentNode;
54417 target = this.el.dom.lastChild || this.el.dom;
54423 * Create the drag data which consists of an object which has the property "ddel" as
54424 * the drag proxy element.
54426 getDragData : function(e) {
54427 var target = this.findItemFromChild(e.getTarget());
54429 this.handleSelection(e);
54430 var selNodes = this.getSelectedNodes();
54433 copy: this.copy || (this.allowCopy && e.ctrlKey),
54437 var selectedIndices = this.getSelectedIndexes();
54438 for (var i = 0; i < selectedIndices.length; i++) {
54439 dragData.records.push(this.store.getAt(selectedIndices[i]));
54441 if (selNodes.length == 1) {
54442 dragData.ddel = target.cloneNode(true); // the div element
54444 var div = document.createElement('div'); // create the multi element drag "ghost"
54445 div.className = 'multi-proxy';
54446 for (var i = 0, len = selNodes.length; i < len; i++) {
54447 div.appendChild(selNodes[i].cloneNode(true));
54449 dragData.ddel = div;
54451 //console.log(dragData)
54452 //console.log(dragData.ddel.innerHTML)
54455 //console.log('nodragData')
54459 /** Specify to which ddGroup items in this DDView may be dragged. */
54460 setDraggable: function(ddGroup) {
54461 if (ddGroup instanceof Array) {
54462 Roo.each(ddGroup, this.setDraggable, this);
54465 if (this.dragZone) {
54466 this.dragZone.addToGroup(ddGroup);
54468 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
54469 containerScroll: true,
54473 // Draggability implies selection. DragZone's mousedown selects the element.
54474 if (!this.multiSelect) { this.singleSelect = true; }
54476 // Wire the DragZone's handlers up to methods in *this*
54477 this.dragZone.getDragData = this.getDragData.createDelegate(this);
54481 /** Specify from which ddGroup this DDView accepts drops. */
54482 setDroppable: function(ddGroup) {
54483 if (ddGroup instanceof Array) {
54484 Roo.each(ddGroup, this.setDroppable, this);
54487 if (this.dropZone) {
54488 this.dropZone.addToGroup(ddGroup);
54490 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
54491 containerScroll: true,
54495 // Wire the DropZone's handlers up to methods in *this*
54496 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
54497 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
54498 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
54499 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
54500 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
54504 /** Decide whether to drop above or below a View node. */
54505 getDropPoint : function(e, n, dd){
54506 if (n == this.el.dom) { return "above"; }
54507 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
54508 var c = t + (b - t) / 2;
54509 var y = Roo.lib.Event.getPageY(e);
54517 onNodeEnter : function(n, dd, e, data){
54521 onNodeOver : function(n, dd, e, data){
54522 var pt = this.getDropPoint(e, n, dd);
54523 // set the insert point style on the target node
54524 var dragElClass = this.dropNotAllowed;
54527 if (pt == "above"){
54528 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
54529 targetElClass = "x-view-drag-insert-above";
54531 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
54532 targetElClass = "x-view-drag-insert-below";
54534 if (this.lastInsertClass != targetElClass){
54535 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
54536 this.lastInsertClass = targetElClass;
54539 return dragElClass;
54542 onNodeOut : function(n, dd, e, data){
54543 this.removeDropIndicators(n);
54546 onNodeDrop : function(n, dd, e, data){
54547 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
54550 var pt = this.getDropPoint(e, n, dd);
54551 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
54552 if (pt == "below") { insertAt++; }
54553 for (var i = 0; i < data.records.length; i++) {
54554 var r = data.records[i];
54555 var dup = this.store.getById(r.id);
54556 if (dup && (dd != this.dragZone)) {
54557 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
54560 this.store.insert(insertAt++, r.copy());
54562 data.source.isDirtyFlag = true;
54564 this.store.insert(insertAt++, r);
54566 this.isDirtyFlag = true;
54569 this.dragZone.cachedTarget = null;
54573 removeDropIndicators : function(n){
54575 Roo.fly(n).removeClass([
54576 "x-view-drag-insert-above",
54577 "x-view-drag-insert-below"]);
54578 this.lastInsertClass = "_noclass";
54583 * Utility method. Add a delete option to the DDView's context menu.
54584 * @param {String} imageUrl The URL of the "delete" icon image.
54586 setDeletable: function(imageUrl) {
54587 if (!this.singleSelect && !this.multiSelect) {
54588 this.singleSelect = true;
54590 var c = this.getContextMenu();
54591 this.contextMenu.on("itemclick", function(item) {
54594 this.remove(this.getSelectedIndexes());
54598 this.contextMenu.add({
54605 /** Return the context menu for this DDView. */
54606 getContextMenu: function() {
54607 if (!this.contextMenu) {
54608 // Create the View's context menu
54609 this.contextMenu = new Roo.menu.Menu({
54610 id: this.id + "-contextmenu"
54612 this.el.on("contextmenu", this.showContextMenu, this);
54614 return this.contextMenu;
54617 disableContextMenu: function() {
54618 if (this.contextMenu) {
54619 this.el.un("contextmenu", this.showContextMenu, this);
54623 showContextMenu: function(e, item) {
54624 item = this.findItemFromChild(e.getTarget());
54627 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
54628 this.contextMenu.showAt(e.getXY());
54633 * Remove {@link Roo.data.Record}s at the specified indices.
54634 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
54636 remove: function(selectedIndices) {
54637 selectedIndices = [].concat(selectedIndices);
54638 for (var i = 0; i < selectedIndices.length; i++) {
54639 var rec = this.store.getAt(selectedIndices[i]);
54640 this.store.remove(rec);
54645 * Double click fires the event, but also, if this is draggable, and there is only one other
54646 * related DropZone, it transfers the selected node.
54648 onDblClick : function(e){
54649 var item = this.findItemFromChild(e.getTarget());
54651 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
54654 if (this.dragGroup) {
54655 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
54656 while (targets.indexOf(this.dropZone) > -1) {
54657 targets.remove(this.dropZone);
54659 if (targets.length == 1) {
54660 this.dragZone.cachedTarget = null;
54661 var el = Roo.get(targets[0].getEl());
54662 var box = el.getBox(true);
54663 targets[0].onNodeDrop(el.dom, {
54665 xy: [box.x, box.y + box.height - 1]
54666 }, null, this.getDragData(e));
54672 handleSelection: function(e) {
54673 this.dragZone.cachedTarget = null;
54674 var item = this.findItemFromChild(e.getTarget());
54676 this.clearSelections(true);
54679 if (item && (this.multiSelect || this.singleSelect)){
54680 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
54681 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
54682 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
54683 this.unselect(item);
54685 this.select(item, this.multiSelect && e.ctrlKey);
54686 this.lastSelection = item;
54691 onItemClick : function(item, index, e){
54692 if(this.fireEvent("beforeclick", this, index, item, e) === false){
54698 unselect : function(nodeInfo, suppressEvent){
54699 var node = this.getNode(nodeInfo);
54700 if(node && this.isSelected(node)){
54701 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
54702 Roo.fly(node).removeClass(this.selectedClass);
54703 this.selections.remove(node);
54704 if(!suppressEvent){
54705 this.fireEvent("selectionchange", this, this.selections);
54713 * Ext JS Library 1.1.1
54714 * Copyright(c) 2006-2007, Ext JS, LLC.
54716 * Originally Released Under LGPL - original licence link has changed is not relivant.
54719 * <script type="text/javascript">
54723 * @class Roo.LayoutManager
54724 * @extends Roo.util.Observable
54725 * Base class for layout managers.
54727 Roo.LayoutManager = function(container, config){
54728 Roo.LayoutManager.superclass.constructor.call(this);
54729 this.el = Roo.get(container);
54730 // ie scrollbar fix
54731 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
54732 document.body.scroll = "no";
54733 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
54734 this.el.position('relative');
54736 this.id = this.el.id;
54737 this.el.addClass("x-layout-container");
54738 /** false to disable window resize monitoring @type Boolean */
54739 this.monitorWindowResize = true;
54744 * Fires when a layout is performed.
54745 * @param {Roo.LayoutManager} this
54749 * @event regionresized
54750 * Fires when the user resizes a region.
54751 * @param {Roo.LayoutRegion} region The resized region
54752 * @param {Number} newSize The new size (width for east/west, height for north/south)
54754 "regionresized" : true,
54756 * @event regioncollapsed
54757 * Fires when a region is collapsed.
54758 * @param {Roo.LayoutRegion} region The collapsed region
54760 "regioncollapsed" : true,
54762 * @event regionexpanded
54763 * Fires when a region is expanded.
54764 * @param {Roo.LayoutRegion} region The expanded region
54766 "regionexpanded" : true
54768 this.updating = false;
54769 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
54772 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
54774 * Returns true if this layout is currently being updated
54775 * @return {Boolean}
54777 isUpdating : function(){
54778 return this.updating;
54782 * Suspend the LayoutManager from doing auto-layouts while
54783 * making multiple add or remove calls
54785 beginUpdate : function(){
54786 this.updating = true;
54790 * Restore auto-layouts and optionally disable the manager from performing a layout
54791 * @param {Boolean} noLayout true to disable a layout update
54793 endUpdate : function(noLayout){
54794 this.updating = false;
54800 layout: function(){
54804 onRegionResized : function(region, newSize){
54805 this.fireEvent("regionresized", region, newSize);
54809 onRegionCollapsed : function(region){
54810 this.fireEvent("regioncollapsed", region);
54813 onRegionExpanded : function(region){
54814 this.fireEvent("regionexpanded", region);
54818 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
54819 * performs box-model adjustments.
54820 * @return {Object} The size as an object {width: (the width), height: (the height)}
54822 getViewSize : function(){
54824 if(this.el.dom != document.body){
54825 size = this.el.getSize();
54827 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
54829 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
54830 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
54835 * Returns the Element this layout is bound to.
54836 * @return {Roo.Element}
54838 getEl : function(){
54843 * Returns the specified region.
54844 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
54845 * @return {Roo.LayoutRegion}
54847 getRegion : function(target){
54848 return this.regions[target.toLowerCase()];
54851 onWindowResize : function(){
54852 if(this.monitorWindowResize){
54858 * Ext JS Library 1.1.1
54859 * Copyright(c) 2006-2007, Ext JS, LLC.
54861 * Originally Released Under LGPL - original licence link has changed is not relivant.
54864 * <script type="text/javascript">
54867 * @class Roo.BorderLayout
54868 * @extends Roo.LayoutManager
54869 * @children Roo.ContentPanel
54870 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
54871 * please see: <br><br>
54872 * <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>
54873 * <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>
54876 var layout = new Roo.BorderLayout(document.body, {
54910 preferredTabWidth: 150
54915 var CP = Roo.ContentPanel;
54917 layout.beginUpdate();
54918 layout.add("north", new CP("north", "North"));
54919 layout.add("south", new CP("south", {title: "South", closable: true}));
54920 layout.add("west", new CP("west", {title: "West"}));
54921 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
54922 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
54923 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
54924 layout.getRegion("center").showPanel("center1");
54925 layout.endUpdate();
54928 <b>The container the layout is rendered into can be either the body element or any other element.
54929 If it is not the body element, the container needs to either be an absolute positioned element,
54930 or you will need to add "position:relative" to the css of the container. You will also need to specify
54931 the container size if it is not the body element.</b>
54934 * Create a new BorderLayout
54935 * @param {String/HTMLElement/Element} container The container this layout is bound to
54936 * @param {Object} config Configuration options
54938 Roo.BorderLayout = function(container, config){
54939 config = config || {};
54940 Roo.BorderLayout.superclass.constructor.call(this, container, config);
54941 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
54942 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
54943 var target = this.factory.validRegions[i];
54944 if(config[target]){
54945 this.addRegion(target, config[target]);
54950 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
54953 * @cfg {Roo.LayoutRegion} east
54956 * @cfg {Roo.LayoutRegion} west
54959 * @cfg {Roo.LayoutRegion} north
54962 * @cfg {Roo.LayoutRegion} south
54965 * @cfg {Roo.LayoutRegion} center
54968 * Creates and adds a new region if it doesn't already exist.
54969 * @param {String} target The target region key (north, south, east, west or center).
54970 * @param {Object} config The regions config object
54971 * @return {BorderLayoutRegion} The new region
54973 addRegion : function(target, config){
54974 if(!this.regions[target]){
54975 var r = this.factory.create(target, this, config);
54976 this.bindRegion(target, r);
54978 return this.regions[target];
54982 bindRegion : function(name, r){
54983 this.regions[name] = r;
54984 r.on("visibilitychange", this.layout, this);
54985 r.on("paneladded", this.layout, this);
54986 r.on("panelremoved", this.layout, this);
54987 r.on("invalidated", this.layout, this);
54988 r.on("resized", this.onRegionResized, this);
54989 r.on("collapsed", this.onRegionCollapsed, this);
54990 r.on("expanded", this.onRegionExpanded, this);
54994 * Performs a layout update.
54996 layout : function(){
54997 if(this.updating) {
55000 var size = this.getViewSize();
55001 var w = size.width;
55002 var h = size.height;
55007 //var x = 0, y = 0;
55009 var rs = this.regions;
55010 var north = rs["north"];
55011 var south = rs["south"];
55012 var west = rs["west"];
55013 var east = rs["east"];
55014 var center = rs["center"];
55015 //if(this.hideOnLayout){ // not supported anymore
55016 //c.el.setStyle("display", "none");
55018 if(north && north.isVisible()){
55019 var b = north.getBox();
55020 var m = north.getMargins();
55021 b.width = w - (m.left+m.right);
55024 centerY = b.height + b.y + m.bottom;
55025 centerH -= centerY;
55026 north.updateBox(this.safeBox(b));
55028 if(south && south.isVisible()){
55029 var b = south.getBox();
55030 var m = south.getMargins();
55031 b.width = w - (m.left+m.right);
55033 var totalHeight = (b.height + m.top + m.bottom);
55034 b.y = h - totalHeight + m.top;
55035 centerH -= totalHeight;
55036 south.updateBox(this.safeBox(b));
55038 if(west && west.isVisible()){
55039 var b = west.getBox();
55040 var m = west.getMargins();
55041 b.height = centerH - (m.top+m.bottom);
55043 b.y = centerY + m.top;
55044 var totalWidth = (b.width + m.left + m.right);
55045 centerX += totalWidth;
55046 centerW -= totalWidth;
55047 west.updateBox(this.safeBox(b));
55049 if(east && east.isVisible()){
55050 var b = east.getBox();
55051 var m = east.getMargins();
55052 b.height = centerH - (m.top+m.bottom);
55053 var totalWidth = (b.width + m.left + m.right);
55054 b.x = w - totalWidth + m.left;
55055 b.y = centerY + m.top;
55056 centerW -= totalWidth;
55057 east.updateBox(this.safeBox(b));
55060 var m = center.getMargins();
55062 x: centerX + m.left,
55063 y: centerY + m.top,
55064 width: centerW - (m.left+m.right),
55065 height: centerH - (m.top+m.bottom)
55067 //if(this.hideOnLayout){
55068 //center.el.setStyle("display", "block");
55070 center.updateBox(this.safeBox(centerBox));
55073 this.fireEvent("layout", this);
55077 safeBox : function(box){
55078 box.width = Math.max(0, box.width);
55079 box.height = Math.max(0, box.height);
55084 * Adds a ContentPanel (or subclass) to this layout.
55085 * @param {String} target The target region key (north, south, east, west or center).
55086 * @param {Roo.ContentPanel} panel The panel to add
55087 * @return {Roo.ContentPanel} The added panel
55089 add : function(target, panel){
55091 target = target.toLowerCase();
55092 return this.regions[target].add(panel);
55096 * Remove a ContentPanel (or subclass) to this layout.
55097 * @param {String} target The target region key (north, south, east, west or center).
55098 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
55099 * @return {Roo.ContentPanel} The removed panel
55101 remove : function(target, panel){
55102 target = target.toLowerCase();
55103 return this.regions[target].remove(panel);
55107 * Searches all regions for a panel with the specified id
55108 * @param {String} panelId
55109 * @return {Roo.ContentPanel} The panel or null if it wasn't found
55111 findPanel : function(panelId){
55112 var rs = this.regions;
55113 for(var target in rs){
55114 if(typeof rs[target] != "function"){
55115 var p = rs[target].getPanel(panelId);
55125 * Searches all regions for a panel with the specified id and activates (shows) it.
55126 * @param {String/ContentPanel} panelId The panels id or the panel itself
55127 * @return {Roo.ContentPanel} The shown panel or null
55129 showPanel : function(panelId) {
55130 var rs = this.regions;
55131 for(var target in rs){
55132 var r = rs[target];
55133 if(typeof r != "function"){
55134 if(r.hasPanel(panelId)){
55135 return r.showPanel(panelId);
55143 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
55144 * @param {Roo.state.Provider} provider (optional) An alternate state provider
55146 restoreState : function(provider){
55148 provider = Roo.state.Manager;
55150 var sm = new Roo.LayoutStateManager();
55151 sm.init(this, provider);
55155 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
55156 * object should contain properties for each region to add ContentPanels to, and each property's value should be
55157 * a valid ContentPanel config object. Example:
55159 // Create the main layout
55160 var layout = new Roo.BorderLayout('main-ct', {
55171 // Create and add multiple ContentPanels at once via configs
55174 id: 'source-files',
55176 title:'Ext Source Files',
55189 * @param {Object} regions An object containing ContentPanel configs by region name
55191 batchAdd : function(regions){
55192 this.beginUpdate();
55193 for(var rname in regions){
55194 var lr = this.regions[rname];
55196 this.addTypedPanels(lr, regions[rname]);
55203 addTypedPanels : function(lr, ps){
55204 if(typeof ps == 'string'){
55205 lr.add(new Roo.ContentPanel(ps));
55207 else if(ps instanceof Array){
55208 for(var i =0, len = ps.length; i < len; i++){
55209 this.addTypedPanels(lr, ps[i]);
55212 else if(!ps.events){ // raw config?
55214 delete ps.el; // prevent conflict
55215 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
55217 else { // panel object assumed!
55222 * Adds a xtype elements to the layout.
55226 xtype : 'ContentPanel',
55233 xtype : 'NestedLayoutPanel',
55239 items : [ ... list of content panels or nested layout panels.. ]
55243 * @param {Object} cfg Xtype definition of item to add.
55245 addxtype : function(cfg)
55247 // basically accepts a pannel...
55248 // can accept a layout region..!?!?
55249 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
55251 if (!cfg.xtype.match(/Panel$/)) {
55256 if (typeof(cfg.region) == 'undefined') {
55257 Roo.log("Failed to add Panel, region was not set");
55261 var region = cfg.region;
55267 xitems = cfg.items;
55274 case 'ContentPanel': // ContentPanel (el, cfg)
55275 case 'ScrollPanel': // ContentPanel (el, cfg)
55277 if(cfg.autoCreate) {
55278 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
55280 var el = this.el.createChild();
55281 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
55284 this.add(region, ret);
55288 case 'TreePanel': // our new panel!
55289 cfg.el = this.el.createChild();
55290 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
55291 this.add(region, ret);
55294 case 'NestedLayoutPanel':
55295 // create a new Layout (which is a Border Layout...
55296 var el = this.el.createChild();
55297 var clayout = cfg.layout;
55299 clayout.items = clayout.items || [];
55300 // replace this exitems with the clayout ones..
55301 xitems = clayout.items;
55304 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
55305 cfg.background = false;
55307 var layout = new Roo.BorderLayout(el, clayout);
55309 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
55310 //console.log('adding nested layout panel ' + cfg.toSource());
55311 this.add(region, ret);
55312 nb = {}; /// find first...
55317 // needs grid and region
55319 //var el = this.getRegion(region).el.createChild();
55320 var el = this.el.createChild();
55321 // create the grid first...
55323 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
55325 if (region == 'center' && this.active ) {
55326 cfg.background = false;
55328 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
55330 this.add(region, ret);
55331 if (cfg.background) {
55332 ret.on('activate', function(gp) {
55333 if (!gp.grid.rendered) {
55348 if (typeof(Roo[cfg.xtype]) != 'undefined') {
55350 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
55351 this.add(region, ret);
55354 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
55358 // GridPanel (grid, cfg)
55361 this.beginUpdate();
55365 Roo.each(xitems, function(i) {
55366 region = nb && i.region ? i.region : false;
55368 var add = ret.addxtype(i);
55371 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
55372 if (!i.background) {
55373 abn[region] = nb[region] ;
55380 // make the last non-background panel active..
55381 //if (nb) { Roo.log(abn); }
55384 for(var r in abn) {
55385 region = this.getRegion(r);
55387 // tried using nb[r], but it does not work..
55389 region.showPanel(abn[r]);
55400 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
55401 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
55402 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
55403 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
55406 var CP = Roo.ContentPanel;
55408 var layout = Roo.BorderLayout.create({
55412 panels: [new CP("north", "North")]
55421 panels: [new CP("west", {title: "West"})]
55430 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
55439 panels: [new CP("south", {title: "South", closable: true})]
55446 preferredTabWidth: 150,
55448 new CP("center1", {title: "Close Me", closable: true}),
55449 new CP("center2", {title: "Center Panel", closable: false})
55454 layout.getRegion("center").showPanel("center1");
55459 Roo.BorderLayout.create = function(config, targetEl){
55460 var layout = new Roo.BorderLayout(targetEl || document.body, config);
55461 layout.beginUpdate();
55462 var regions = Roo.BorderLayout.RegionFactory.validRegions;
55463 for(var j = 0, jlen = regions.length; j < jlen; j++){
55464 var lr = regions[j];
55465 if(layout.regions[lr] && config[lr].panels){
55466 var r = layout.regions[lr];
55467 var ps = config[lr].panels;
55468 layout.addTypedPanels(r, ps);
55471 layout.endUpdate();
55476 Roo.BorderLayout.RegionFactory = {
55478 validRegions : ["north","south","east","west","center"],
55481 create : function(target, mgr, config){
55482 target = target.toLowerCase();
55483 if(config.lightweight || config.basic){
55484 return new Roo.BasicLayoutRegion(mgr, config, target);
55488 return new Roo.NorthLayoutRegion(mgr, config);
55490 return new Roo.SouthLayoutRegion(mgr, config);
55492 return new Roo.EastLayoutRegion(mgr, config);
55494 return new Roo.WestLayoutRegion(mgr, config);
55496 return new Roo.CenterLayoutRegion(mgr, config);
55498 throw 'Layout region "'+target+'" not supported.';
55502 * Ext JS Library 1.1.1
55503 * Copyright(c) 2006-2007, Ext JS, LLC.
55505 * Originally Released Under LGPL - original licence link has changed is not relivant.
55508 * <script type="text/javascript">
55512 * @class Roo.BasicLayoutRegion
55513 * @extends Roo.util.Observable
55514 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
55515 * and does not have a titlebar, tabs or any other features. All it does is size and position
55516 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
55518 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
55520 this.position = pos;
55523 * @scope Roo.BasicLayoutRegion
55527 * @event beforeremove
55528 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
55529 * @param {Roo.LayoutRegion} this
55530 * @param {Roo.ContentPanel} panel The panel
55531 * @param {Object} e The cancel event object
55533 "beforeremove" : true,
55535 * @event invalidated
55536 * Fires when the layout for this region is changed.
55537 * @param {Roo.LayoutRegion} this
55539 "invalidated" : true,
55541 * @event visibilitychange
55542 * Fires when this region is shown or hidden
55543 * @param {Roo.LayoutRegion} this
55544 * @param {Boolean} visibility true or false
55546 "visibilitychange" : true,
55548 * @event paneladded
55549 * Fires when a panel is added.
55550 * @param {Roo.LayoutRegion} this
55551 * @param {Roo.ContentPanel} panel The panel
55553 "paneladded" : true,
55555 * @event panelremoved
55556 * Fires when a panel is removed.
55557 * @param {Roo.LayoutRegion} this
55558 * @param {Roo.ContentPanel} panel The panel
55560 "panelremoved" : true,
55562 * @event beforecollapse
55563 * Fires when this region before collapse.
55564 * @param {Roo.LayoutRegion} this
55566 "beforecollapse" : true,
55569 * Fires when this region is collapsed.
55570 * @param {Roo.LayoutRegion} this
55572 "collapsed" : true,
55575 * Fires when this region is expanded.
55576 * @param {Roo.LayoutRegion} this
55581 * Fires when this region is slid into view.
55582 * @param {Roo.LayoutRegion} this
55584 "slideshow" : true,
55587 * Fires when this region slides out of view.
55588 * @param {Roo.LayoutRegion} this
55590 "slidehide" : true,
55592 * @event panelactivated
55593 * Fires when a panel is activated.
55594 * @param {Roo.LayoutRegion} this
55595 * @param {Roo.ContentPanel} panel The activated panel
55597 "panelactivated" : true,
55600 * Fires when the user resizes this region.
55601 * @param {Roo.LayoutRegion} this
55602 * @param {Number} newSize The new size (width for east/west, height for north/south)
55606 /** A collection of panels in this region. @type Roo.util.MixedCollection */
55607 this.panels = new Roo.util.MixedCollection();
55608 this.panels.getKey = this.getPanelId.createDelegate(this);
55610 this.activePanel = null;
55611 // ensure listeners are added...
55613 if (config.listeners || config.events) {
55614 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
55615 listeners : config.listeners || {},
55616 events : config.events || {}
55620 if(skipConfig !== true){
55621 this.applyConfig(config);
55625 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
55626 getPanelId : function(p){
55630 applyConfig : function(config){
55631 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
55632 this.config = config;
55637 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
55638 * the width, for horizontal (north, south) the height.
55639 * @param {Number} newSize The new width or height
55641 resizeTo : function(newSize){
55642 var el = this.el ? this.el :
55643 (this.activePanel ? this.activePanel.getEl() : null);
55645 switch(this.position){
55648 el.setWidth(newSize);
55649 this.fireEvent("resized", this, newSize);
55653 el.setHeight(newSize);
55654 this.fireEvent("resized", this, newSize);
55660 getBox : function(){
55661 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
55664 getMargins : function(){
55665 return this.margins;
55668 updateBox : function(box){
55670 var el = this.activePanel.getEl();
55671 el.dom.style.left = box.x + "px";
55672 el.dom.style.top = box.y + "px";
55673 this.activePanel.setSize(box.width, box.height);
55677 * Returns the container element for this region.
55678 * @return {Roo.Element}
55680 getEl : function(){
55681 return this.activePanel;
55685 * Returns true if this region is currently visible.
55686 * @return {Boolean}
55688 isVisible : function(){
55689 return this.activePanel ? true : false;
55692 setActivePanel : function(panel){
55693 panel = this.getPanel(panel);
55694 if(this.activePanel && this.activePanel != panel){
55695 this.activePanel.setActiveState(false);
55696 this.activePanel.getEl().setLeftTop(-10000,-10000);
55698 this.activePanel = panel;
55699 panel.setActiveState(true);
55701 panel.setSize(this.box.width, this.box.height);
55703 this.fireEvent("panelactivated", this, panel);
55704 this.fireEvent("invalidated");
55708 * Show the specified panel.
55709 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
55710 * @return {Roo.ContentPanel} The shown panel or null
55712 showPanel : function(panel){
55713 if(panel = this.getPanel(panel)){
55714 this.setActivePanel(panel);
55720 * Get the active panel for this region.
55721 * @return {Roo.ContentPanel} The active panel or null
55723 getActivePanel : function(){
55724 return this.activePanel;
55728 * Add the passed ContentPanel(s)
55729 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
55730 * @return {Roo.ContentPanel} The panel added (if only one was added)
55732 add : function(panel){
55733 if(arguments.length > 1){
55734 for(var i = 0, len = arguments.length; i < len; i++) {
55735 this.add(arguments[i]);
55739 if(this.hasPanel(panel)){
55740 this.showPanel(panel);
55743 var el = panel.getEl();
55744 if(el.dom.parentNode != this.mgr.el.dom){
55745 this.mgr.el.dom.appendChild(el.dom);
55747 if(panel.setRegion){
55748 panel.setRegion(this);
55750 this.panels.add(panel);
55751 el.setStyle("position", "absolute");
55752 if(!panel.background){
55753 this.setActivePanel(panel);
55754 if(this.config.initialSize && this.panels.getCount()==1){
55755 this.resizeTo(this.config.initialSize);
55758 this.fireEvent("paneladded", this, panel);
55763 * Returns true if the panel is in this region.
55764 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
55765 * @return {Boolean}
55767 hasPanel : function(panel){
55768 if(typeof panel == "object"){ // must be panel obj
55769 panel = panel.getId();
55771 return this.getPanel(panel) ? true : false;
55775 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
55776 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
55777 * @param {Boolean} preservePanel Overrides the config preservePanel option
55778 * @return {Roo.ContentPanel} The panel that was removed
55780 remove : function(panel, preservePanel){
55781 panel = this.getPanel(panel);
55786 this.fireEvent("beforeremove", this, panel, e);
55787 if(e.cancel === true){
55790 var panelId = panel.getId();
55791 this.panels.removeKey(panelId);
55796 * Returns the panel specified or null if it's not in this region.
55797 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
55798 * @return {Roo.ContentPanel}
55800 getPanel : function(id){
55801 if(typeof id == "object"){ // must be panel obj
55804 return this.panels.get(id);
55808 * Returns this regions position (north/south/east/west/center).
55811 getPosition: function(){
55812 return this.position;
55816 * Ext JS Library 1.1.1
55817 * Copyright(c) 2006-2007, Ext JS, LLC.
55819 * Originally Released Under LGPL - original licence link has changed is not relivant.
55822 * <script type="text/javascript">
55826 * @class Roo.LayoutRegion
55827 * @extends Roo.BasicLayoutRegion
55828 * This class represents a region in a layout manager.
55829 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
55830 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
55831 * @cfg {Boolean} floatable False to disable floating (defaults to true)
55832 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
55833 * @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})
55834 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
55835 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
55836 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
55837 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
55838 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
55839 * @cfg {String} title The title for the region (overrides panel titles)
55840 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
55841 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
55842 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
55843 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
55844 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
55845 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
55846 * the space available, similar to FireFox 1.5 tabs (defaults to false)
55847 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
55848 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
55849 * @cfg {Boolean} showPin True to show a pin button
55850 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
55851 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
55852 * @cfg {Boolean} disableTabTips True to disable tab tooltips
55853 * @cfg {Number} width For East/West panels
55854 * @cfg {Number} height For North/South panels
55855 * @cfg {Boolean} split To show the splitter
55856 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
55858 Roo.LayoutRegion = function(mgr, config, pos){
55859 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
55860 var dh = Roo.DomHelper;
55861 /** This region's container element
55862 * @type Roo.Element */
55863 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
55864 /** This region's title element
55865 * @type Roo.Element */
55867 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
55868 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
55869 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
55871 this.titleEl.enableDisplayMode();
55872 /** This region's title text element
55873 * @type HTMLElement */
55874 this.titleTextEl = this.titleEl.dom.firstChild;
55875 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
55876 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
55877 this.closeBtn.enableDisplayMode();
55878 this.closeBtn.on("click", this.closeClicked, this);
55879 this.closeBtn.hide();
55881 this.createBody(config);
55882 this.visible = true;
55883 this.collapsed = false;
55885 if(config.hideWhenEmpty){
55887 this.on("paneladded", this.validateVisibility, this);
55888 this.on("panelremoved", this.validateVisibility, this);
55890 this.applyConfig(config);
55893 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
55895 createBody : function(){
55896 /** This region's body element
55897 * @type Roo.Element */
55898 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
55901 applyConfig : function(c){
55902 if(c.collapsible && this.position != "center" && !this.collapsedEl){
55903 var dh = Roo.DomHelper;
55904 if(c.titlebar !== false){
55905 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
55906 this.collapseBtn.on("click", this.collapse, this);
55907 this.collapseBtn.enableDisplayMode();
55909 if(c.showPin === true || this.showPin){
55910 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
55911 this.stickBtn.enableDisplayMode();
55912 this.stickBtn.on("click", this.expand, this);
55913 this.stickBtn.hide();
55916 /** This region's collapsed element
55917 * @type Roo.Element */
55918 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
55919 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
55921 if(c.floatable !== false){
55922 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
55923 this.collapsedEl.on("click", this.collapseClick, this);
55926 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
55927 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
55928 id: "message", unselectable: "on", style:{"float":"left"}});
55929 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
55931 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
55932 this.expandBtn.on("click", this.expand, this);
55934 if(this.collapseBtn){
55935 this.collapseBtn.setVisible(c.collapsible == true);
55937 this.cmargins = c.cmargins || this.cmargins ||
55938 (this.position == "west" || this.position == "east" ?
55939 {top: 0, left: 2, right:2, bottom: 0} :
55940 {top: 2, left: 0, right:0, bottom: 2});
55941 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
55942 this.bottomTabs = c.tabPosition != "top";
55943 this.autoScroll = c.autoScroll || false;
55944 if(this.autoScroll){
55945 this.bodyEl.setStyle("overflow", "auto");
55947 this.bodyEl.setStyle("overflow", "hidden");
55949 //if(c.titlebar !== false){
55950 if((!c.titlebar && !c.title) || c.titlebar === false){
55951 this.titleEl.hide();
55953 this.titleEl.show();
55955 this.titleTextEl.innerHTML = c.title;
55959 this.duration = c.duration || .30;
55960 this.slideDuration = c.slideDuration || .45;
55963 this.collapse(true);
55970 * Returns true if this region is currently visible.
55971 * @return {Boolean}
55973 isVisible : function(){
55974 return this.visible;
55978 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
55979 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
55981 setCollapsedTitle : function(title){
55982 title = title || " ";
55983 if(this.collapsedTitleTextEl){
55984 this.collapsedTitleTextEl.innerHTML = title;
55988 getBox : function(){
55990 if(!this.collapsed){
55991 b = this.el.getBox(false, true);
55993 b = this.collapsedEl.getBox(false, true);
55998 getMargins : function(){
55999 return this.collapsed ? this.cmargins : this.margins;
56002 highlight : function(){
56003 this.el.addClass("x-layout-panel-dragover");
56006 unhighlight : function(){
56007 this.el.removeClass("x-layout-panel-dragover");
56010 updateBox : function(box){
56012 if(!this.collapsed){
56013 this.el.dom.style.left = box.x + "px";
56014 this.el.dom.style.top = box.y + "px";
56015 this.updateBody(box.width, box.height);
56017 this.collapsedEl.dom.style.left = box.x + "px";
56018 this.collapsedEl.dom.style.top = box.y + "px";
56019 this.collapsedEl.setSize(box.width, box.height);
56022 this.tabs.autoSizeTabs();
56026 updateBody : function(w, h){
56028 this.el.setWidth(w);
56029 w -= this.el.getBorderWidth("rl");
56030 if(this.config.adjustments){
56031 w += this.config.adjustments[0];
56035 this.el.setHeight(h);
56036 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
56037 h -= this.el.getBorderWidth("tb");
56038 if(this.config.adjustments){
56039 h += this.config.adjustments[1];
56041 this.bodyEl.setHeight(h);
56043 h = this.tabs.syncHeight(h);
56046 if(this.panelSize){
56047 w = w !== null ? w : this.panelSize.width;
56048 h = h !== null ? h : this.panelSize.height;
56050 if(this.activePanel){
56051 var el = this.activePanel.getEl();
56052 w = w !== null ? w : el.getWidth();
56053 h = h !== null ? h : el.getHeight();
56054 this.panelSize = {width: w, height: h};
56055 this.activePanel.setSize(w, h);
56057 if(Roo.isIE && this.tabs){
56058 this.tabs.el.repaint();
56063 * Returns the container element for this region.
56064 * @return {Roo.Element}
56066 getEl : function(){
56071 * Hides this region.
56074 if(!this.collapsed){
56075 this.el.dom.style.left = "-2000px";
56078 this.collapsedEl.dom.style.left = "-2000px";
56079 this.collapsedEl.hide();
56081 this.visible = false;
56082 this.fireEvent("visibilitychange", this, false);
56086 * Shows this region if it was previously hidden.
56089 if(!this.collapsed){
56092 this.collapsedEl.show();
56094 this.visible = true;
56095 this.fireEvent("visibilitychange", this, true);
56098 closeClicked : function(){
56099 if(this.activePanel){
56100 this.remove(this.activePanel);
56104 collapseClick : function(e){
56106 e.stopPropagation();
56109 e.stopPropagation();
56115 * Collapses this region.
56116 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
56118 collapse : function(skipAnim, skipCheck){
56119 if(this.collapsed) {
56123 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
56125 this.collapsed = true;
56127 this.split.el.hide();
56129 if(this.config.animate && skipAnim !== true){
56130 this.fireEvent("invalidated", this);
56131 this.animateCollapse();
56133 this.el.setLocation(-20000,-20000);
56135 this.collapsedEl.show();
56136 this.fireEvent("collapsed", this);
56137 this.fireEvent("invalidated", this);
56143 animateCollapse : function(){
56148 * Expands this region if it was previously collapsed.
56149 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
56150 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
56152 expand : function(e, skipAnim){
56154 e.stopPropagation();
56156 if(!this.collapsed || this.el.hasActiveFx()) {
56160 this.afterSlideIn();
56163 this.collapsed = false;
56164 if(this.config.animate && skipAnim !== true){
56165 this.animateExpand();
56169 this.split.el.show();
56171 this.collapsedEl.setLocation(-2000,-2000);
56172 this.collapsedEl.hide();
56173 this.fireEvent("invalidated", this);
56174 this.fireEvent("expanded", this);
56178 animateExpand : function(){
56182 initTabs : function()
56184 this.bodyEl.setStyle("overflow", "hidden");
56185 var ts = new Roo.TabPanel(
56188 tabPosition: this.bottomTabs ? 'bottom' : 'top',
56189 disableTooltips: this.config.disableTabTips,
56190 toolbar : this.config.toolbar
56193 if(this.config.hideTabs){
56194 ts.stripWrap.setDisplayed(false);
56197 ts.resizeTabs = this.config.resizeTabs === true;
56198 ts.minTabWidth = this.config.minTabWidth || 40;
56199 ts.maxTabWidth = this.config.maxTabWidth || 250;
56200 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
56201 ts.monitorResize = false;
56202 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
56203 ts.bodyEl.addClass('x-layout-tabs-body');
56204 this.panels.each(this.initPanelAsTab, this);
56207 initPanelAsTab : function(panel){
56208 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
56209 this.config.closeOnTab && panel.isClosable());
56210 if(panel.tabTip !== undefined){
56211 ti.setTooltip(panel.tabTip);
56213 ti.on("activate", function(){
56214 this.setActivePanel(panel);
56216 if(this.config.closeOnTab){
56217 ti.on("beforeclose", function(t, e){
56219 this.remove(panel);
56225 updatePanelTitle : function(panel, title){
56226 if(this.activePanel == panel){
56227 this.updateTitle(title);
56230 var ti = this.tabs.getTab(panel.getEl().id);
56232 if(panel.tabTip !== undefined){
56233 ti.setTooltip(panel.tabTip);
56238 updateTitle : function(title){
56239 if(this.titleTextEl && !this.config.title){
56240 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
56244 setActivePanel : function(panel){
56245 panel = this.getPanel(panel);
56246 if(this.activePanel && this.activePanel != panel){
56247 this.activePanel.setActiveState(false);
56249 this.activePanel = panel;
56250 panel.setActiveState(true);
56251 if(this.panelSize){
56252 panel.setSize(this.panelSize.width, this.panelSize.height);
56255 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
56257 this.updateTitle(panel.getTitle());
56259 this.fireEvent("invalidated", this);
56261 this.fireEvent("panelactivated", this, panel);
56265 * Shows the specified panel.
56266 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
56267 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
56269 showPanel : function(panel)
56271 panel = this.getPanel(panel);
56274 var tab = this.tabs.getTab(panel.getEl().id);
56275 if(tab.isHidden()){
56276 this.tabs.unhideTab(tab.id);
56280 this.setActivePanel(panel);
56287 * Get the active panel for this region.
56288 * @return {Roo.ContentPanel} The active panel or null
56290 getActivePanel : function(){
56291 return this.activePanel;
56294 validateVisibility : function(){
56295 if(this.panels.getCount() < 1){
56296 this.updateTitle(" ");
56297 this.closeBtn.hide();
56300 if(!this.isVisible()){
56307 * Adds the passed ContentPanel(s) to this region.
56308 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
56309 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
56311 add : function(panel){
56312 if(arguments.length > 1){
56313 for(var i = 0, len = arguments.length; i < len; i++) {
56314 this.add(arguments[i]);
56318 if(this.hasPanel(panel)){
56319 this.showPanel(panel);
56322 panel.setRegion(this);
56323 this.panels.add(panel);
56324 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
56325 this.bodyEl.dom.appendChild(panel.getEl().dom);
56326 if(panel.background !== true){
56327 this.setActivePanel(panel);
56329 this.fireEvent("paneladded", this, panel);
56335 this.initPanelAsTab(panel);
56337 if(panel.background !== true){
56338 this.tabs.activate(panel.getEl().id);
56340 this.fireEvent("paneladded", this, panel);
56345 * Hides the tab for the specified panel.
56346 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
56348 hidePanel : function(panel){
56349 if(this.tabs && (panel = this.getPanel(panel))){
56350 this.tabs.hideTab(panel.getEl().id);
56355 * Unhides the tab for a previously hidden panel.
56356 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
56358 unhidePanel : function(panel){
56359 if(this.tabs && (panel = this.getPanel(panel))){
56360 this.tabs.unhideTab(panel.getEl().id);
56364 clearPanels : function(){
56365 while(this.panels.getCount() > 0){
56366 this.remove(this.panels.first());
56371 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
56372 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
56373 * @param {Boolean} preservePanel Overrides the config preservePanel option
56374 * @return {Roo.ContentPanel} The panel that was removed
56376 remove : function(panel, preservePanel){
56377 panel = this.getPanel(panel);
56382 this.fireEvent("beforeremove", this, panel, e);
56383 if(e.cancel === true){
56386 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
56387 var panelId = panel.getId();
56388 this.panels.removeKey(panelId);
56390 document.body.appendChild(panel.getEl().dom);
56393 this.tabs.removeTab(panel.getEl().id);
56394 }else if (!preservePanel){
56395 this.bodyEl.dom.removeChild(panel.getEl().dom);
56397 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
56398 var p = this.panels.first();
56399 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
56400 tempEl.appendChild(p.getEl().dom);
56401 this.bodyEl.update("");
56402 this.bodyEl.dom.appendChild(p.getEl().dom);
56404 this.updateTitle(p.getTitle());
56406 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
56407 this.setActivePanel(p);
56409 panel.setRegion(null);
56410 if(this.activePanel == panel){
56411 this.activePanel = null;
56413 if(this.config.autoDestroy !== false && preservePanel !== true){
56414 try{panel.destroy();}catch(e){}
56416 this.fireEvent("panelremoved", this, panel);
56421 * Returns the TabPanel component used by this region
56422 * @return {Roo.TabPanel}
56424 getTabs : function(){
56428 createTool : function(parentEl, className){
56429 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
56430 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
56431 btn.addClassOnOver("x-layout-tools-button-over");
56436 * Ext JS Library 1.1.1
56437 * Copyright(c) 2006-2007, Ext JS, LLC.
56439 * Originally Released Under LGPL - original licence link has changed is not relivant.
56442 * <script type="text/javascript">
56448 * @class Roo.SplitLayoutRegion
56449 * @extends Roo.LayoutRegion
56450 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
56452 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
56453 this.cursor = cursor;
56454 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
56457 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
56458 splitTip : "Drag to resize.",
56459 collapsibleSplitTip : "Drag to resize. Double click to hide.",
56460 useSplitTips : false,
56462 applyConfig : function(config){
56463 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
56466 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
56467 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
56468 /** The SplitBar for this region
56469 * @type Roo.SplitBar */
56470 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
56471 this.split.on("moved", this.onSplitMove, this);
56472 this.split.useShim = config.useShim === true;
56473 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
56474 if(this.useSplitTips){
56475 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
56477 if(config.collapsible){
56478 this.split.el.on("dblclick", this.collapse, this);
56481 if(typeof config.minSize != "undefined"){
56482 this.split.minSize = config.minSize;
56484 if(typeof config.maxSize != "undefined"){
56485 this.split.maxSize = config.maxSize;
56487 if(config.hideWhenEmpty || config.hidden || config.collapsed){
56488 this.hideSplitter();
56493 getHMaxSize : function(){
56494 var cmax = this.config.maxSize || 10000;
56495 var center = this.mgr.getRegion("center");
56496 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
56499 getVMaxSize : function(){
56500 var cmax = this.config.maxSize || 10000;
56501 var center = this.mgr.getRegion("center");
56502 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
56505 onSplitMove : function(split, newSize){
56506 this.fireEvent("resized", this, newSize);
56510 * Returns the {@link Roo.SplitBar} for this region.
56511 * @return {Roo.SplitBar}
56513 getSplitBar : function(){
56518 this.hideSplitter();
56519 Roo.SplitLayoutRegion.superclass.hide.call(this);
56522 hideSplitter : function(){
56524 this.split.el.setLocation(-2000,-2000);
56525 this.split.el.hide();
56531 this.split.el.show();
56533 Roo.SplitLayoutRegion.superclass.show.call(this);
56536 beforeSlide: function(){
56537 if(Roo.isGecko){// firefox overflow auto bug workaround
56538 this.bodyEl.clip();
56540 this.tabs.bodyEl.clip();
56542 if(this.activePanel){
56543 this.activePanel.getEl().clip();
56545 if(this.activePanel.beforeSlide){
56546 this.activePanel.beforeSlide();
56552 afterSlide : function(){
56553 if(Roo.isGecko){// firefox overflow auto bug workaround
56554 this.bodyEl.unclip();
56556 this.tabs.bodyEl.unclip();
56558 if(this.activePanel){
56559 this.activePanel.getEl().unclip();
56560 if(this.activePanel.afterSlide){
56561 this.activePanel.afterSlide();
56567 initAutoHide : function(){
56568 if(this.autoHide !== false){
56569 if(!this.autoHideHd){
56570 var st = new Roo.util.DelayedTask(this.slideIn, this);
56571 this.autoHideHd = {
56572 "mouseout": function(e){
56573 if(!e.within(this.el, true)){
56577 "mouseover" : function(e){
56583 this.el.on(this.autoHideHd);
56587 clearAutoHide : function(){
56588 if(this.autoHide !== false){
56589 this.el.un("mouseout", this.autoHideHd.mouseout);
56590 this.el.un("mouseover", this.autoHideHd.mouseover);
56594 clearMonitor : function(){
56595 Roo.get(document).un("click", this.slideInIf, this);
56598 // these names are backwards but not changed for compat
56599 slideOut : function(){
56600 if(this.isSlid || this.el.hasActiveFx()){
56603 this.isSlid = true;
56604 if(this.collapseBtn){
56605 this.collapseBtn.hide();
56607 this.closeBtnState = this.closeBtn.getStyle('display');
56608 this.closeBtn.hide();
56610 this.stickBtn.show();
56613 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
56614 this.beforeSlide();
56615 this.el.setStyle("z-index", 10001);
56616 this.el.slideIn(this.getSlideAnchor(), {
56617 callback: function(){
56619 this.initAutoHide();
56620 Roo.get(document).on("click", this.slideInIf, this);
56621 this.fireEvent("slideshow", this);
56628 afterSlideIn : function(){
56629 this.clearAutoHide();
56630 this.isSlid = false;
56631 this.clearMonitor();
56632 this.el.setStyle("z-index", "");
56633 if(this.collapseBtn){
56634 this.collapseBtn.show();
56636 this.closeBtn.setStyle('display', this.closeBtnState);
56638 this.stickBtn.hide();
56640 this.fireEvent("slidehide", this);
56643 slideIn : function(cb){
56644 if(!this.isSlid || this.el.hasActiveFx()){
56648 this.isSlid = false;
56649 this.beforeSlide();
56650 this.el.slideOut(this.getSlideAnchor(), {
56651 callback: function(){
56652 this.el.setLeftTop(-10000, -10000);
56654 this.afterSlideIn();
56662 slideInIf : function(e){
56663 if(!e.within(this.el)){
56668 animateCollapse : function(){
56669 this.beforeSlide();
56670 this.el.setStyle("z-index", 20000);
56671 var anchor = this.getSlideAnchor();
56672 this.el.slideOut(anchor, {
56673 callback : function(){
56674 this.el.setStyle("z-index", "");
56675 this.collapsedEl.slideIn(anchor, {duration:.3});
56677 this.el.setLocation(-10000,-10000);
56679 this.fireEvent("collapsed", this);
56686 animateExpand : function(){
56687 this.beforeSlide();
56688 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
56689 this.el.setStyle("z-index", 20000);
56690 this.collapsedEl.hide({
56693 this.el.slideIn(this.getSlideAnchor(), {
56694 callback : function(){
56695 this.el.setStyle("z-index", "");
56698 this.split.el.show();
56700 this.fireEvent("invalidated", this);
56701 this.fireEvent("expanded", this);
56729 getAnchor : function(){
56730 return this.anchors[this.position];
56733 getCollapseAnchor : function(){
56734 return this.canchors[this.position];
56737 getSlideAnchor : function(){
56738 return this.sanchors[this.position];
56741 getAlignAdj : function(){
56742 var cm = this.cmargins;
56743 switch(this.position){
56759 getExpandAdj : function(){
56760 var c = this.collapsedEl, cm = this.cmargins;
56761 switch(this.position){
56763 return [-(cm.right+c.getWidth()+cm.left), 0];
56766 return [cm.right+c.getWidth()+cm.left, 0];
56769 return [0, -(cm.top+cm.bottom+c.getHeight())];
56772 return [0, cm.top+cm.bottom+c.getHeight()];
56778 * Ext JS Library 1.1.1
56779 * Copyright(c) 2006-2007, Ext JS, LLC.
56781 * Originally Released Under LGPL - original licence link has changed is not relivant.
56784 * <script type="text/javascript">
56787 * These classes are private internal classes
56789 Roo.CenterLayoutRegion = function(mgr, config){
56790 Roo.LayoutRegion.call(this, mgr, config, "center");
56791 this.visible = true;
56792 this.minWidth = config.minWidth || 20;
56793 this.minHeight = config.minHeight || 20;
56796 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
56798 // center panel can't be hidden
56802 // center panel can't be hidden
56805 getMinWidth: function(){
56806 return this.minWidth;
56809 getMinHeight: function(){
56810 return this.minHeight;
56815 Roo.NorthLayoutRegion = function(mgr, config){
56816 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
56818 this.split.placement = Roo.SplitBar.TOP;
56819 this.split.orientation = Roo.SplitBar.VERTICAL;
56820 this.split.el.addClass("x-layout-split-v");
56822 var size = config.initialSize || config.height;
56823 if(typeof size != "undefined"){
56824 this.el.setHeight(size);
56827 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
56828 orientation: Roo.SplitBar.VERTICAL,
56829 getBox : function(){
56830 if(this.collapsed){
56831 return this.collapsedEl.getBox();
56833 var box = this.el.getBox();
56835 box.height += this.split.el.getHeight();
56840 updateBox : function(box){
56841 if(this.split && !this.collapsed){
56842 box.height -= this.split.el.getHeight();
56843 this.split.el.setLeft(box.x);
56844 this.split.el.setTop(box.y+box.height);
56845 this.split.el.setWidth(box.width);
56847 if(this.collapsed){
56848 this.updateBody(box.width, null);
56850 Roo.LayoutRegion.prototype.updateBox.call(this, box);
56854 Roo.SouthLayoutRegion = function(mgr, config){
56855 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
56857 this.split.placement = Roo.SplitBar.BOTTOM;
56858 this.split.orientation = Roo.SplitBar.VERTICAL;
56859 this.split.el.addClass("x-layout-split-v");
56861 var size = config.initialSize || config.height;
56862 if(typeof size != "undefined"){
56863 this.el.setHeight(size);
56866 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
56867 orientation: Roo.SplitBar.VERTICAL,
56868 getBox : function(){
56869 if(this.collapsed){
56870 return this.collapsedEl.getBox();
56872 var box = this.el.getBox();
56874 var sh = this.split.el.getHeight();
56881 updateBox : function(box){
56882 if(this.split && !this.collapsed){
56883 var sh = this.split.el.getHeight();
56886 this.split.el.setLeft(box.x);
56887 this.split.el.setTop(box.y-sh);
56888 this.split.el.setWidth(box.width);
56890 if(this.collapsed){
56891 this.updateBody(box.width, null);
56893 Roo.LayoutRegion.prototype.updateBox.call(this, box);
56897 Roo.EastLayoutRegion = function(mgr, config){
56898 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
56900 this.split.placement = Roo.SplitBar.RIGHT;
56901 this.split.orientation = Roo.SplitBar.HORIZONTAL;
56902 this.split.el.addClass("x-layout-split-h");
56904 var size = config.initialSize || config.width;
56905 if(typeof size != "undefined"){
56906 this.el.setWidth(size);
56909 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
56910 orientation: Roo.SplitBar.HORIZONTAL,
56911 getBox : function(){
56912 if(this.collapsed){
56913 return this.collapsedEl.getBox();
56915 var box = this.el.getBox();
56917 var sw = this.split.el.getWidth();
56924 updateBox : function(box){
56925 if(this.split && !this.collapsed){
56926 var sw = this.split.el.getWidth();
56928 this.split.el.setLeft(box.x);
56929 this.split.el.setTop(box.y);
56930 this.split.el.setHeight(box.height);
56933 if(this.collapsed){
56934 this.updateBody(null, box.height);
56936 Roo.LayoutRegion.prototype.updateBox.call(this, box);
56940 Roo.WestLayoutRegion = function(mgr, config){
56941 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
56943 this.split.placement = Roo.SplitBar.LEFT;
56944 this.split.orientation = Roo.SplitBar.HORIZONTAL;
56945 this.split.el.addClass("x-layout-split-h");
56947 var size = config.initialSize || config.width;
56948 if(typeof size != "undefined"){
56949 this.el.setWidth(size);
56952 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
56953 orientation: Roo.SplitBar.HORIZONTAL,
56954 getBox : function(){
56955 if(this.collapsed){
56956 return this.collapsedEl.getBox();
56958 var box = this.el.getBox();
56960 box.width += this.split.el.getWidth();
56965 updateBox : function(box){
56966 if(this.split && !this.collapsed){
56967 var sw = this.split.el.getWidth();
56969 this.split.el.setLeft(box.x+box.width);
56970 this.split.el.setTop(box.y);
56971 this.split.el.setHeight(box.height);
56973 if(this.collapsed){
56974 this.updateBody(null, box.height);
56976 Roo.LayoutRegion.prototype.updateBox.call(this, box);
56981 * Ext JS Library 1.1.1
56982 * Copyright(c) 2006-2007, Ext JS, LLC.
56984 * Originally Released Under LGPL - original licence link has changed is not relivant.
56987 * <script type="text/javascript">
56992 * Private internal class for reading and applying state
56994 Roo.LayoutStateManager = function(layout){
56995 // default empty state
57004 Roo.LayoutStateManager.prototype = {
57005 init : function(layout, provider){
57006 this.provider = provider;
57007 var state = provider.get(layout.id+"-layout-state");
57009 var wasUpdating = layout.isUpdating();
57011 layout.beginUpdate();
57013 for(var key in state){
57014 if(typeof state[key] != "function"){
57015 var rstate = state[key];
57016 var r = layout.getRegion(key);
57019 r.resizeTo(rstate.size);
57021 if(rstate.collapsed == true){
57024 r.expand(null, true);
57030 layout.endUpdate();
57032 this.state = state;
57034 this.layout = layout;
57035 layout.on("regionresized", this.onRegionResized, this);
57036 layout.on("regioncollapsed", this.onRegionCollapsed, this);
57037 layout.on("regionexpanded", this.onRegionExpanded, this);
57040 storeState : function(){
57041 this.provider.set(this.layout.id+"-layout-state", this.state);
57044 onRegionResized : function(region, newSize){
57045 this.state[region.getPosition()].size = newSize;
57049 onRegionCollapsed : function(region){
57050 this.state[region.getPosition()].collapsed = true;
57054 onRegionExpanded : function(region){
57055 this.state[region.getPosition()].collapsed = false;
57060 * Ext JS Library 1.1.1
57061 * Copyright(c) 2006-2007, Ext JS, LLC.
57063 * Originally Released Under LGPL - original licence link has changed is not relivant.
57066 * <script type="text/javascript">
57069 * @class Roo.ContentPanel
57070 * @extends Roo.util.Observable
57071 * @children Roo.form.Form Roo.JsonView Roo.View
57072 * @parent Roo.BorderLayout Roo.LayoutDialog builder
57073 * A basic ContentPanel element.
57074 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
57075 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
57076 * @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
57077 * @cfg {Boolean} closable True if the panel can be closed/removed
57078 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
57079 * @cfg {String|HTMLElement|Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
57080 * @cfg {Roo.Toolbar} toolbar A toolbar for this panel
57081 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
57082 * @cfg {String} title The title for this panel
57083 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
57084 * @cfg {String} url Calls {@link #setUrl} with this value
57085 * @cfg {String} region (center|north|south|east|west) [required] which region to put this panel on (when used with xtype constructors)
57086 * @cfg {String|Object} params When used with {@link #url}, calls {@link #setUrl} with this value
57087 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
57088 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
57089 * @cfg {String} style Extra style to add to the content panel
57090 * @cfg {Roo.menu.Menu} menu popup menu
57093 * Create a new ContentPanel.
57094 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
57095 * @param {String/Object} config A string to set only the title or a config object
57096 * @param {String} content (optional) Set the HTML content for this panel
57097 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
57099 Roo.ContentPanel = function(el, config, content){
57103 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
57107 if (config && config.parentLayout) {
57108 el = config.parentLayout.el.createChild();
57111 if(el.autoCreate){ // xtype is available if this is called from factory
57115 this.el = Roo.get(el);
57116 if(!this.el && config && config.autoCreate){
57117 if(typeof config.autoCreate == "object"){
57118 if(!config.autoCreate.id){
57119 config.autoCreate.id = config.id||el;
57121 this.el = Roo.DomHelper.append(document.body,
57122 config.autoCreate, true);
57124 this.el = Roo.DomHelper.append(document.body,
57125 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
57130 this.closable = false;
57131 this.loaded = false;
57132 this.active = false;
57133 if(typeof config == "string"){
57134 this.title = config;
57136 Roo.apply(this, config);
57139 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
57140 this.wrapEl = this.el.wrap();
57141 this.toolbar.container = this.el.insertSibling(false, 'before');
57142 this.toolbar = new Roo.Toolbar(this.toolbar);
57145 // xtype created footer. - not sure if will work as we normally have to render first..
57146 if (this.footer && !this.footer.el && this.footer.xtype) {
57147 if (!this.wrapEl) {
57148 this.wrapEl = this.el.wrap();
57151 this.footer.container = this.wrapEl.createChild();
57153 this.footer = Roo.factory(this.footer, Roo);
57158 this.resizeEl = Roo.get(this.resizeEl, true);
57160 this.resizeEl = this.el;
57162 // handle view.xtype
57170 * Fires when this panel is activated.
57171 * @param {Roo.ContentPanel} this
57175 * @event deactivate
57176 * Fires when this panel is activated.
57177 * @param {Roo.ContentPanel} this
57179 "deactivate" : true,
57183 * Fires when this panel is resized if fitToFrame is true.
57184 * @param {Roo.ContentPanel} this
57185 * @param {Number} width The width after any component adjustments
57186 * @param {Number} height The height after any component adjustments
57192 * Fires when this tab is created
57193 * @param {Roo.ContentPanel} this
57203 if(this.autoScroll){
57204 this.resizeEl.setStyle("overflow", "auto");
57206 // fix randome scrolling
57207 this.el.on('scroll', function() {
57208 Roo.log('fix random scolling');
57209 this.scrollTo('top',0);
57212 content = content || this.content;
57214 this.setContent(content);
57216 if(config && config.url){
57217 this.setUrl(this.url, this.params, this.loadOnce);
57222 Roo.ContentPanel.superclass.constructor.call(this);
57224 if (this.view && typeof(this.view.xtype) != 'undefined') {
57225 this.view.el = this.el.appendChild(document.createElement("div"));
57226 this.view = Roo.factory(this.view);
57227 this.view.render && this.view.render(false, '');
57231 this.fireEvent('render', this);
57234 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
57236 setRegion : function(region){
57237 this.region = region;
57239 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
57241 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
57246 * Returns the toolbar for this Panel if one was configured.
57247 * @return {Roo.Toolbar}
57249 getToolbar : function(){
57250 return this.toolbar;
57253 setActiveState : function(active){
57254 this.active = active;
57256 this.fireEvent("deactivate", this);
57258 this.fireEvent("activate", this);
57262 * Updates this panel's element
57263 * @param {String} content The new content
57264 * @param {Boolean} loadScripts (optional) true to look for and process scripts
57266 setContent : function(content, loadScripts){
57267 this.el.update(content, loadScripts);
57270 ignoreResize : function(w, h){
57271 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
57274 this.lastSize = {width: w, height: h};
57279 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
57280 * @return {Roo.UpdateManager} The UpdateManager
57282 getUpdateManager : function(){
57283 return this.el.getUpdateManager();
57286 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
57287 * @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:
57290 url: "your-url.php",
57291 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
57292 callback: yourFunction,
57293 scope: yourObject, //(optional scope)
57296 text: "Loading...",
57301 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
57302 * 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.
57303 * @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}
57304 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
57305 * @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.
57306 * @return {Roo.ContentPanel} this
57309 var um = this.el.getUpdateManager();
57310 um.update.apply(um, arguments);
57316 * 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.
57317 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
57318 * @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)
57319 * @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)
57320 * @return {Roo.UpdateManager} The UpdateManager
57322 setUrl : function(url, params, loadOnce){
57323 if(this.refreshDelegate){
57324 this.removeListener("activate", this.refreshDelegate);
57326 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
57327 this.on("activate", this.refreshDelegate);
57328 return this.el.getUpdateManager();
57331 _handleRefresh : function(url, params, loadOnce){
57332 if(!loadOnce || !this.loaded){
57333 var updater = this.el.getUpdateManager();
57334 updater.update(url, params, this._setLoaded.createDelegate(this));
57338 _setLoaded : function(){
57339 this.loaded = true;
57343 * Returns this panel's id
57346 getId : function(){
57351 * Returns this panel's element - used by regiosn to add.
57352 * @return {Roo.Element}
57354 getEl : function(){
57355 return this.wrapEl || this.el;
57358 adjustForComponents : function(width, height)
57360 //Roo.log('adjustForComponents ');
57361 if(this.resizeEl != this.el){
57362 width -= this.el.getFrameWidth('lr');
57363 height -= this.el.getFrameWidth('tb');
57366 var te = this.toolbar.getEl();
57367 height -= te.getHeight();
57368 te.setWidth(width);
57371 var te = this.footer.getEl();
57372 //Roo.log("footer:" + te.getHeight());
57374 height -= te.getHeight();
57375 te.setWidth(width);
57379 if(this.adjustments){
57380 width += this.adjustments[0];
57381 height += this.adjustments[1];
57383 return {"width": width, "height": height};
57386 setSize : function(width, height){
57387 if(this.fitToFrame && !this.ignoreResize(width, height)){
57388 if(this.fitContainer && this.resizeEl != this.el){
57389 this.el.setSize(width, height);
57391 var size = this.adjustForComponents(width, height);
57392 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
57393 this.fireEvent('resize', this, size.width, size.height);
57398 * Returns this panel's title
57401 getTitle : function(){
57406 * Set this panel's title
57407 * @param {String} title
57409 setTitle : function(title){
57410 this.title = title;
57412 this.region.updatePanelTitle(this, title);
57417 * Returns true is this panel was configured to be closable
57418 * @return {Boolean}
57420 isClosable : function(){
57421 return this.closable;
57424 beforeSlide : function(){
57426 this.resizeEl.clip();
57429 afterSlide : function(){
57431 this.resizeEl.unclip();
57435 * Force a content refresh from the URL specified in the {@link #setUrl} method.
57436 * Will fail silently if the {@link #setUrl} method has not been called.
57437 * This does not activate the panel, just updates its content.
57439 refresh : function(){
57440 if(this.refreshDelegate){
57441 this.loaded = false;
57442 this.refreshDelegate();
57447 * Destroys this panel
57449 destroy : function(){
57450 this.el.removeAllListeners();
57451 var tempEl = document.createElement("span");
57452 tempEl.appendChild(this.el.dom);
57453 tempEl.innerHTML = "";
57459 * form - if the content panel contains a form - this is a reference to it.
57460 * @type {Roo.form.Form}
57464 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
57465 * This contains a reference to it.
57471 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
57481 * @param {Object} cfg Xtype definition of item to add.
57484 addxtype : function(cfg) {
57486 if (cfg.xtype.match(/^Form$/)) {
57489 //if (this.footer) {
57490 // el = this.footer.container.insertSibling(false, 'before');
57492 el = this.el.createChild();
57495 this.form = new Roo.form.Form(cfg);
57498 if ( this.form.allItems.length) {
57499 this.form.render(el.dom);
57503 // should only have one of theses..
57504 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
57505 // views.. should not be just added - used named prop 'view''
57507 cfg.el = this.el.appendChild(document.createElement("div"));
57510 var ret = new Roo.factory(cfg);
57512 ret.render && ret.render(false, ''); // render blank..
57521 * @class Roo.GridPanel
57522 * @extends Roo.ContentPanel
57523 * @parent Roo.BorderLayout Roo.LayoutDialog builder
57525 * Create a new GridPanel.
57526 * @cfg {Roo.grid.Grid} grid The grid for this panel
57528 Roo.GridPanel = function(grid, config){
57530 // universal ctor...
57531 if (typeof(grid.grid) != 'undefined') {
57533 grid = config.grid;
57535 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
57536 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
57538 this.wrapper.dom.appendChild(grid.getGridEl().dom);
57540 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
57543 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
57545 // xtype created footer. - not sure if will work as we normally have to render first..
57546 if (this.footer && !this.footer.el && this.footer.xtype) {
57548 this.footer.container = this.grid.getView().getFooterPanel(true);
57549 this.footer.dataSource = this.grid.dataSource;
57550 this.footer = Roo.factory(this.footer, Roo);
57554 grid.monitorWindowResize = false; // turn off autosizing
57555 grid.autoHeight = false;
57556 grid.autoWidth = false;
57558 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
57561 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
57562 getId : function(){
57563 return this.grid.id;
57567 * Returns the grid for this panel
57568 * @return {Roo.grid.Grid}
57570 getGrid : function(){
57574 setSize : function(width, height){
57575 if(!this.ignoreResize(width, height)){
57576 var grid = this.grid;
57577 var size = this.adjustForComponents(width, height);
57578 grid.getGridEl().setSize(size.width, size.height);
57583 beforeSlide : function(){
57584 this.grid.getView().scroller.clip();
57587 afterSlide : function(){
57588 this.grid.getView().scroller.unclip();
57591 destroy : function(){
57592 this.grid.destroy();
57594 Roo.GridPanel.superclass.destroy.call(this);
57600 * @class Roo.NestedLayoutPanel
57601 * @extends Roo.ContentPanel
57602 * @parent Roo.BorderLayout Roo.LayoutDialog builder
57603 * @cfg Roo.BorderLayout} layout [required] The layout for this panel
57607 * Create a new NestedLayoutPanel.
57610 * @param {Roo.BorderLayout} layout [required] The layout for this panel
57611 * @param {String/Object} config A string to set only the title or a config object
57613 Roo.NestedLayoutPanel = function(layout, config)
57615 // construct with only one argument..
57616 /* FIXME - implement nicer consturctors
57617 if (layout.layout) {
57619 layout = config.layout;
57620 delete config.layout;
57622 if (layout.xtype && !layout.getEl) {
57623 // then layout needs constructing..
57624 layout = Roo.factory(layout, Roo);
57629 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
57631 layout.monitorWindowResize = false; // turn off autosizing
57632 this.layout = layout;
57633 this.layout.getEl().addClass("x-layout-nested-layout");
57640 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
57642 setSize : function(width, height){
57643 if(!this.ignoreResize(width, height)){
57644 var size = this.adjustForComponents(width, height);
57645 var el = this.layout.getEl();
57646 el.setSize(size.width, size.height);
57647 var touch = el.dom.offsetWidth;
57648 this.layout.layout();
57649 // ie requires a double layout on the first pass
57650 if(Roo.isIE && !this.initialized){
57651 this.initialized = true;
57652 this.layout.layout();
57657 // activate all subpanels if not currently active..
57659 setActiveState : function(active){
57660 this.active = active;
57662 this.fireEvent("deactivate", this);
57666 this.fireEvent("activate", this);
57667 // not sure if this should happen before or after..
57668 if (!this.layout) {
57669 return; // should not happen..
57672 for (var r in this.layout.regions) {
57673 reg = this.layout.getRegion(r);
57674 if (reg.getActivePanel()) {
57675 //reg.showPanel(reg.getActivePanel()); // force it to activate..
57676 reg.setActivePanel(reg.getActivePanel());
57679 if (!reg.panels.length) {
57682 reg.showPanel(reg.getPanel(0));
57691 * Returns the nested BorderLayout for this panel
57692 * @return {Roo.BorderLayout}
57694 getLayout : function(){
57695 return this.layout;
57699 * Adds a xtype elements to the layout of the nested panel
57703 xtype : 'ContentPanel',
57710 xtype : 'NestedLayoutPanel',
57716 items : [ ... list of content panels or nested layout panels.. ]
57720 * @param {Object} cfg Xtype definition of item to add.
57722 addxtype : function(cfg) {
57723 return this.layout.addxtype(cfg);
57728 Roo.ScrollPanel = function(el, config, content){
57729 config = config || {};
57730 config.fitToFrame = true;
57731 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
57733 this.el.dom.style.overflow = "hidden";
57734 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
57735 this.el.removeClass("x-layout-inactive-content");
57736 this.el.on("mousewheel", this.onWheel, this);
57738 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
57739 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
57740 up.unselectable(); down.unselectable();
57741 up.on("click", this.scrollUp, this);
57742 down.on("click", this.scrollDown, this);
57743 up.addClassOnOver("x-scroller-btn-over");
57744 down.addClassOnOver("x-scroller-btn-over");
57745 up.addClassOnClick("x-scroller-btn-click");
57746 down.addClassOnClick("x-scroller-btn-click");
57747 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
57749 this.resizeEl = this.el;
57750 this.el = wrap; this.up = up; this.down = down;
57753 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
57755 wheelIncrement : 5,
57756 scrollUp : function(){
57757 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
57760 scrollDown : function(){
57761 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
57764 afterScroll : function(){
57765 var el = this.resizeEl;
57766 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
57767 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
57768 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
57771 setSize : function(){
57772 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
57773 this.afterScroll();
57776 onWheel : function(e){
57777 var d = e.getWheelDelta();
57778 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
57779 this.afterScroll();
57783 setContent : function(content, loadScripts){
57784 this.resizeEl.update(content, loadScripts);
57792 * @class Roo.TreePanel
57793 * @extends Roo.ContentPanel
57794 * @parent Roo.BorderLayout Roo.LayoutDialog builder
57795 * Treepanel component
57798 * Create a new TreePanel. - defaults to fit/scoll contents.
57799 * @param {String/Object} config A string to set only the panel's title, or a config object
57801 Roo.TreePanel = function(config){
57802 var el = config.el;
57803 var tree = config.tree;
57804 delete config.tree;
57805 delete config.el; // hopefull!
57807 // wrapper for IE7 strict & safari scroll issue
57809 var treeEl = el.createChild();
57810 config.resizeEl = treeEl;
57814 Roo.TreePanel.superclass.constructor.call(this, el, config);
57817 this.tree = new Roo.tree.TreePanel(treeEl , tree);
57818 //console.log(tree);
57819 this.on('activate', function()
57821 if (this.tree.rendered) {
57824 //console.log('render tree');
57825 this.tree.render();
57827 // this should not be needed.. - it's actually the 'el' that resizes?
57828 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
57830 //this.on('resize', function (cp, w, h) {
57831 // this.tree.innerCt.setWidth(w);
57832 // this.tree.innerCt.setHeight(h);
57833 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
57840 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
57844 * @cfg {Roo.tree.TreePanel} tree [required] The tree TreePanel, with config etc.
57862 * Ext JS Library 1.1.1
57863 * Copyright(c) 2006-2007, Ext JS, LLC.
57865 * Originally Released Under LGPL - original licence link has changed is not relivant.
57868 * <script type="text/javascript">
57873 * @class Roo.ReaderLayout
57874 * @extends Roo.BorderLayout
57875 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
57876 * center region containing two nested regions (a top one for a list view and one for item preview below),
57877 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
57878 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
57879 * expedites the setup of the overall layout and regions for this common application style.
57882 var reader = new Roo.ReaderLayout();
57883 var CP = Roo.ContentPanel; // shortcut for adding
57885 reader.beginUpdate();
57886 reader.add("north", new CP("north", "North"));
57887 reader.add("west", new CP("west", {title: "West"}));
57888 reader.add("east", new CP("east", {title: "East"}));
57890 reader.regions.listView.add(new CP("listView", "List"));
57891 reader.regions.preview.add(new CP("preview", "Preview"));
57892 reader.endUpdate();
57895 * Create a new ReaderLayout
57896 * @param {Object} config Configuration options
57897 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
57898 * document.body if omitted)
57900 Roo.ReaderLayout = function(config, renderTo){
57901 var c = config || {size:{}};
57902 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
57903 north: c.north !== false ? Roo.apply({
57907 }, c.north) : false,
57908 west: c.west !== false ? Roo.apply({
57916 margins:{left:5,right:0,bottom:5,top:5},
57917 cmargins:{left:5,right:5,bottom:5,top:5}
57918 }, c.west) : false,
57919 east: c.east !== false ? Roo.apply({
57927 margins:{left:0,right:5,bottom:5,top:5},
57928 cmargins:{left:5,right:5,bottom:5,top:5}
57929 }, c.east) : false,
57930 center: Roo.apply({
57931 tabPosition: 'top',
57935 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
57939 this.el.addClass('x-reader');
57941 this.beginUpdate();
57943 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
57944 south: c.preview !== false ? Roo.apply({
57951 cmargins:{top:5,left:0, right:0, bottom:0}
57952 }, c.preview) : false,
57953 center: Roo.apply({
57959 this.add('center', new Roo.NestedLayoutPanel(inner,
57960 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
57964 this.regions.preview = inner.getRegion('south');
57965 this.regions.listView = inner.getRegion('center');
57968 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
57970 * Ext JS Library 1.1.1
57971 * Copyright(c) 2006-2007, Ext JS, LLC.
57973 * Originally Released Under LGPL - original licence link has changed is not relivant.
57976 * <script type="text/javascript">
57980 * @class Roo.grid.Grid
57981 * @extends Roo.util.Observable
57982 * This class represents the primary interface of a component based grid control.
57983 * <br><br>Usage:<pre><code>
57984 var grid = new Roo.grid.Grid("my-container-id", {
57987 selModel: mySelectionModel,
57988 autoSizeColumns: true,
57989 monitorWindowResize: false,
57990 trackMouseOver: true
57995 * <b>Common Problems:</b><br/>
57996 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
57997 * element will correct this<br/>
57998 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
57999 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
58000 * are unpredictable.<br/>
58001 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
58002 * grid to calculate dimensions/offsets.<br/>
58004 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58005 * The container MUST have some type of size defined for the grid to fill. The container will be
58006 * automatically set to position relative if it isn't already.
58007 * @param {Object} config A config object that sets properties on this grid.
58009 Roo.grid.Grid = function(container, config){
58010 // initialize the container
58011 this.container = Roo.get(container);
58012 this.container.update("");
58013 this.container.setStyle("overflow", "hidden");
58014 this.container.addClass('x-grid-container');
58016 this.id = this.container.id;
58018 Roo.apply(this, config);
58019 // check and correct shorthanded configs
58021 this.dataSource = this.ds;
58025 this.colModel = this.cm;
58029 this.selModel = this.sm;
58033 if (this.selModel) {
58034 this.selModel = Roo.factory(this.selModel, Roo.grid);
58035 this.sm = this.selModel;
58036 this.sm.xmodule = this.xmodule || false;
58038 if (typeof(this.colModel.config) == 'undefined') {
58039 this.colModel = new Roo.grid.ColumnModel(this.colModel);
58040 this.cm = this.colModel;
58041 this.cm.xmodule = this.xmodule || false;
58043 if (this.dataSource) {
58044 this.dataSource= Roo.factory(this.dataSource, Roo.data);
58045 this.ds = this.dataSource;
58046 this.ds.xmodule = this.xmodule || false;
58053 this.container.setWidth(this.width);
58057 this.container.setHeight(this.height);
58064 * The raw click event for the entire grid.
58065 * @param {Roo.EventObject} e
58070 * The raw dblclick event for the entire grid.
58071 * @param {Roo.EventObject} e
58075 * @event contextmenu
58076 * The raw contextmenu event for the entire grid.
58077 * @param {Roo.EventObject} e
58079 "contextmenu" : true,
58082 * The raw mousedown event for the entire grid.
58083 * @param {Roo.EventObject} e
58085 "mousedown" : true,
58088 * The raw mouseup event for the entire grid.
58089 * @param {Roo.EventObject} e
58094 * The raw mouseover event for the entire grid.
58095 * @param {Roo.EventObject} e
58097 "mouseover" : true,
58100 * The raw mouseout event for the entire grid.
58101 * @param {Roo.EventObject} e
58106 * The raw keypress event for the entire grid.
58107 * @param {Roo.EventObject} e
58112 * The raw keydown event for the entire grid.
58113 * @param {Roo.EventObject} e
58121 * Fires when a cell is clicked
58122 * @param {Grid} this
58123 * @param {Number} rowIndex
58124 * @param {Number} columnIndex
58125 * @param {Roo.EventObject} e
58127 "cellclick" : true,
58129 * @event celldblclick
58130 * Fires when a cell is double clicked
58131 * @param {Grid} this
58132 * @param {Number} rowIndex
58133 * @param {Number} columnIndex
58134 * @param {Roo.EventObject} e
58136 "celldblclick" : true,
58139 * Fires when a row is clicked
58140 * @param {Grid} this
58141 * @param {Number} rowIndex
58142 * @param {Roo.EventObject} e
58146 * @event rowdblclick
58147 * Fires when a row is double clicked
58148 * @param {Grid} this
58149 * @param {Number} rowIndex
58150 * @param {Roo.EventObject} e
58152 "rowdblclick" : true,
58154 * @event headerclick
58155 * Fires when a header is clicked
58156 * @param {Grid} this
58157 * @param {Number} columnIndex
58158 * @param {Roo.EventObject} e
58160 "headerclick" : true,
58162 * @event headerdblclick
58163 * Fires when a header cell is double clicked
58164 * @param {Grid} this
58165 * @param {Number} columnIndex
58166 * @param {Roo.EventObject} e
58168 "headerdblclick" : true,
58170 * @event rowcontextmenu
58171 * Fires when a row is right clicked
58172 * @param {Grid} this
58173 * @param {Number} rowIndex
58174 * @param {Roo.EventObject} e
58176 "rowcontextmenu" : true,
58178 * @event cellcontextmenu
58179 * Fires when a cell is right clicked
58180 * @param {Grid} this
58181 * @param {Number} rowIndex
58182 * @param {Number} cellIndex
58183 * @param {Roo.EventObject} e
58185 "cellcontextmenu" : true,
58187 * @event headercontextmenu
58188 * Fires when a header is right clicked
58189 * @param {Grid} this
58190 * @param {Number} columnIndex
58191 * @param {Roo.EventObject} e
58193 "headercontextmenu" : true,
58195 * @event bodyscroll
58196 * Fires when the body element is scrolled
58197 * @param {Number} scrollLeft
58198 * @param {Number} scrollTop
58200 "bodyscroll" : true,
58202 * @event columnresize
58203 * Fires when the user resizes a column
58204 * @param {Number} columnIndex
58205 * @param {Number} newSize
58207 "columnresize" : true,
58209 * @event columnmove
58210 * Fires when the user moves a column
58211 * @param {Number} oldIndex
58212 * @param {Number} newIndex
58214 "columnmove" : true,
58217 * Fires when row(s) start being dragged
58218 * @param {Grid} this
58219 * @param {Roo.GridDD} dd The drag drop object
58220 * @param {event} e The raw browser event
58222 "startdrag" : true,
58225 * Fires when a drag operation is complete
58226 * @param {Grid} this
58227 * @param {Roo.GridDD} dd The drag drop object
58228 * @param {event} e The raw browser event
58233 * Fires when dragged row(s) are dropped on a valid DD target
58234 * @param {Grid} this
58235 * @param {Roo.GridDD} dd The drag drop object
58236 * @param {String} targetId The target drag drop object
58237 * @param {event} e The raw browser event
58242 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
58243 * @param {Grid} this
58244 * @param {Roo.GridDD} dd The drag drop object
58245 * @param {String} targetId The target drag drop object
58246 * @param {event} e The raw browser event
58251 * Fires when the dragged row(s) first cross another DD target while being dragged
58252 * @param {Grid} this
58253 * @param {Roo.GridDD} dd The drag drop object
58254 * @param {String} targetId The target drag drop object
58255 * @param {event} e The raw browser event
58257 "dragenter" : true,
58260 * Fires when the dragged row(s) leave another DD target while being dragged
58261 * @param {Grid} this
58262 * @param {Roo.GridDD} dd The drag drop object
58263 * @param {String} targetId The target drag drop object
58264 * @param {event} e The raw browser event
58269 * Fires when a row is rendered, so you can change add a style to it.
58270 * @param {GridView} gridview The grid view
58271 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
58277 * Fires when the grid is rendered
58278 * @param {Grid} grid
58283 Roo.grid.Grid.superclass.constructor.call(this);
58285 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
58288 * @cfg {Roo.grid.AbstractSelectionModel} sm The selection Model (default = Roo.grid.RowSelectionModel)
58291 * @cfg {Roo.grid.GridView} view The view that renders the grid (default = Roo.grid.GridView)
58294 * @cfg {Roo.grid.ColumnModel} cm[] The columns of the grid
58297 * @cfg {Roo.grid.Store} ds The data store for the grid
58300 * @cfg {Roo.Toolbar} toolbar a toolbar for buttons etc.
58303 * @cfg {String} ddGroup - drag drop group.
58306 * @cfg {String} dragGroup - drag group (?? not sure if needed.)
58310 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
58312 minColumnWidth : 25,
58315 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
58316 * <b>on initial render.</b> It is more efficient to explicitly size the columns
58317 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
58319 autoSizeColumns : false,
58322 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
58324 autoSizeHeaders : true,
58327 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
58329 monitorWindowResize : true,
58332 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
58333 * rows measured to get a columns size. Default is 0 (all rows).
58335 maxRowsToMeasure : 0,
58338 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
58340 trackMouseOver : true,
58343 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
58346 * @cfg {Boolean} enableDrop True to enable drop of elements. Default is false. (double check if this is needed?)
58350 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
58352 enableDragDrop : false,
58355 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
58357 enableColumnMove : true,
58360 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
58362 enableColumnHide : true,
58365 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
58367 enableRowHeightSync : false,
58370 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
58375 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
58377 autoHeight : false,
58380 * @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.
58382 autoExpandColumn : false,
58385 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
58388 autoExpandMin : 50,
58391 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
58393 autoExpandMax : 1000,
58396 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
58401 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
58405 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
58409 * @cfg {boolean} sortColMenu Sort the column order menu when it shows (usefull for long lists..) default false
58411 sortColMenu : false,
58417 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
58418 * of a fixed width. Default is false.
58421 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
58426 * @cfg {String} ddText Configures the text is the drag proxy (defaults to "%0 selected row(s)").
58427 * %0 is replaced with the number of selected rows.
58429 ddText : "{0} selected row{1}",
58433 * Called once after all setup has been completed and the grid is ready to be rendered.
58434 * @return {Roo.grid.Grid} this
58436 render : function()
58438 var c = this.container;
58439 // try to detect autoHeight/width mode
58440 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
58441 this.autoHeight = true;
58443 var view = this.getView();
58446 c.on("click", this.onClick, this);
58447 c.on("dblclick", this.onDblClick, this);
58448 c.on("contextmenu", this.onContextMenu, this);
58449 c.on("keydown", this.onKeyDown, this);
58451 c.on("touchstart", this.onTouchStart, this);
58454 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
58456 this.getSelectionModel().init(this);
58461 this.loadMask = new Roo.LoadMask(this.container,
58462 Roo.apply({store:this.dataSource}, this.loadMask));
58466 if (this.toolbar && this.toolbar.xtype) {
58467 this.toolbar.container = this.getView().getHeaderPanel(true);
58468 this.toolbar = new Roo.Toolbar(this.toolbar);
58470 if (this.footer && this.footer.xtype) {
58471 this.footer.dataSource = this.getDataSource();
58472 this.footer.container = this.getView().getFooterPanel(true);
58473 this.footer = Roo.factory(this.footer, Roo);
58475 if (this.dropTarget && this.dropTarget.xtype) {
58476 delete this.dropTarget.xtype;
58477 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
58481 this.rendered = true;
58482 this.fireEvent('render', this);
58487 * Reconfigures the grid to use a different Store and Column Model.
58488 * The View will be bound to the new objects and refreshed.
58489 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
58490 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
58492 reconfigure : function(dataSource, colModel){
58494 this.loadMask.destroy();
58495 this.loadMask = new Roo.LoadMask(this.container,
58496 Roo.apply({store:dataSource}, this.loadMask));
58498 this.view.bind(dataSource, colModel);
58499 this.dataSource = dataSource;
58500 this.colModel = colModel;
58501 this.view.refresh(true);
58505 * Add's a column, default at the end..
58507 * @param {int} position to add (default end)
58508 * @param {Array} of objects of column configuration see {@link Roo.grid.ColumnModel}
58510 addColumns : function(pos, ar)
58513 for (var i =0;i< ar.length;i++) {
58515 cfg.id = typeof(cfg.id) == 'undefined' ? Roo.id() : cfg.id; // don't normally use this..
58516 this.cm.lookup[cfg.id] = cfg;
58520 if (typeof(pos) == 'undefined' || pos >= this.cm.config.length) {
58521 pos = this.cm.config.length; //this.cm.config.push(cfg);
58523 pos = Math.max(0,pos);
58526 this.cm.config.splice.apply(this.cm.config, ar);
58530 this.view.generateRules(this.cm);
58531 this.view.refresh(true);
58539 onKeyDown : function(e){
58540 this.fireEvent("keydown", e);
58544 * Destroy this grid.
58545 * @param {Boolean} removeEl True to remove the element
58547 destroy : function(removeEl, keepListeners){
58549 this.loadMask.destroy();
58551 var c = this.container;
58552 c.removeAllListeners();
58553 this.view.destroy();
58554 this.colModel.purgeListeners();
58555 if(!keepListeners){
58556 this.purgeListeners();
58559 if(removeEl === true){
58565 processEvent : function(name, e){
58566 // does this fire select???
58567 //Roo.log('grid:processEvent ' + name);
58569 if (name != 'touchstart' ) {
58570 this.fireEvent(name, e);
58573 var t = e.getTarget();
58575 var header = v.findHeaderIndex(t);
58576 if(header !== false){
58577 var ename = name == 'touchstart' ? 'click' : name;
58579 this.fireEvent("header" + ename, this, header, e);
58581 var row = v.findRowIndex(t);
58582 var cell = v.findCellIndex(t);
58583 if (name == 'touchstart') {
58584 // first touch is always a click.
58585 // hopefull this happens after selection is updated.?
58588 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
58589 var cs = this.selModel.getSelectedCell();
58590 if (row == cs[0] && cell == cs[1]){
58594 if (typeof(this.selModel.getSelections) != 'undefined') {
58595 var cs = this.selModel.getSelections();
58596 var ds = this.dataSource;
58597 if (cs.length == 1 && ds.getAt(row) == cs[0]){
58608 this.fireEvent("row" + name, this, row, e);
58609 if(cell !== false){
58610 this.fireEvent("cell" + name, this, row, cell, e);
58617 onClick : function(e){
58618 this.processEvent("click", e);
58621 onTouchStart : function(e){
58622 this.processEvent("touchstart", e);
58626 onContextMenu : function(e, t){
58627 this.processEvent("contextmenu", e);
58631 onDblClick : function(e){
58632 this.processEvent("dblclick", e);
58636 walkCells : function(row, col, step, fn, scope){
58637 var cm = this.colModel, clen = cm.getColumnCount();
58638 var ds = this.dataSource, rlen = ds.getCount(), first = true;
58650 if(fn.call(scope || this, row, col, cm) === true){
58668 if(fn.call(scope || this, row, col, cm) === true){
58680 getSelections : function(){
58681 return this.selModel.getSelections();
58685 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
58686 * but if manual update is required this method will initiate it.
58688 autoSize : function(){
58690 this.view.layout();
58691 if(this.view.adjustForScroll){
58692 this.view.adjustForScroll();
58698 * Returns the grid's underlying element.
58699 * @return {Element} The element
58701 getGridEl : function(){
58702 return this.container;
58705 // private for compatibility, overridden by editor grid
58706 stopEditing : function(){},
58709 * Returns the grid's SelectionModel.
58710 * @return {SelectionModel}
58712 getSelectionModel : function(){
58713 if(!this.selModel){
58714 this.selModel = new Roo.grid.RowSelectionModel();
58716 return this.selModel;
58720 * Returns the grid's DataSource.
58721 * @return {DataSource}
58723 getDataSource : function(){
58724 return this.dataSource;
58728 * Returns the grid's ColumnModel.
58729 * @return {ColumnModel}
58731 getColumnModel : function(){
58732 return this.colModel;
58736 * Returns the grid's GridView object.
58737 * @return {GridView}
58739 getView : function(){
58741 this.view = new Roo.grid.GridView(this.viewConfig);
58742 this.relayEvents(this.view, [
58743 "beforerowremoved", "beforerowsinserted",
58744 "beforerefresh", "rowremoved",
58745 "rowsinserted", "rowupdated" ,"refresh"
58751 * Called to get grid's drag proxy text, by default returns this.ddText.
58752 * Override this to put something different in the dragged text.
58755 getDragDropText : function(){
58756 var count = this.selModel.getCount();
58757 return String.format(this.ddText, count, count == 1 ? '' : 's');
58762 * Ext JS Library 1.1.1
58763 * Copyright(c) 2006-2007, Ext JS, LLC.
58765 * Originally Released Under LGPL - original licence link has changed is not relivant.
58768 * <script type="text/javascript">
58771 * @class Roo.grid.AbstractGridView
58772 * @extends Roo.util.Observable
58774 * Abstract base class for grid Views
58777 Roo.grid.AbstractGridView = function(){
58781 "beforerowremoved" : true,
58782 "beforerowsinserted" : true,
58783 "beforerefresh" : true,
58784 "rowremoved" : true,
58785 "rowsinserted" : true,
58786 "rowupdated" : true,
58789 Roo.grid.AbstractGridView.superclass.constructor.call(this);
58792 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
58793 rowClass : "x-grid-row",
58794 cellClass : "x-grid-cell",
58795 tdClass : "x-grid-td",
58796 hdClass : "x-grid-hd",
58797 splitClass : "x-grid-hd-split",
58799 init: function(grid){
58801 var cid = this.grid.getGridEl().id;
58802 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
58803 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
58804 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
58805 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
58808 getColumnRenderers : function(){
58809 var renderers = [];
58810 var cm = this.grid.colModel;
58811 var colCount = cm.getColumnCount();
58812 for(var i = 0; i < colCount; i++){
58813 renderers[i] = cm.getRenderer(i);
58818 getColumnIds : function(){
58820 var cm = this.grid.colModel;
58821 var colCount = cm.getColumnCount();
58822 for(var i = 0; i < colCount; i++){
58823 ids[i] = cm.getColumnId(i);
58828 getDataIndexes : function(){
58829 if(!this.indexMap){
58830 this.indexMap = this.buildIndexMap();
58832 return this.indexMap.colToData;
58835 getColumnIndexByDataIndex : function(dataIndex){
58836 if(!this.indexMap){
58837 this.indexMap = this.buildIndexMap();
58839 return this.indexMap.dataToCol[dataIndex];
58843 * Set a css style for a column dynamically.
58844 * @param {Number} colIndex The index of the column
58845 * @param {String} name The css property name
58846 * @param {String} value The css value
58848 setCSSStyle : function(colIndex, name, value){
58849 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
58850 Roo.util.CSS.updateRule(selector, name, value);
58853 generateRules : function(cm){
58854 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
58855 Roo.util.CSS.removeStyleSheet(rulesId);
58856 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
58857 var cid = cm.getColumnId(i);
58858 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
58859 this.tdSelector, cid, " {\n}\n",
58860 this.hdSelector, cid, " {\n}\n",
58861 this.splitSelector, cid, " {\n}\n");
58863 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
58867 * Ext JS Library 1.1.1
58868 * Copyright(c) 2006-2007, Ext JS, LLC.
58870 * Originally Released Under LGPL - original licence link has changed is not relivant.
58873 * <script type="text/javascript">
58877 // This is a support class used internally by the Grid components
58878 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
58880 this.view = grid.getView();
58881 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
58882 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
58884 this.setHandleElId(Roo.id(hd));
58885 this.setOuterHandleElId(Roo.id(hd2));
58887 this.scroll = false;
58889 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
58891 getDragData : function(e){
58892 var t = Roo.lib.Event.getTarget(e);
58893 var h = this.view.findHeaderCell(t);
58895 return {ddel: h.firstChild, header:h};
58900 onInitDrag : function(e){
58901 this.view.headersDisabled = true;
58902 var clone = this.dragData.ddel.cloneNode(true);
58903 clone.id = Roo.id();
58904 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
58905 this.proxy.update(clone);
58909 afterValidDrop : function(){
58911 setTimeout(function(){
58912 v.headersDisabled = false;
58916 afterInvalidDrop : function(){
58918 setTimeout(function(){
58919 v.headersDisabled = false;
58925 * Ext JS Library 1.1.1
58926 * Copyright(c) 2006-2007, Ext JS, LLC.
58928 * Originally Released Under LGPL - original licence link has changed is not relivant.
58931 * <script type="text/javascript">
58934 // This is a support class used internally by the Grid components
58935 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
58937 this.view = grid.getView();
58938 // split the proxies so they don't interfere with mouse events
58939 this.proxyTop = Roo.DomHelper.append(document.body, {
58940 cls:"col-move-top", html:" "
58942 this.proxyBottom = Roo.DomHelper.append(document.body, {
58943 cls:"col-move-bottom", html:" "
58945 this.proxyTop.hide = this.proxyBottom.hide = function(){
58946 this.setLeftTop(-100,-100);
58947 this.setStyle("visibility", "hidden");
58949 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
58950 // temporarily disabled
58951 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
58952 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
58954 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
58955 proxyOffsets : [-4, -9],
58956 fly: Roo.Element.fly,
58958 getTargetFromEvent : function(e){
58959 var t = Roo.lib.Event.getTarget(e);
58960 var cindex = this.view.findCellIndex(t);
58961 if(cindex !== false){
58962 return this.view.getHeaderCell(cindex);
58967 nextVisible : function(h){
58968 var v = this.view, cm = this.grid.colModel;
58971 if(!cm.isHidden(v.getCellIndex(h))){
58979 prevVisible : function(h){
58980 var v = this.view, cm = this.grid.colModel;
58983 if(!cm.isHidden(v.getCellIndex(h))){
58991 positionIndicator : function(h, n, e){
58992 var x = Roo.lib.Event.getPageX(e);
58993 var r = Roo.lib.Dom.getRegion(n.firstChild);
58994 var px, pt, py = r.top + this.proxyOffsets[1];
58995 if((r.right - x) <= (r.right-r.left)/2){
58996 px = r.right+this.view.borderWidth;
59002 var oldIndex = this.view.getCellIndex(h);
59003 var newIndex = this.view.getCellIndex(n);
59005 if(this.grid.colModel.isFixed(newIndex)){
59009 var locked = this.grid.colModel.isLocked(newIndex);
59014 if(oldIndex < newIndex){
59017 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
59020 px += this.proxyOffsets[0];
59021 this.proxyTop.setLeftTop(px, py);
59022 this.proxyTop.show();
59023 if(!this.bottomOffset){
59024 this.bottomOffset = this.view.mainHd.getHeight();
59026 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
59027 this.proxyBottom.show();
59031 onNodeEnter : function(n, dd, e, data){
59032 if(data.header != n){
59033 this.positionIndicator(data.header, n, e);
59037 onNodeOver : function(n, dd, e, data){
59038 var result = false;
59039 if(data.header != n){
59040 result = this.positionIndicator(data.header, n, e);
59043 this.proxyTop.hide();
59044 this.proxyBottom.hide();
59046 return result ? this.dropAllowed : this.dropNotAllowed;
59049 onNodeOut : function(n, dd, e, data){
59050 this.proxyTop.hide();
59051 this.proxyBottom.hide();
59054 onNodeDrop : function(n, dd, e, data){
59055 var h = data.header;
59057 var cm = this.grid.colModel;
59058 var x = Roo.lib.Event.getPageX(e);
59059 var r = Roo.lib.Dom.getRegion(n.firstChild);
59060 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
59061 var oldIndex = this.view.getCellIndex(h);
59062 var newIndex = this.view.getCellIndex(n);
59063 var locked = cm.isLocked(newIndex);
59067 if(oldIndex < newIndex){
59070 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
59073 cm.setLocked(oldIndex, locked, true);
59074 cm.moveColumn(oldIndex, newIndex);
59075 this.grid.fireEvent("columnmove", oldIndex, newIndex);
59083 * Ext JS Library 1.1.1
59084 * Copyright(c) 2006-2007, Ext JS, LLC.
59086 * Originally Released Under LGPL - original licence link has changed is not relivant.
59089 * <script type="text/javascript">
59093 * @class Roo.grid.GridView
59094 * @extends Roo.util.Observable
59097 * @param {Object} config
59099 Roo.grid.GridView = function(config){
59100 Roo.grid.GridView.superclass.constructor.call(this);
59103 Roo.apply(this, config);
59106 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
59108 unselectable : 'unselectable="on"',
59109 unselectableCls : 'x-unselectable',
59112 rowClass : "x-grid-row",
59114 cellClass : "x-grid-col",
59116 tdClass : "x-grid-td",
59118 hdClass : "x-grid-hd",
59120 splitClass : "x-grid-split",
59122 sortClasses : ["sort-asc", "sort-desc"],
59124 enableMoveAnim : false,
59128 dh : Roo.DomHelper,
59130 fly : Roo.Element.fly,
59132 css : Roo.util.CSS,
59138 scrollIncrement : 22,
59140 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
59142 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
59144 bind : function(ds, cm){
59146 this.ds.un("load", this.onLoad, this);
59147 this.ds.un("datachanged", this.onDataChange, this);
59148 this.ds.un("add", this.onAdd, this);
59149 this.ds.un("remove", this.onRemove, this);
59150 this.ds.un("update", this.onUpdate, this);
59151 this.ds.un("clear", this.onClear, this);
59154 ds.on("load", this.onLoad, this);
59155 ds.on("datachanged", this.onDataChange, this);
59156 ds.on("add", this.onAdd, this);
59157 ds.on("remove", this.onRemove, this);
59158 ds.on("update", this.onUpdate, this);
59159 ds.on("clear", this.onClear, this);
59164 this.cm.un("widthchange", this.onColWidthChange, this);
59165 this.cm.un("headerchange", this.onHeaderChange, this);
59166 this.cm.un("hiddenchange", this.onHiddenChange, this);
59167 this.cm.un("columnmoved", this.onColumnMove, this);
59168 this.cm.un("columnlockchange", this.onColumnLock, this);
59171 this.generateRules(cm);
59172 cm.on("widthchange", this.onColWidthChange, this);
59173 cm.on("headerchange", this.onHeaderChange, this);
59174 cm.on("hiddenchange", this.onHiddenChange, this);
59175 cm.on("columnmoved", this.onColumnMove, this);
59176 cm.on("columnlockchange", this.onColumnLock, this);
59181 init: function(grid){
59182 Roo.grid.GridView.superclass.init.call(this, grid);
59184 this.bind(grid.dataSource, grid.colModel);
59186 grid.on("headerclick", this.handleHeaderClick, this);
59188 if(grid.trackMouseOver){
59189 grid.on("mouseover", this.onRowOver, this);
59190 grid.on("mouseout", this.onRowOut, this);
59192 grid.cancelTextSelection = function(){};
59193 this.gridId = grid.id;
59195 var tpls = this.templates || {};
59198 tpls.master = new Roo.Template(
59199 '<div class="x-grid" hidefocus="true">',
59200 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
59201 '<div class="x-grid-topbar"></div>',
59202 '<div class="x-grid-scroller"><div></div></div>',
59203 '<div class="x-grid-locked">',
59204 '<div class="x-grid-header">{lockedHeader}</div>',
59205 '<div class="x-grid-body">{lockedBody}</div>',
59207 '<div class="x-grid-viewport">',
59208 '<div class="x-grid-header">{header}</div>',
59209 '<div class="x-grid-body">{body}</div>',
59211 '<div class="x-grid-bottombar"></div>',
59213 '<div class="x-grid-resize-proxy"> </div>',
59216 tpls.master.disableformats = true;
59220 tpls.header = new Roo.Template(
59221 '<table border="0" cellspacing="0" cellpadding="0">',
59222 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
59225 tpls.header.disableformats = true;
59227 tpls.header.compile();
59230 tpls.hcell = new Roo.Template(
59231 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
59232 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
59235 tpls.hcell.disableFormats = true;
59237 tpls.hcell.compile();
59240 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
59241 this.unselectableCls + '" ' + this.unselectable +'> </div>');
59242 tpls.hsplit.disableFormats = true;
59244 tpls.hsplit.compile();
59247 tpls.body = new Roo.Template(
59248 '<table border="0" cellspacing="0" cellpadding="0">',
59249 "<tbody>{rows}</tbody>",
59252 tpls.body.disableFormats = true;
59254 tpls.body.compile();
59257 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
59258 tpls.row.disableFormats = true;
59260 tpls.row.compile();
59263 tpls.cell = new Roo.Template(
59264 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
59265 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
59266 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
59269 tpls.cell.disableFormats = true;
59271 tpls.cell.compile();
59273 this.templates = tpls;
59276 // remap these for backwards compat
59277 onColWidthChange : function(){
59278 this.updateColumns.apply(this, arguments);
59280 onHeaderChange : function(){
59281 this.updateHeaders.apply(this, arguments);
59283 onHiddenChange : function(){
59284 this.handleHiddenChange.apply(this, arguments);
59286 onColumnMove : function(){
59287 this.handleColumnMove.apply(this, arguments);
59289 onColumnLock : function(){
59290 this.handleLockChange.apply(this, arguments);
59293 onDataChange : function(){
59295 this.updateHeaderSortState();
59298 onClear : function(){
59302 onUpdate : function(ds, record){
59303 this.refreshRow(record);
59306 refreshRow : function(record){
59307 var ds = this.ds, index;
59308 if(typeof record == 'number'){
59310 record = ds.getAt(index);
59312 index = ds.indexOf(record);
59314 this.insertRows(ds, index, index, true);
59315 this.onRemove(ds, record, index+1, true);
59316 this.syncRowHeights(index, index);
59318 this.fireEvent("rowupdated", this, index, record);
59321 onAdd : function(ds, records, index){
59322 this.insertRows(ds, index, index + (records.length-1));
59325 onRemove : function(ds, record, index, isUpdate){
59326 if(isUpdate !== true){
59327 this.fireEvent("beforerowremoved", this, index, record);
59329 var bt = this.getBodyTable(), lt = this.getLockedTable();
59330 if(bt.rows[index]){
59331 bt.firstChild.removeChild(bt.rows[index]);
59333 if(lt.rows[index]){
59334 lt.firstChild.removeChild(lt.rows[index]);
59336 if(isUpdate !== true){
59337 this.stripeRows(index);
59338 this.syncRowHeights(index, index);
59340 this.fireEvent("rowremoved", this, index, record);
59344 onLoad : function(){
59345 this.scrollToTop();
59349 * Scrolls the grid to the top
59351 scrollToTop : function(){
59353 this.scroller.dom.scrollTop = 0;
59359 * Gets a panel in the header of the grid that can be used for toolbars etc.
59360 * After modifying the contents of this panel a call to grid.autoSize() may be
59361 * required to register any changes in size.
59362 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
59363 * @return Roo.Element
59365 getHeaderPanel : function(doShow){
59367 this.headerPanel.show();
59369 return this.headerPanel;
59373 * Gets a panel in the footer of the grid that can be used for toolbars etc.
59374 * After modifying the contents of this panel a call to grid.autoSize() may be
59375 * required to register any changes in size.
59376 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
59377 * @return Roo.Element
59379 getFooterPanel : function(doShow){
59381 this.footerPanel.show();
59383 return this.footerPanel;
59386 initElements : function(){
59387 var E = Roo.Element;
59388 var el = this.grid.getGridEl().dom.firstChild;
59389 var cs = el.childNodes;
59391 this.el = new E(el);
59393 this.focusEl = new E(el.firstChild);
59394 this.focusEl.swallowEvent("click", true);
59396 this.headerPanel = new E(cs[1]);
59397 this.headerPanel.enableDisplayMode("block");
59399 this.scroller = new E(cs[2]);
59400 this.scrollSizer = new E(this.scroller.dom.firstChild);
59402 this.lockedWrap = new E(cs[3]);
59403 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
59404 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
59406 this.mainWrap = new E(cs[4]);
59407 this.mainHd = new E(this.mainWrap.dom.firstChild);
59408 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
59410 this.footerPanel = new E(cs[5]);
59411 this.footerPanel.enableDisplayMode("block");
59413 this.resizeProxy = new E(cs[6]);
59415 this.headerSelector = String.format(
59416 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
59417 this.lockedHd.id, this.mainHd.id
59420 this.splitterSelector = String.format(
59421 '#{0} div.x-grid-split, #{1} div.x-grid-split',
59422 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
59425 idToCssName : function(s)
59427 return s.replace(/[^a-z0-9]+/ig, '-');
59430 getHeaderCell : function(index){
59431 return Roo.DomQuery.select(this.headerSelector)[index];
59434 getHeaderCellMeasure : function(index){
59435 return this.getHeaderCell(index).firstChild;
59438 getHeaderCellText : function(index){
59439 return this.getHeaderCell(index).firstChild.firstChild;
59442 getLockedTable : function(){
59443 return this.lockedBody.dom.firstChild;
59446 getBodyTable : function(){
59447 return this.mainBody.dom.firstChild;
59450 getLockedRow : function(index){
59451 return this.getLockedTable().rows[index];
59454 getRow : function(index){
59455 return this.getBodyTable().rows[index];
59458 getRowComposite : function(index){
59460 this.rowEl = new Roo.CompositeElementLite();
59462 var els = [], lrow, mrow;
59463 if(lrow = this.getLockedRow(index)){
59466 if(mrow = this.getRow(index)){
59469 this.rowEl.elements = els;
59473 * Gets the 'td' of the cell
59475 * @param {Integer} rowIndex row to select
59476 * @param {Integer} colIndex column to select
59480 getCell : function(rowIndex, colIndex){
59481 var locked = this.cm.getLockedCount();
59483 if(colIndex < locked){
59484 source = this.lockedBody.dom.firstChild;
59486 source = this.mainBody.dom.firstChild;
59487 colIndex -= locked;
59489 return source.rows[rowIndex].childNodes[colIndex];
59492 getCellText : function(rowIndex, colIndex){
59493 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
59496 getCellBox : function(cell){
59497 var b = this.fly(cell).getBox();
59498 if(Roo.isOpera){ // opera fails to report the Y
59499 b.y = cell.offsetTop + this.mainBody.getY();
59504 getCellIndex : function(cell){
59505 var id = String(cell.className).match(this.cellRE);
59507 return parseInt(id[1], 10);
59512 findHeaderIndex : function(n){
59513 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
59514 return r ? this.getCellIndex(r) : false;
59517 findHeaderCell : function(n){
59518 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
59519 return r ? r : false;
59522 findRowIndex : function(n){
59526 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
59527 return r ? r.rowIndex : false;
59530 findCellIndex : function(node){
59531 var stop = this.el.dom;
59532 while(node && node != stop){
59533 if(this.findRE.test(node.className)){
59534 return this.getCellIndex(node);
59536 node = node.parentNode;
59541 getColumnId : function(index){
59542 return this.cm.getColumnId(index);
59545 getSplitters : function()
59547 if(this.splitterSelector){
59548 return Roo.DomQuery.select(this.splitterSelector);
59554 getSplitter : function(index){
59555 return this.getSplitters()[index];
59558 onRowOver : function(e, t){
59560 if((row = this.findRowIndex(t)) !== false){
59561 this.getRowComposite(row).addClass("x-grid-row-over");
59565 onRowOut : function(e, t){
59567 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
59568 this.getRowComposite(row).removeClass("x-grid-row-over");
59572 renderHeaders : function(){
59574 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
59575 var cb = [], lb = [], sb = [], lsb = [], p = {};
59576 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
59577 p.cellId = "x-grid-hd-0-" + i;
59578 p.splitId = "x-grid-csplit-0-" + i;
59579 p.id = cm.getColumnId(i);
59580 p.value = cm.getColumnHeader(i) || "";
59581 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
59582 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
59583 if(!cm.isLocked(i)){
59584 cb[cb.length] = ct.apply(p);
59585 sb[sb.length] = st.apply(p);
59587 lb[lb.length] = ct.apply(p);
59588 lsb[lsb.length] = st.apply(p);
59591 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
59592 ht.apply({cells: cb.join(""), splits:sb.join("")})];
59595 updateHeaders : function(){
59596 var html = this.renderHeaders();
59597 this.lockedHd.update(html[0]);
59598 this.mainHd.update(html[1]);
59602 * Focuses the specified row.
59603 * @param {Number} row The row index
59605 focusRow : function(row)
59607 //Roo.log('GridView.focusRow');
59608 var x = this.scroller.dom.scrollLeft;
59609 this.focusCell(row, 0, false);
59610 this.scroller.dom.scrollLeft = x;
59614 * Focuses the specified cell.
59615 * @param {Number} row The row index
59616 * @param {Number} col The column index
59617 * @param {Boolean} hscroll false to disable horizontal scrolling
59619 focusCell : function(row, col, hscroll)
59621 //Roo.log('GridView.focusCell');
59622 var el = this.ensureVisible(row, col, hscroll);
59623 this.focusEl.alignTo(el, "tl-tl");
59625 this.focusEl.focus();
59627 this.focusEl.focus.defer(1, this.focusEl);
59632 * Scrolls the specified cell into view
59633 * @param {Number} row The row index
59634 * @param {Number} col The column index
59635 * @param {Boolean} hscroll false to disable horizontal scrolling
59637 ensureVisible : function(row, col, hscroll)
59639 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
59640 //return null; //disable for testing.
59641 if(typeof row != "number"){
59642 row = row.rowIndex;
59644 if(row < 0 && row >= this.ds.getCount()){
59647 col = (col !== undefined ? col : 0);
59648 var cm = this.grid.colModel;
59649 while(cm.isHidden(col)){
59653 var el = this.getCell(row, col);
59657 var c = this.scroller.dom;
59659 var ctop = parseInt(el.offsetTop, 10);
59660 var cleft = parseInt(el.offsetLeft, 10);
59661 var cbot = ctop + el.offsetHeight;
59662 var cright = cleft + el.offsetWidth;
59664 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
59665 var stop = parseInt(c.scrollTop, 10);
59666 var sleft = parseInt(c.scrollLeft, 10);
59667 var sbot = stop + ch;
59668 var sright = sleft + c.clientWidth;
59670 Roo.log('GridView.ensureVisible:' +
59672 ' c.clientHeight:' + c.clientHeight +
59673 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
59681 c.scrollTop = ctop;
59682 //Roo.log("set scrolltop to ctop DISABLE?");
59683 }else if(cbot > sbot){
59684 //Roo.log("set scrolltop to cbot-ch");
59685 c.scrollTop = cbot-ch;
59688 if(hscroll !== false){
59690 c.scrollLeft = cleft;
59691 }else if(cright > sright){
59692 c.scrollLeft = cright-c.clientWidth;
59699 updateColumns : function(){
59700 this.grid.stopEditing();
59701 var cm = this.grid.colModel, colIds = this.getColumnIds();
59702 //var totalWidth = cm.getTotalWidth();
59704 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
59705 //if(cm.isHidden(i)) continue;
59706 var w = cm.getColumnWidth(i);
59707 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
59708 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
59710 this.updateSplitters();
59713 generateRules : function(cm){
59714 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
59715 Roo.util.CSS.removeStyleSheet(rulesId);
59716 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
59717 var cid = cm.getColumnId(i);
59719 if(cm.config[i].align){
59720 align = 'text-align:'+cm.config[i].align+';';
59723 if(cm.isHidden(i)){
59724 hidden = 'display:none;';
59726 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
59728 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
59729 this.hdSelector, cid, " {\n", align, width, "}\n",
59730 this.tdSelector, cid, " {\n",hidden,"\n}\n",
59731 this.splitSelector, cid, " {\n", hidden , "\n}\n");
59733 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
59736 updateSplitters : function(){
59737 var cm = this.cm, s = this.getSplitters();
59738 if(s){ // splitters not created yet
59739 var pos = 0, locked = true;
59740 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
59741 if(cm.isHidden(i)) {
59744 var w = cm.getColumnWidth(i); // make sure it's a number
59745 if(!cm.isLocked(i) && locked){
59750 s[i].style.left = (pos-this.splitOffset) + "px";
59755 handleHiddenChange : function(colModel, colIndex, hidden){
59757 this.hideColumn(colIndex);
59759 this.unhideColumn(colIndex);
59763 hideColumn : function(colIndex){
59764 var cid = this.getColumnId(colIndex);
59765 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
59766 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
59768 this.updateHeaders();
59770 this.updateSplitters();
59774 unhideColumn : function(colIndex){
59775 var cid = this.getColumnId(colIndex);
59776 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
59777 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
59780 this.updateHeaders();
59782 this.updateSplitters();
59786 insertRows : function(dm, firstRow, lastRow, isUpdate){
59787 if(firstRow == 0 && lastRow == dm.getCount()-1){
59791 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
59793 var s = this.getScrollState();
59794 var markup = this.renderRows(firstRow, lastRow);
59795 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
59796 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
59797 this.restoreScroll(s);
59799 this.fireEvent("rowsinserted", this, firstRow, lastRow);
59800 this.syncRowHeights(firstRow, lastRow);
59801 this.stripeRows(firstRow);
59807 bufferRows : function(markup, target, index){
59808 var before = null, trows = target.rows, tbody = target.tBodies[0];
59809 if(index < trows.length){
59810 before = trows[index];
59812 var b = document.createElement("div");
59813 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
59814 var rows = b.firstChild.rows;
59815 for(var i = 0, len = rows.length; i < len; i++){
59817 tbody.insertBefore(rows[0], before);
59819 tbody.appendChild(rows[0]);
59826 deleteRows : function(dm, firstRow, lastRow){
59827 if(dm.getRowCount()<1){
59828 this.fireEvent("beforerefresh", this);
59829 this.mainBody.update("");
59830 this.lockedBody.update("");
59831 this.fireEvent("refresh", this);
59833 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
59834 var bt = this.getBodyTable();
59835 var tbody = bt.firstChild;
59836 var rows = bt.rows;
59837 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
59838 tbody.removeChild(rows[firstRow]);
59840 this.stripeRows(firstRow);
59841 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
59845 updateRows : function(dataSource, firstRow, lastRow){
59846 var s = this.getScrollState();
59848 this.restoreScroll(s);
59851 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
59855 this.updateHeaderSortState();
59858 getScrollState : function(){
59860 var sb = this.scroller.dom;
59861 return {left: sb.scrollLeft, top: sb.scrollTop};
59864 stripeRows : function(startRow){
59865 if(!this.grid.stripeRows || this.ds.getCount() < 1){
59868 startRow = startRow || 0;
59869 var rows = this.getBodyTable().rows;
59870 var lrows = this.getLockedTable().rows;
59871 var cls = ' x-grid-row-alt ';
59872 for(var i = startRow, len = rows.length; i < len; i++){
59873 var row = rows[i], lrow = lrows[i];
59874 var isAlt = ((i+1) % 2 == 0);
59875 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
59876 if(isAlt == hasAlt){
59880 row.className += " x-grid-row-alt";
59882 row.className = row.className.replace("x-grid-row-alt", "");
59885 lrow.className = row.className;
59890 restoreScroll : function(state){
59891 //Roo.log('GridView.restoreScroll');
59892 var sb = this.scroller.dom;
59893 sb.scrollLeft = state.left;
59894 sb.scrollTop = state.top;
59898 syncScroll : function(){
59899 //Roo.log('GridView.syncScroll');
59900 var sb = this.scroller.dom;
59901 var sh = this.mainHd.dom;
59902 var bs = this.mainBody.dom;
59903 var lv = this.lockedBody.dom;
59904 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
59905 lv.scrollTop = bs.scrollTop = sb.scrollTop;
59908 handleScroll : function(e){
59910 var sb = this.scroller.dom;
59911 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
59915 handleWheel : function(e){
59916 var d = e.getWheelDelta();
59917 this.scroller.dom.scrollTop -= d*22;
59918 // set this here to prevent jumpy scrolling on large tables
59919 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
59923 renderRows : function(startRow, endRow){
59924 // pull in all the crap needed to render rows
59925 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
59926 var colCount = cm.getColumnCount();
59928 if(ds.getCount() < 1){
59932 // build a map for all the columns
59934 for(var i = 0; i < colCount; i++){
59935 var name = cm.getDataIndex(i);
59937 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
59938 renderer : cm.getRenderer(i),
59939 id : cm.getColumnId(i),
59940 locked : cm.isLocked(i),
59941 has_editor : cm.isCellEditable(i)
59945 startRow = startRow || 0;
59946 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
59948 // records to render
59949 var rs = ds.getRange(startRow, endRow);
59951 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
59954 // As much as I hate to duplicate code, this was branched because FireFox really hates
59955 // [].join("") on strings. The performance difference was substantial enough to
59956 // branch this function
59957 doRender : Roo.isGecko ?
59958 function(cs, rs, ds, startRow, colCount, stripe){
59959 var ts = this.templates, ct = ts.cell, rt = ts.row;
59961 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
59963 var hasListener = this.grid.hasListener('rowclass');
59965 for(var j = 0, len = rs.length; j < len; j++){
59966 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
59967 for(var i = 0; i < colCount; i++){
59969 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
59971 p.css = p.attr = "";
59972 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
59973 if(p.value == undefined || p.value === "") {
59974 p.value = " ";
59977 p.css += ' x-grid-editable-cell';
59979 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
59980 p.css += ' x-grid-dirty-cell';
59982 var markup = ct.apply(p);
59990 if(stripe && ((rowIndex+1) % 2 == 0)){
59991 alt.push("x-grid-row-alt")
59994 alt.push( " x-grid-dirty-row");
59997 if(this.getRowClass){
59998 alt.push(this.getRowClass(r, rowIndex));
60004 rowIndex : rowIndex,
60007 this.grid.fireEvent('rowclass', this, rowcfg);
60008 alt.push(rowcfg.rowClass);
60010 rp.alt = alt.join(" ");
60011 lbuf+= rt.apply(rp);
60013 buf+= rt.apply(rp);
60015 return [lbuf, buf];
60017 function(cs, rs, ds, startRow, colCount, stripe){
60018 var ts = this.templates, ct = ts.cell, rt = ts.row;
60020 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
60021 var hasListener = this.grid.hasListener('rowclass');
60024 for(var j = 0, len = rs.length; j < len; j++){
60025 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
60026 for(var i = 0; i < colCount; i++){
60028 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
60030 p.css = p.attr = "";
60031 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
60032 if(p.value == undefined || p.value === "") {
60033 p.value = " ";
60037 p.css += ' x-grid-editable-cell';
60039 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
60040 p.css += ' x-grid-dirty-cell'
60043 var markup = ct.apply(p);
60045 cb[cb.length] = markup;
60047 lcb[lcb.length] = markup;
60051 if(stripe && ((rowIndex+1) % 2 == 0)){
60052 alt.push( "x-grid-row-alt");
60055 alt.push(" x-grid-dirty-row");
60058 if(this.getRowClass){
60059 alt.push( this.getRowClass(r, rowIndex));
60065 rowIndex : rowIndex,
60068 this.grid.fireEvent('rowclass', this, rowcfg);
60069 alt.push(rowcfg.rowClass);
60072 rp.alt = alt.join(" ");
60073 rp.cells = lcb.join("");
60074 lbuf[lbuf.length] = rt.apply(rp);
60075 rp.cells = cb.join("");
60076 buf[buf.length] = rt.apply(rp);
60078 return [lbuf.join(""), buf.join("")];
60081 renderBody : function(){
60082 var markup = this.renderRows();
60083 var bt = this.templates.body;
60084 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
60088 * Refreshes the grid
60089 * @param {Boolean} headersToo
60091 refresh : function(headersToo){
60092 this.fireEvent("beforerefresh", this);
60093 this.grid.stopEditing();
60094 var result = this.renderBody();
60095 this.lockedBody.update(result[0]);
60096 this.mainBody.update(result[1]);
60097 if(headersToo === true){
60098 this.updateHeaders();
60099 this.updateColumns();
60100 this.updateSplitters();
60101 this.updateHeaderSortState();
60103 this.syncRowHeights();
60105 this.fireEvent("refresh", this);
60108 handleColumnMove : function(cm, oldIndex, newIndex){
60109 this.indexMap = null;
60110 var s = this.getScrollState();
60111 this.refresh(true);
60112 this.restoreScroll(s);
60113 this.afterMove(newIndex);
60116 afterMove : function(colIndex){
60117 if(this.enableMoveAnim && Roo.enableFx){
60118 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
60120 // if multisort - fix sortOrder, and reload..
60121 if (this.grid.dataSource.multiSort) {
60122 // the we can call sort again..
60123 var dm = this.grid.dataSource;
60124 var cm = this.grid.colModel;
60126 for(var i = 0; i < cm.config.length; i++ ) {
60128 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
60129 continue; // dont' bother, it's not in sort list or being set.
60132 so.push(cm.config[i].dataIndex);
60135 dm.load(dm.lastOptions);
60142 updateCell : function(dm, rowIndex, dataIndex){
60143 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
60144 if(typeof colIndex == "undefined"){ // not present in grid
60147 var cm = this.grid.colModel;
60148 var cell = this.getCell(rowIndex, colIndex);
60149 var cellText = this.getCellText(rowIndex, colIndex);
60152 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
60153 id : cm.getColumnId(colIndex),
60154 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
60156 var renderer = cm.getRenderer(colIndex);
60157 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
60158 if(typeof val == "undefined" || val === "") {
60161 cellText.innerHTML = val;
60162 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
60163 this.syncRowHeights(rowIndex, rowIndex);
60166 calcColumnWidth : function(colIndex, maxRowsToMeasure){
60168 if(this.grid.autoSizeHeaders){
60169 var h = this.getHeaderCellMeasure(colIndex);
60170 maxWidth = Math.max(maxWidth, h.scrollWidth);
60173 if(this.cm.isLocked(colIndex)){
60174 tb = this.getLockedTable();
60177 tb = this.getBodyTable();
60178 index = colIndex - this.cm.getLockedCount();
60181 var rows = tb.rows;
60182 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
60183 for(var i = 0; i < stopIndex; i++){
60184 var cell = rows[i].childNodes[index].firstChild;
60185 maxWidth = Math.max(maxWidth, cell.scrollWidth);
60188 return maxWidth + /*margin for error in IE*/ 5;
60191 * Autofit a column to its content.
60192 * @param {Number} colIndex
60193 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
60195 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
60196 if(this.cm.isHidden(colIndex)){
60197 return; // can't calc a hidden column
60200 var cid = this.cm.getColumnId(colIndex);
60201 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
60202 if(this.grid.autoSizeHeaders){
60203 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
60206 var newWidth = this.calcColumnWidth(colIndex);
60207 this.cm.setColumnWidth(colIndex,
60208 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
60209 if(!suppressEvent){
60210 this.grid.fireEvent("columnresize", colIndex, newWidth);
60215 * Autofits all columns to their content and then expands to fit any extra space in the grid
60217 autoSizeColumns : function(){
60218 var cm = this.grid.colModel;
60219 var colCount = cm.getColumnCount();
60220 for(var i = 0; i < colCount; i++){
60221 this.autoSizeColumn(i, true, true);
60223 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
60226 this.updateColumns();
60232 * Autofits all columns to the grid's width proportionate with their current size
60233 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
60235 fitColumns : function(reserveScrollSpace){
60236 var cm = this.grid.colModel;
60237 var colCount = cm.getColumnCount();
60241 for (i = 0; i < colCount; i++){
60242 if(!cm.isHidden(i) && !cm.isFixed(i)){
60243 w = cm.getColumnWidth(i);
60249 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
60250 if(reserveScrollSpace){
60253 var frac = (avail - cm.getTotalWidth())/width;
60254 while (cols.length){
60257 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
60259 this.updateColumns();
60263 onRowSelect : function(rowIndex){
60264 var row = this.getRowComposite(rowIndex);
60265 row.addClass("x-grid-row-selected");
60268 onRowDeselect : function(rowIndex){
60269 var row = this.getRowComposite(rowIndex);
60270 row.removeClass("x-grid-row-selected");
60273 onCellSelect : function(row, col){
60274 var cell = this.getCell(row, col);
60276 Roo.fly(cell).addClass("x-grid-cell-selected");
60280 onCellDeselect : function(row, col){
60281 var cell = this.getCell(row, col);
60283 Roo.fly(cell).removeClass("x-grid-cell-selected");
60287 updateHeaderSortState : function(){
60289 // sort state can be single { field: xxx, direction : yyy}
60290 // or { xxx=>ASC , yyy : DESC ..... }
60293 if (!this.ds.multiSort) {
60294 var state = this.ds.getSortState();
60298 mstate[state.field] = state.direction;
60299 // FIXME... - this is not used here.. but might be elsewhere..
60300 this.sortState = state;
60303 mstate = this.ds.sortToggle;
60305 //remove existing sort classes..
60307 var sc = this.sortClasses;
60308 var hds = this.el.select(this.headerSelector).removeClass(sc);
60310 for(var f in mstate) {
60312 var sortColumn = this.cm.findColumnIndex(f);
60314 if(sortColumn != -1){
60315 var sortDir = mstate[f];
60316 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
60325 handleHeaderClick : function(g, index,e){
60327 Roo.log("header click");
60330 // touch events on header are handled by context
60331 this.handleHdCtx(g,index,e);
60336 if(this.headersDisabled){
60339 var dm = g.dataSource, cm = g.colModel;
60340 if(!cm.isSortable(index)){
60345 if (dm.multiSort) {
60346 // update the sortOrder
60348 for(var i = 0; i < cm.config.length; i++ ) {
60350 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
60351 continue; // dont' bother, it's not in sort list or being set.
60354 so.push(cm.config[i].dataIndex);
60360 dm.sort(cm.getDataIndex(index));
60364 destroy : function(){
60366 this.colMenu.removeAll();
60367 Roo.menu.MenuMgr.unregister(this.colMenu);
60368 this.colMenu.getEl().remove();
60369 delete this.colMenu;
60372 this.hmenu.removeAll();
60373 Roo.menu.MenuMgr.unregister(this.hmenu);
60374 this.hmenu.getEl().remove();
60377 if(this.grid.enableColumnMove){
60378 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
60380 for(var dd in dds){
60381 if(!dds[dd].config.isTarget && dds[dd].dragElId){
60382 var elid = dds[dd].dragElId;
60384 Roo.get(elid).remove();
60385 } else if(dds[dd].config.isTarget){
60386 dds[dd].proxyTop.remove();
60387 dds[dd].proxyBottom.remove();
60390 if(Roo.dd.DDM.locationCache[dd]){
60391 delete Roo.dd.DDM.locationCache[dd];
60394 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
60397 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
60398 this.bind(null, null);
60399 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
60402 handleLockChange : function(){
60403 this.refresh(true);
60406 onDenyColumnLock : function(){
60410 onDenyColumnHide : function(){
60414 handleHdMenuClick : function(item){
60415 var index = this.hdCtxIndex;
60416 var cm = this.cm, ds = this.ds;
60419 ds.sort(cm.getDataIndex(index), "ASC");
60422 ds.sort(cm.getDataIndex(index), "DESC");
60425 var lc = cm.getLockedCount();
60426 if(cm.getColumnCount(true) <= lc+1){
60427 this.onDenyColumnLock();
60431 cm.setLocked(index, true, true);
60432 cm.moveColumn(index, lc);
60433 this.grid.fireEvent("columnmove", index, lc);
60435 cm.setLocked(index, true);
60439 var lc = cm.getLockedCount();
60440 if((lc-1) != index){
60441 cm.setLocked(index, false, true);
60442 cm.moveColumn(index, lc-1);
60443 this.grid.fireEvent("columnmove", index, lc-1);
60445 cm.setLocked(index, false);
60448 case 'wider': // used to expand cols on touch..
60450 var cw = cm.getColumnWidth(index);
60451 cw += (item.id == 'wider' ? 1 : -1) * 50;
60452 cw = Math.max(0, cw);
60453 cw = Math.min(cw,4000);
60454 cm.setColumnWidth(index, cw);
60458 index = cm.getIndexById(item.id.substr(4));
60460 if(item.checked && cm.getColumnCount(true) <= 1){
60461 this.onDenyColumnHide();
60464 cm.setHidden(index, item.checked);
60470 beforeColMenuShow : function(){
60471 var cm = this.cm, colCount = cm.getColumnCount();
60472 this.colMenu.removeAll();
60475 for(var i = 0; i < colCount; i++){
60477 id: "col-"+cm.getColumnId(i),
60478 text: cm.getColumnHeader(i),
60479 checked: !cm.isHidden(i),
60484 if (this.grid.sortColMenu) {
60485 items.sort(function(a,b) {
60486 if (a.text == b.text) {
60489 return a.text.toUpperCase() > b.text.toUpperCase() ? 1 : -1;
60493 for(var i = 0; i < colCount; i++){
60494 this.colMenu.add(new Roo.menu.CheckItem(items[i]));
60498 handleHdCtx : function(g, index, e){
60500 var hd = this.getHeaderCell(index);
60501 this.hdCtxIndex = index;
60502 var ms = this.hmenu.items, cm = this.cm;
60503 ms.get("asc").setDisabled(!cm.isSortable(index));
60504 ms.get("desc").setDisabled(!cm.isSortable(index));
60505 if(this.grid.enableColLock !== false){
60506 ms.get("lock").setDisabled(cm.isLocked(index));
60507 ms.get("unlock").setDisabled(!cm.isLocked(index));
60509 this.hmenu.show(hd, "tl-bl");
60512 handleHdOver : function(e){
60513 var hd = this.findHeaderCell(e.getTarget());
60514 if(hd && !this.headersDisabled){
60515 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
60516 this.fly(hd).addClass("x-grid-hd-over");
60521 handleHdOut : function(e){
60522 var hd = this.findHeaderCell(e.getTarget());
60524 this.fly(hd).removeClass("x-grid-hd-over");
60528 handleSplitDblClick : function(e, t){
60529 var i = this.getCellIndex(t);
60530 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
60531 this.autoSizeColumn(i, true);
60536 render : function(){
60539 var colCount = cm.getColumnCount();
60541 if(this.grid.monitorWindowResize === true){
60542 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
60544 var header = this.renderHeaders();
60545 var body = this.templates.body.apply({rows:""});
60546 var html = this.templates.master.apply({
60549 lockedHeader: header[0],
60553 //this.updateColumns();
60555 this.grid.getGridEl().dom.innerHTML = html;
60557 this.initElements();
60559 // a kludge to fix the random scolling effect in webkit
60560 this.el.on("scroll", function() {
60561 this.el.dom.scrollTop=0; // hopefully not recursive..
60564 this.scroller.on("scroll", this.handleScroll, this);
60565 this.lockedBody.on("mousewheel", this.handleWheel, this);
60566 this.mainBody.on("mousewheel", this.handleWheel, this);
60568 this.mainHd.on("mouseover", this.handleHdOver, this);
60569 this.mainHd.on("mouseout", this.handleHdOut, this);
60570 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
60571 {delegate: "."+this.splitClass});
60573 this.lockedHd.on("mouseover", this.handleHdOver, this);
60574 this.lockedHd.on("mouseout", this.handleHdOut, this);
60575 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
60576 {delegate: "."+this.splitClass});
60578 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
60579 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
60582 this.updateSplitters();
60584 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
60585 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
60586 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
60589 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
60590 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
60592 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
60593 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
60595 if(this.grid.enableColLock !== false){
60596 this.hmenu.add('-',
60597 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
60598 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
60602 this.hmenu.add('-',
60603 {id:"wider", text: this.columnsWiderText},
60604 {id:"narrow", text: this.columnsNarrowText }
60610 if(this.grid.enableColumnHide !== false){
60612 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
60613 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
60614 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
60616 this.hmenu.add('-',
60617 {id:"columns", text: this.columnsText, menu: this.colMenu}
60620 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
60622 this.grid.on("headercontextmenu", this.handleHdCtx, this);
60625 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
60626 this.dd = new Roo.grid.GridDragZone(this.grid, {
60627 ddGroup : this.grid.ddGroup || 'GridDD'
60633 for(var i = 0; i < colCount; i++){
60634 if(cm.isHidden(i)){
60635 this.hideColumn(i);
60637 if(cm.config[i].align){
60638 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
60639 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
60643 this.updateHeaderSortState();
60645 this.beforeInitialResize();
60648 // two part rendering gives faster view to the user
60649 this.renderPhase2.defer(1, this);
60652 renderPhase2 : function(){
60653 // render the rows now
60655 if(this.grid.autoSizeColumns){
60656 this.autoSizeColumns();
60660 beforeInitialResize : function(){
60664 onColumnSplitterMoved : function(i, w){
60665 this.userResized = true;
60666 var cm = this.grid.colModel;
60667 cm.setColumnWidth(i, w, true);
60668 var cid = cm.getColumnId(i);
60669 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
60670 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
60671 this.updateSplitters();
60673 this.grid.fireEvent("columnresize", i, w);
60676 syncRowHeights : function(startIndex, endIndex){
60677 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
60678 startIndex = startIndex || 0;
60679 var mrows = this.getBodyTable().rows;
60680 var lrows = this.getLockedTable().rows;
60681 var len = mrows.length-1;
60682 endIndex = Math.min(endIndex || len, len);
60683 for(var i = startIndex; i <= endIndex; i++){
60684 var m = mrows[i], l = lrows[i];
60685 var h = Math.max(m.offsetHeight, l.offsetHeight);
60686 m.style.height = l.style.height = h + "px";
60691 layout : function(initialRender, is2ndPass)
60694 var auto = g.autoHeight;
60695 var scrollOffset = 16;
60696 var c = g.getGridEl(), cm = this.cm,
60697 expandCol = g.autoExpandColumn,
60699 //c.beginMeasure();
60701 if(!c.dom.offsetWidth){ // display:none?
60703 this.lockedWrap.show();
60704 this.mainWrap.show();
60709 var hasLock = this.cm.isLocked(0);
60711 var tbh = this.headerPanel.getHeight();
60712 var bbh = this.footerPanel.getHeight();
60715 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
60716 var newHeight = ch + c.getBorderWidth("tb");
60718 newHeight = Math.min(g.maxHeight, newHeight);
60720 c.setHeight(newHeight);
60724 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
60727 var s = this.scroller;
60729 var csize = c.getSize(true);
60731 this.el.setSize(csize.width, csize.height);
60733 this.headerPanel.setWidth(csize.width);
60734 this.footerPanel.setWidth(csize.width);
60736 var hdHeight = this.mainHd.getHeight();
60737 var vw = csize.width;
60738 var vh = csize.height - (tbh + bbh);
60742 var bt = this.getBodyTable();
60744 if(cm.getLockedCount() == cm.config.length){
60745 bt = this.getLockedTable();
60748 var ltWidth = hasLock ?
60749 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
60751 var scrollHeight = bt.offsetHeight;
60752 var scrollWidth = ltWidth + bt.offsetWidth;
60753 var vscroll = false, hscroll = false;
60755 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
60757 var lw = this.lockedWrap, mw = this.mainWrap;
60758 var lb = this.lockedBody, mb = this.mainBody;
60760 setTimeout(function(){
60761 var t = s.dom.offsetTop;
60762 var w = s.dom.clientWidth,
60763 h = s.dom.clientHeight;
60766 lw.setSize(ltWidth, h);
60768 mw.setLeftTop(ltWidth, t);
60769 mw.setSize(w-ltWidth, h);
60771 lb.setHeight(h-hdHeight);
60772 mb.setHeight(h-hdHeight);
60774 if(is2ndPass !== true && !gv.userResized && expandCol){
60775 // high speed resize without full column calculation
60777 var ci = cm.getIndexById(expandCol);
60779 ci = cm.findColumnIndex(expandCol);
60781 ci = Math.max(0, ci); // make sure it's got at least the first col.
60782 var expandId = cm.getColumnId(ci);
60783 var tw = cm.getTotalWidth(false);
60784 var currentWidth = cm.getColumnWidth(ci);
60785 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
60786 if(currentWidth != cw){
60787 cm.setColumnWidth(ci, cw, true);
60788 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
60789 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
60790 gv.updateSplitters();
60791 gv.layout(false, true);
60803 onWindowResize : function(){
60804 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
60810 appendFooter : function(parentEl){
60814 sortAscText : "Sort Ascending",
60815 sortDescText : "Sort Descending",
60816 lockText : "Lock Column",
60817 unlockText : "Unlock Column",
60818 columnsText : "Columns",
60820 columnsWiderText : "Wider",
60821 columnsNarrowText : "Thinner"
60825 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
60826 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
60827 this.proxy.el.addClass('x-grid3-col-dd');
60830 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
60831 handleMouseDown : function(e){
60835 callHandleMouseDown : function(e){
60836 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
60841 * Ext JS Library 1.1.1
60842 * Copyright(c) 2006-2007, Ext JS, LLC.
60844 * Originally Released Under LGPL - original licence link has changed is not relivant.
60847 * <script type="text/javascript">
60850 * @extends Roo.dd.DDProxy
60851 * @class Roo.grid.SplitDragZone
60852 * Support for Column Header resizing
60854 * @param {Object} config
60857 // This is a support class used internally by the Grid components
60858 Roo.grid.SplitDragZone = function(grid, hd, hd2){
60860 this.view = grid.getView();
60861 this.proxy = this.view.resizeProxy;
60862 Roo.grid.SplitDragZone.superclass.constructor.call(
60865 "gridSplitters" + this.grid.getGridEl().id, // SGROUP
60867 dragElId : Roo.id(this.proxy.dom),
60872 this.setHandleElId(Roo.id(hd));
60873 if (hd2 !== false) {
60874 this.setOuterHandleElId(Roo.id(hd2));
60877 this.scroll = false;
60879 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
60880 fly: Roo.Element.fly,
60882 b4StartDrag : function(x, y){
60883 this.view.headersDisabled = true;
60884 var h = this.view.mainWrap ? this.view.mainWrap.getHeight() : (
60885 this.view.headEl.getHeight() + this.view.bodyEl.getHeight()
60887 this.proxy.setHeight(h);
60889 // for old system colWidth really stored the actual width?
60890 // in bootstrap we tried using xs/ms/etc.. to do % sizing?
60891 // which in reality did not work.. - it worked only for fixed sizes
60892 // for resizable we need to use actual sizes.
60893 var w = this.cm.getColumnWidth(this.cellIndex);
60894 if (!this.view.mainWrap) {
60896 w = this.view.getHeaderIndex(this.cellIndex).getWidth();
60901 // this was w-this.grid.minColumnWidth;
60902 // doesnt really make sense? - w = thie curren width or the rendered one?
60903 var minw = Math.max(w-this.grid.minColumnWidth, 0);
60904 this.resetConstraints();
60905 this.setXConstraint(minw, 1000);
60906 this.setYConstraint(0, 0);
60907 this.minX = x - minw;
60908 this.maxX = x + 1000;
60910 if (!this.view.mainWrap) { // this is Bootstrap code..
60911 this.getDragEl().style.display='block';
60914 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
60918 handleMouseDown : function(e){
60919 ev = Roo.EventObject.setEvent(e);
60920 var t = this.fly(ev.getTarget());
60921 if(t.hasClass("x-grid-split")){
60922 this.cellIndex = this.view.getCellIndex(t.dom);
60923 this.split = t.dom;
60924 this.cm = this.grid.colModel;
60925 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
60926 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
60931 endDrag : function(e){
60932 this.view.headersDisabled = false;
60933 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
60934 var diff = endX - this.startPos;
60936 var w = this.cm.getColumnWidth(this.cellIndex);
60937 if (!this.view.mainWrap) {
60940 this.view.onColumnSplitterMoved(this.cellIndex, w+diff);
60943 autoOffset : function(){
60944 this.setDelta(0,0);
60948 * Ext JS Library 1.1.1
60949 * Copyright(c) 2006-2007, Ext JS, LLC.
60951 * Originally Released Under LGPL - original licence link has changed is not relivant.
60954 * <script type="text/javascript">
60958 // This is a support class used internally by the Grid components
60959 Roo.grid.GridDragZone = function(grid, config){
60960 this.view = grid.getView();
60961 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
60962 if(this.view.lockedBody){
60963 this.setHandleElId(Roo.id(this.view.mainBody.dom));
60964 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
60966 this.scroll = false;
60968 this.ddel = document.createElement('div');
60969 this.ddel.className = 'x-grid-dd-wrap';
60972 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
60973 ddGroup : "GridDD",
60975 getDragData : function(e){
60976 var t = Roo.lib.Event.getTarget(e);
60977 var rowIndex = this.view.findRowIndex(t);
60978 var sm = this.grid.selModel;
60980 //Roo.log(rowIndex);
60982 if (sm.getSelectedCell) {
60983 // cell selection..
60984 if (!sm.getSelectedCell()) {
60987 if (rowIndex != sm.getSelectedCell()[0]) {
60992 if (sm.getSelections && sm.getSelections().length < 1) {
60997 // before it used to all dragging of unseleted... - now we dont do that.
60998 if(rowIndex !== false){
61003 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
61005 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
61008 if (e.hasModifier()){
61009 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
61012 Roo.log("getDragData");
61017 rowIndex: rowIndex,
61018 selections: sm.getSelections ? sm.getSelections() : (
61019 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : [])
61026 onInitDrag : function(e){
61027 var data = this.dragData;
61028 this.ddel.innerHTML = this.grid.getDragDropText();
61029 this.proxy.update(this.ddel);
61030 // fire start drag?
61033 afterRepair : function(){
61034 this.dragging = false;
61037 getRepairXY : function(e, data){
61041 onEndDrag : function(data, e){
61045 onValidDrop : function(dd, e, id){
61050 beforeInvalidDrop : function(e, id){
61055 * Ext JS Library 1.1.1
61056 * Copyright(c) 2006-2007, Ext JS, LLC.
61058 * Originally Released Under LGPL - original licence link has changed is not relivant.
61061 * <script type="text/javascript">
61066 * @class Roo.grid.ColumnModel
61067 * @extends Roo.util.Observable
61068 * This is the default implementation of a ColumnModel used by the Grid. It defines
61069 * the columns in the grid.
61072 var colModel = new Roo.grid.ColumnModel([
61073 {header: "Ticker", width: 60, sortable: true, locked: true},
61074 {header: "Company Name", width: 150, sortable: true},
61075 {header: "Market Cap.", width: 100, sortable: true},
61076 {header: "$ Sales", width: 100, sortable: true, renderer: money},
61077 {header: "Employees", width: 100, sortable: true, resizable: false}
61082 * The config options listed for this class are options which may appear in each
61083 * individual column definition.
61084 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
61086 * @param {Object} config An Array of column config objects. See this class's
61087 * config objects for details.
61089 Roo.grid.ColumnModel = function(config){
61091 * The config passed into the constructor
61093 this.config = []; //config;
61096 // if no id, create one
61097 // if the column does not have a dataIndex mapping,
61098 // map it to the order it is in the config
61099 for(var i = 0, len = config.length; i < len; i++){
61100 this.addColumn(config[i]);
61105 * The width of columns which have no width specified (defaults to 100)
61108 this.defaultWidth = 100;
61111 * Default sortable of columns which have no sortable specified (defaults to false)
61114 this.defaultSortable = false;
61118 * @event widthchange
61119 * Fires when the width of a column changes.
61120 * @param {ColumnModel} this
61121 * @param {Number} columnIndex The column index
61122 * @param {Number} newWidth The new width
61124 "widthchange": true,
61126 * @event headerchange
61127 * Fires when the text of a header changes.
61128 * @param {ColumnModel} this
61129 * @param {Number} columnIndex The column index
61130 * @param {Number} newText The new header text
61132 "headerchange": true,
61134 * @event hiddenchange
61135 * Fires when a column is hidden or "unhidden".
61136 * @param {ColumnModel} this
61137 * @param {Number} columnIndex The column index
61138 * @param {Boolean} hidden true if hidden, false otherwise
61140 "hiddenchange": true,
61142 * @event columnmoved
61143 * Fires when a column is moved.
61144 * @param {ColumnModel} this
61145 * @param {Number} oldIndex
61146 * @param {Number} newIndex
61148 "columnmoved" : true,
61150 * @event columlockchange
61151 * Fires when a column's locked state is changed
61152 * @param {ColumnModel} this
61153 * @param {Number} colIndex
61154 * @param {Boolean} locked true if locked
61156 "columnlockchange" : true
61158 Roo.grid.ColumnModel.superclass.constructor.call(this);
61160 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
61162 * @cfg {String} header The header text to display in the Grid view.
61165 * @cfg {String} xsHeader Header at Bootsrap Extra Small width (default for all)
61168 * @cfg {String} smHeader Header at Bootsrap Small width
61171 * @cfg {String} mdHeader Header at Bootsrap Medium width
61174 * @cfg {String} lgHeader Header at Bootsrap Large width
61177 * @cfg {String} xlHeader Header at Bootsrap extra Large width
61180 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
61181 * {@link Roo.data.Record} definition from which to draw the column's value. If not
61182 * specified, the column's index is used as an index into the Record's data Array.
61185 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
61186 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
61189 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
61190 * Defaults to the value of the {@link #defaultSortable} property.
61191 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
61194 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
61197 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
61200 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
61203 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
61206 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
61207 * given the cell's data value. See {@link #setRenderer}. If not specified, the
61208 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
61209 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
61212 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
61215 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
61218 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
61221 * @cfg {String} cursor (Optional)
61224 * @cfg {String} tooltip (Optional)
61227 * @cfg {Number} xs (Optional) can be '0' for hidden at this size (number less than 12)
61230 * @cfg {Number} sm (Optional) can be '0' for hidden at this size (number less than 12)
61233 * @cfg {Number} md (Optional) can be '0' for hidden at this size (number less than 12)
61236 * @cfg {Number} lg (Optional) can be '0' for hidden at this size (number less than 12)
61239 * @cfg {Number} xl (Optional) can be '0' for hidden at this size (number less than 12)
61242 * Returns the id of the column at the specified index.
61243 * @param {Number} index The column index
61244 * @return {String} the id
61246 getColumnId : function(index){
61247 return this.config[index].id;
61251 * Returns the column for a specified id.
61252 * @param {String} id The column id
61253 * @return {Object} the column
61255 getColumnById : function(id){
61256 return this.lookup[id];
61261 * Returns the column Object for a specified dataIndex.
61262 * @param {String} dataIndex The column dataIndex
61263 * @return {Object|Boolean} the column or false if not found
61265 getColumnByDataIndex: function(dataIndex){
61266 var index = this.findColumnIndex(dataIndex);
61267 return index > -1 ? this.config[index] : false;
61271 * Returns the index for a specified column id.
61272 * @param {String} id The column id
61273 * @return {Number} the index, or -1 if not found
61275 getIndexById : function(id){
61276 for(var i = 0, len = this.config.length; i < len; i++){
61277 if(this.config[i].id == id){
61285 * Returns the index for a specified column dataIndex.
61286 * @param {String} dataIndex The column dataIndex
61287 * @return {Number} the index, or -1 if not found
61290 findColumnIndex : function(dataIndex){
61291 for(var i = 0, len = this.config.length; i < len; i++){
61292 if(this.config[i].dataIndex == dataIndex){
61300 moveColumn : function(oldIndex, newIndex){
61301 var c = this.config[oldIndex];
61302 this.config.splice(oldIndex, 1);
61303 this.config.splice(newIndex, 0, c);
61304 this.dataMap = null;
61305 this.fireEvent("columnmoved", this, oldIndex, newIndex);
61308 isLocked : function(colIndex){
61309 return this.config[colIndex].locked === true;
61312 setLocked : function(colIndex, value, suppressEvent){
61313 if(this.isLocked(colIndex) == value){
61316 this.config[colIndex].locked = value;
61317 if(!suppressEvent){
61318 this.fireEvent("columnlockchange", this, colIndex, value);
61322 getTotalLockedWidth : function(){
61323 var totalWidth = 0;
61324 for(var i = 0; i < this.config.length; i++){
61325 if(this.isLocked(i) && !this.isHidden(i)){
61326 this.totalWidth += this.getColumnWidth(i);
61332 getLockedCount : function(){
61333 for(var i = 0, len = this.config.length; i < len; i++){
61334 if(!this.isLocked(i)){
61339 return this.config.length;
61343 * Returns the number of columns.
61346 getColumnCount : function(visibleOnly){
61347 if(visibleOnly === true){
61349 for(var i = 0, len = this.config.length; i < len; i++){
61350 if(!this.isHidden(i)){
61356 return this.config.length;
61360 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
61361 * @param {Function} fn
61362 * @param {Object} scope (optional)
61363 * @return {Array} result
61365 getColumnsBy : function(fn, scope){
61367 for(var i = 0, len = this.config.length; i < len; i++){
61368 var c = this.config[i];
61369 if(fn.call(scope||this, c, i) === true){
61377 * Returns true if the specified column is sortable.
61378 * @param {Number} col The column index
61379 * @return {Boolean}
61381 isSortable : function(col){
61382 if(typeof this.config[col].sortable == "undefined"){
61383 return this.defaultSortable;
61385 return this.config[col].sortable;
61389 * Returns the rendering (formatting) function defined for the column.
61390 * @param {Number} col The column index.
61391 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
61393 getRenderer : function(col){
61394 if(!this.config[col].renderer){
61395 return Roo.grid.ColumnModel.defaultRenderer;
61397 return this.config[col].renderer;
61401 * Sets the rendering (formatting) function for a column.
61402 * @param {Number} col The column index
61403 * @param {Function} fn The function to use to process the cell's raw data
61404 * to return HTML markup for the grid view. The render function is called with
61405 * the following parameters:<ul>
61406 * <li>Data value.</li>
61407 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
61408 * <li>css A CSS style string to apply to the table cell.</li>
61409 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
61410 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
61411 * <li>Row index</li>
61412 * <li>Column index</li>
61413 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
61415 setRenderer : function(col, fn){
61416 this.config[col].renderer = fn;
61420 * Returns the width for the specified column.
61421 * @param {Number} col The column index
61422 * @param (optional) {String} gridSize bootstrap width size.
61425 getColumnWidth : function(col, gridSize)
61427 var cfg = this.config[col];
61429 if (typeof(gridSize) == 'undefined') {
61430 return cfg.width * 1 || this.defaultWidth;
61432 if (gridSize === false) { // if we set it..
61433 return cfg.width || false;
61435 var sizes = ['xl', 'lg', 'md', 'sm', 'xs'];
61437 for(var i = sizes.indexOf(gridSize); i < sizes.length; i++) {
61438 if (typeof(cfg[ sizes[i] ] ) == 'undefined') {
61441 return cfg[ sizes[i] ];
61448 * Sets the width for a column.
61449 * @param {Number} col The column index
61450 * @param {Number} width The new width
61452 setColumnWidth : function(col, width, suppressEvent){
61453 this.config[col].width = width;
61454 this.totalWidth = null;
61455 if(!suppressEvent){
61456 this.fireEvent("widthchange", this, col, width);
61461 * Returns the total width of all columns.
61462 * @param {Boolean} includeHidden True to include hidden column widths
61465 getTotalWidth : function(includeHidden){
61466 if(!this.totalWidth){
61467 this.totalWidth = 0;
61468 for(var i = 0, len = this.config.length; i < len; i++){
61469 if(includeHidden || !this.isHidden(i)){
61470 this.totalWidth += this.getColumnWidth(i);
61474 return this.totalWidth;
61478 * Returns the header for the specified column.
61479 * @param {Number} col The column index
61482 getColumnHeader : function(col){
61483 return this.config[col].header;
61487 * Sets the header for a column.
61488 * @param {Number} col The column index
61489 * @param {String} header The new header
61491 setColumnHeader : function(col, header){
61492 this.config[col].header = header;
61493 this.fireEvent("headerchange", this, col, header);
61497 * Returns the tooltip for the specified column.
61498 * @param {Number} col The column index
61501 getColumnTooltip : function(col){
61502 return this.config[col].tooltip;
61505 * Sets the tooltip for a column.
61506 * @param {Number} col The column index
61507 * @param {String} tooltip The new tooltip
61509 setColumnTooltip : function(col, tooltip){
61510 this.config[col].tooltip = tooltip;
61514 * Returns the dataIndex for the specified column.
61515 * @param {Number} col The column index
61518 getDataIndex : function(col){
61519 return this.config[col].dataIndex;
61523 * Sets the dataIndex for a column.
61524 * @param {Number} col The column index
61525 * @param {Number} dataIndex The new dataIndex
61527 setDataIndex : function(col, dataIndex){
61528 this.config[col].dataIndex = dataIndex;
61534 * Returns true if the cell is editable.
61535 * @param {Number} colIndex The column index
61536 * @param {Number} rowIndex The row index - this is nto actually used..?
61537 * @return {Boolean}
61539 isCellEditable : function(colIndex, rowIndex){
61540 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
61544 * Returns the editor defined for the cell/column.
61545 * return false or null to disable editing.
61546 * @param {Number} colIndex The column index
61547 * @param {Number} rowIndex The row index
61550 getCellEditor : function(colIndex, rowIndex){
61551 return this.config[colIndex].editor;
61555 * Sets if a column is editable.
61556 * @param {Number} col The column index
61557 * @param {Boolean} editable True if the column is editable
61559 setEditable : function(col, editable){
61560 this.config[col].editable = editable;
61565 * Returns true if the column is hidden.
61566 * @param {Number} colIndex The column index
61567 * @return {Boolean}
61569 isHidden : function(colIndex){
61570 return this.config[colIndex].hidden;
61575 * Returns true if the column width cannot be changed
61577 isFixed : function(colIndex){
61578 return this.config[colIndex].fixed;
61582 * Returns true if the column can be resized
61583 * @return {Boolean}
61585 isResizable : function(colIndex){
61586 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
61589 * Sets if a column is hidden.
61590 * @param {Number} colIndex The column index
61591 * @param {Boolean} hidden True if the column is hidden
61593 setHidden : function(colIndex, hidden){
61594 this.config[colIndex].hidden = hidden;
61595 this.totalWidth = null;
61596 this.fireEvent("hiddenchange", this, colIndex, hidden);
61600 * Sets the editor for a column.
61601 * @param {Number} col The column index
61602 * @param {Object} editor The editor object
61604 setEditor : function(col, editor){
61605 this.config[col].editor = editor;
61608 * Add a column (experimental...) - defaults to adding to the end..
61609 * @param {Object} config
61611 addColumn : function(c)
61614 var i = this.config.length;
61615 this.config[i] = c;
61617 if(typeof c.dataIndex == "undefined"){
61620 if(typeof c.renderer == "string"){
61621 c.renderer = Roo.util.Format[c.renderer];
61623 if(typeof c.id == "undefined"){
61626 if(c.editor && c.editor.xtype){
61627 c.editor = Roo.factory(c.editor, Roo.grid);
61629 if(c.editor && c.editor.isFormField){
61630 c.editor = new Roo.grid.GridEditor(c.editor);
61632 this.lookup[c.id] = c;
61637 Roo.grid.ColumnModel.defaultRenderer = function(value)
61639 if(typeof value == "object") {
61642 if(typeof value == "string" && value.length < 1){
61646 return String.format("{0}", value);
61649 // Alias for backwards compatibility
61650 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
61653 * Ext JS Library 1.1.1
61654 * Copyright(c) 2006-2007, Ext JS, LLC.
61656 * Originally Released Under LGPL - original licence link has changed is not relivant.
61659 * <script type="text/javascript">
61663 * @class Roo.grid.AbstractSelectionModel
61664 * @extends Roo.util.Observable
61666 * Abstract base class for grid SelectionModels. It provides the interface that should be
61667 * implemented by descendant classes. This class should not be directly instantiated.
61670 Roo.grid.AbstractSelectionModel = function(){
61671 this.locked = false;
61672 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
61675 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
61676 /** @ignore Called by the grid automatically. Do not call directly. */
61677 init : function(grid){
61683 * Locks the selections.
61686 this.locked = true;
61690 * Unlocks the selections.
61692 unlock : function(){
61693 this.locked = false;
61697 * Returns true if the selections are locked.
61698 * @return {Boolean}
61700 isLocked : function(){
61701 return this.locked;
61705 * Ext JS Library 1.1.1
61706 * Copyright(c) 2006-2007, Ext JS, LLC.
61708 * Originally Released Under LGPL - original licence link has changed is not relivant.
61711 * <script type="text/javascript">
61714 * @extends Roo.grid.AbstractSelectionModel
61715 * @class Roo.grid.RowSelectionModel
61716 * The default SelectionModel used by {@link Roo.grid.Grid}.
61717 * It supports multiple selections and keyboard selection/navigation.
61719 * @param {Object} config
61721 Roo.grid.RowSelectionModel = function(config){
61722 Roo.apply(this, config);
61723 this.selections = new Roo.util.MixedCollection(false, function(o){
61728 this.lastActive = false;
61732 * @event selectionchange
61733 * Fires when the selection changes
61734 * @param {SelectionModel} this
61736 "selectionchange" : true,
61738 * @event afterselectionchange
61739 * Fires after the selection changes (eg. by key press or clicking)
61740 * @param {SelectionModel} this
61742 "afterselectionchange" : true,
61744 * @event beforerowselect
61745 * Fires when a row is selected being selected, return false to cancel.
61746 * @param {SelectionModel} this
61747 * @param {Number} rowIndex The selected index
61748 * @param {Boolean} keepExisting False if other selections will be cleared
61750 "beforerowselect" : true,
61753 * Fires when a row is selected.
61754 * @param {SelectionModel} this
61755 * @param {Number} rowIndex The selected index
61756 * @param {Roo.data.Record} r The record
61758 "rowselect" : true,
61760 * @event rowdeselect
61761 * Fires when a row is deselected.
61762 * @param {SelectionModel} this
61763 * @param {Number} rowIndex The selected index
61765 "rowdeselect" : true
61767 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
61768 this.locked = false;
61771 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
61773 * @cfg {Boolean} singleSelect
61774 * True to allow selection of only one row at a time (defaults to false)
61776 singleSelect : false,
61779 initEvents : function(){
61781 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
61782 this.grid.on("mousedown", this.handleMouseDown, this);
61783 }else{ // allow click to work like normal
61784 this.grid.on("rowclick", this.handleDragableRowClick, this);
61786 // bootstrap does not have a view..
61787 var view = this.grid.view ? this.grid.view : this.grid;
61788 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
61789 "up" : function(e){
61791 this.selectPrevious(e.shiftKey);
61792 }else if(this.last !== false && this.lastActive !== false){
61793 var last = this.last;
61794 this.selectRange(this.last, this.lastActive-1);
61795 view.focusRow(this.lastActive);
61796 if(last !== false){
61800 this.selectFirstRow();
61802 this.fireEvent("afterselectionchange", this);
61804 "down" : function(e){
61806 this.selectNext(e.shiftKey);
61807 }else if(this.last !== false && this.lastActive !== false){
61808 var last = this.last;
61809 this.selectRange(this.last, this.lastActive+1);
61810 view.focusRow(this.lastActive);
61811 if(last !== false){
61815 this.selectFirstRow();
61817 this.fireEvent("afterselectionchange", this);
61823 view.on("refresh", this.onRefresh, this);
61824 view.on("rowupdated", this.onRowUpdated, this);
61825 view.on("rowremoved", this.onRemove, this);
61829 onRefresh : function(){
61830 var ds = this.grid.ds, i, v = this.grid.view;
61831 var s = this.selections;
61832 s.each(function(r){
61833 if((i = ds.indexOfId(r.id)) != -1){
61835 s.add(ds.getAt(i)); // updating the selection relate data
61843 onRemove : function(v, index, r){
61844 this.selections.remove(r);
61848 onRowUpdated : function(v, index, r){
61849 if(this.isSelected(r)){
61850 v.onRowSelect(index);
61856 * @param {Array} records The records to select
61857 * @param {Boolean} keepExisting (optional) True to keep existing selections
61859 selectRecords : function(records, keepExisting){
61861 this.clearSelections();
61863 var ds = this.grid.ds;
61864 for(var i = 0, len = records.length; i < len; i++){
61865 this.selectRow(ds.indexOf(records[i]), true);
61870 * Gets the number of selected rows.
61873 getCount : function(){
61874 return this.selections.length;
61878 * Selects the first row in the grid.
61880 selectFirstRow : function(){
61885 * Select the last row.
61886 * @param {Boolean} keepExisting (optional) True to keep existing selections
61888 selectLastRow : function(keepExisting){
61889 this.selectRow(this.grid.ds.getCount() - 1, keepExisting);
61893 * Selects the row immediately following the last selected row.
61894 * @param {Boolean} keepExisting (optional) True to keep existing selections
61896 selectNext : function(keepExisting){
61897 if(this.last !== false && (this.last+1) < this.grid.ds.getCount()){
61898 this.selectRow(this.last+1, keepExisting);
61899 var view = this.grid.view ? this.grid.view : this.grid;
61900 view.focusRow(this.last);
61905 * Selects the row that precedes the last selected row.
61906 * @param {Boolean} keepExisting (optional) True to keep existing selections
61908 selectPrevious : function(keepExisting){
61910 this.selectRow(this.last-1, keepExisting);
61911 var view = this.grid.view ? this.grid.view : this.grid;
61912 view.focusRow(this.last);
61917 * Returns the selected records
61918 * @return {Array} Array of selected records
61920 getSelections : function(){
61921 return [].concat(this.selections.items);
61925 * Returns the first selected record.
61928 getSelected : function(){
61929 return this.selections.itemAt(0);
61934 * Clears all selections.
61936 clearSelections : function(fast){
61941 var ds = this.grid.ds;
61942 var s = this.selections;
61943 s.each(function(r){
61944 this.deselectRow(ds.indexOfId(r.id));
61948 this.selections.clear();
61955 * Selects all rows.
61957 selectAll : function(){
61961 this.selections.clear();
61962 for(var i = 0, len = this.grid.ds.getCount(); i < len; i++){
61963 this.selectRow(i, true);
61968 * Returns True if there is a selection.
61969 * @return {Boolean}
61971 hasSelection : function(){
61972 return this.selections.length > 0;
61976 * Returns True if the specified row is selected.
61977 * @param {Number/Record} record The record or index of the record to check
61978 * @return {Boolean}
61980 isSelected : function(index){
61981 var r = typeof index == "number" ? this.grid.ds.getAt(index) : index;
61982 return (r && this.selections.key(r.id) ? true : false);
61986 * Returns True if the specified record id is selected.
61987 * @param {String} id The id of record to check
61988 * @return {Boolean}
61990 isIdSelected : function(id){
61991 return (this.selections.key(id) ? true : false);
61995 handleMouseDown : function(e, t)
61997 var view = this.grid.view ? this.grid.view : this.grid;
61999 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
62002 if(e.shiftKey && this.last !== false){
62003 var last = this.last;
62004 this.selectRange(last, rowIndex, e.ctrlKey);
62005 this.last = last; // reset the last
62006 view.focusRow(rowIndex);
62008 var isSelected = this.isSelected(rowIndex);
62009 if(e.button !== 0 && isSelected){
62010 view.focusRow(rowIndex);
62011 }else if(e.ctrlKey && isSelected){
62012 this.deselectRow(rowIndex);
62013 }else if(!isSelected){
62014 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
62015 view.focusRow(rowIndex);
62018 this.fireEvent("afterselectionchange", this);
62021 handleDragableRowClick : function(grid, rowIndex, e)
62023 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
62024 this.selectRow(rowIndex, false);
62025 var view = this.grid.view ? this.grid.view : this.grid;
62026 view.focusRow(rowIndex);
62027 this.fireEvent("afterselectionchange", this);
62032 * Selects multiple rows.
62033 * @param {Array} rows Array of the indexes of the row to select
62034 * @param {Boolean} keepExisting (optional) True to keep existing selections
62036 selectRows : function(rows, keepExisting){
62038 this.clearSelections();
62040 for(var i = 0, len = rows.length; i < len; i++){
62041 this.selectRow(rows[i], true);
62046 * Selects a range of rows. All rows in between startRow and endRow are also selected.
62047 * @param {Number} startRow The index of the first row in the range
62048 * @param {Number} endRow The index of the last row in the range
62049 * @param {Boolean} keepExisting (optional) True to retain existing selections
62051 selectRange : function(startRow, endRow, keepExisting){
62056 this.clearSelections();
62058 if(startRow <= endRow){
62059 for(var i = startRow; i <= endRow; i++){
62060 this.selectRow(i, true);
62063 for(var i = startRow; i >= endRow; i--){
62064 this.selectRow(i, true);
62070 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
62071 * @param {Number} startRow The index of the first row in the range
62072 * @param {Number} endRow The index of the last row in the range
62074 deselectRange : function(startRow, endRow, preventViewNotify){
62078 for(var i = startRow; i <= endRow; i++){
62079 this.deselectRow(i, preventViewNotify);
62085 * @param {Number} row The index of the row to select
62086 * @param {Boolean} keepExisting (optional) True to keep existing selections
62088 selectRow : function(index, keepExisting, preventViewNotify){
62089 if(this.locked || (index < 0 || index >= this.grid.ds.getCount())) {
62092 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
62093 if(!keepExisting || this.singleSelect){
62094 this.clearSelections();
62096 var r = this.grid.ds.getAt(index);
62097 this.selections.add(r);
62098 this.last = this.lastActive = index;
62099 if(!preventViewNotify){
62100 var view = this.grid.view ? this.grid.view : this.grid;
62101 view.onRowSelect(index);
62103 this.fireEvent("rowselect", this, index, r);
62104 this.fireEvent("selectionchange", this);
62110 * @param {Number} row The index of the row to deselect
62112 deselectRow : function(index, preventViewNotify){
62116 if(this.last == index){
62119 if(this.lastActive == index){
62120 this.lastActive = false;
62122 var r = this.grid.ds.getAt(index);
62123 this.selections.remove(r);
62124 if(!preventViewNotify){
62125 var view = this.grid.view ? this.grid.view : this.grid;
62126 view.onRowDeselect(index);
62128 this.fireEvent("rowdeselect", this, index);
62129 this.fireEvent("selectionchange", this);
62133 restoreLast : function(){
62135 this.last = this._last;
62140 acceptsNav : function(row, col, cm){
62141 return !cm.isHidden(col) && cm.isCellEditable(col, row);
62145 onEditorKey : function(field, e){
62146 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
62151 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
62153 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
62155 }else if(k == e.ENTER && !e.ctrlKey){
62159 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
62161 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
62163 }else if(k == e.ESC){
62167 g.startEditing(newCell[0], newCell[1]);
62172 * Ext JS Library 1.1.1
62173 * Copyright(c) 2006-2007, Ext JS, LLC.
62175 * Originally Released Under LGPL - original licence link has changed is not relivant.
62178 * <script type="text/javascript">
62181 * @class Roo.grid.CellSelectionModel
62182 * @extends Roo.grid.AbstractSelectionModel
62183 * This class provides the basic implementation for cell selection in a grid.
62185 * @param {Object} config The object containing the configuration of this model.
62186 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
62188 Roo.grid.CellSelectionModel = function(config){
62189 Roo.apply(this, config);
62191 this.selection = null;
62195 * @event beforerowselect
62196 * Fires before a cell is selected.
62197 * @param {SelectionModel} this
62198 * @param {Number} rowIndex The selected row index
62199 * @param {Number} colIndex The selected cell index
62201 "beforecellselect" : true,
62203 * @event cellselect
62204 * Fires when a cell is selected.
62205 * @param {SelectionModel} this
62206 * @param {Number} rowIndex The selected row index
62207 * @param {Number} colIndex The selected cell index
62209 "cellselect" : true,
62211 * @event selectionchange
62212 * Fires when the active selection changes.
62213 * @param {SelectionModel} this
62214 * @param {Object} selection null for no selection or an object (o) with two properties
62216 <li>o.record: the record object for the row the selection is in</li>
62217 <li>o.cell: An array of [rowIndex, columnIndex]</li>
62220 "selectionchange" : true,
62223 * Fires when the tab (or enter) was pressed on the last editable cell
62224 * You can use this to trigger add new row.
62225 * @param {SelectionModel} this
62229 * @event beforeeditnext
62230 * Fires before the next editable sell is made active
62231 * You can use this to skip to another cell or fire the tabend
62232 * if you set cell to false
62233 * @param {Object} eventdata object : { cell : [ row, col ] }
62235 "beforeeditnext" : true
62237 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
62240 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
62242 enter_is_tab: false,
62245 initEvents : function(){
62246 this.grid.on("mousedown", this.handleMouseDown, this);
62247 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
62248 var view = this.grid.view;
62249 view.on("refresh", this.onViewChange, this);
62250 view.on("rowupdated", this.onRowUpdated, this);
62251 view.on("beforerowremoved", this.clearSelections, this);
62252 view.on("beforerowsinserted", this.clearSelections, this);
62253 if(this.grid.isEditor){
62254 this.grid.on("beforeedit", this.beforeEdit, this);
62259 beforeEdit : function(e){
62260 this.select(e.row, e.column, false, true, e.record);
62264 onRowUpdated : function(v, index, r){
62265 if(this.selection && this.selection.record == r){
62266 v.onCellSelect(index, this.selection.cell[1]);
62271 onViewChange : function(){
62272 this.clearSelections(true);
62276 * Returns the currently selected cell,.
62277 * @return {Array} The selected cell (row, column) or null if none selected.
62279 getSelectedCell : function(){
62280 return this.selection ? this.selection.cell : null;
62284 * Clears all selections.
62285 * @param {Boolean} true to prevent the gridview from being notified about the change.
62287 clearSelections : function(preventNotify){
62288 var s = this.selection;
62290 if(preventNotify !== true){
62291 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
62293 this.selection = null;
62294 this.fireEvent("selectionchange", this, null);
62299 * Returns true if there is a selection.
62300 * @return {Boolean}
62302 hasSelection : function(){
62303 return this.selection ? true : false;
62307 handleMouseDown : function(e, t){
62308 var v = this.grid.getView();
62309 if(this.isLocked()){
62312 var row = v.findRowIndex(t);
62313 var cell = v.findCellIndex(t);
62314 if(row !== false && cell !== false){
62315 this.select(row, cell);
62321 * @param {Number} rowIndex
62322 * @param {Number} collIndex
62324 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
62325 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
62326 this.clearSelections();
62327 r = r || this.grid.dataSource.getAt(rowIndex);
62330 cell : [rowIndex, colIndex]
62332 if(!preventViewNotify){
62333 var v = this.grid.getView();
62334 v.onCellSelect(rowIndex, colIndex);
62335 if(preventFocus !== true){
62336 v.focusCell(rowIndex, colIndex);
62339 this.fireEvent("cellselect", this, rowIndex, colIndex);
62340 this.fireEvent("selectionchange", this, this.selection);
62345 isSelectable : function(rowIndex, colIndex, cm){
62346 return !cm.isHidden(colIndex);
62350 handleKeyDown : function(e){
62351 //Roo.log('Cell Sel Model handleKeyDown');
62352 if(!e.isNavKeyPress()){
62355 var g = this.grid, s = this.selection;
62358 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
62360 this.select(cell[0], cell[1]);
62365 var walk = function(row, col, step){
62366 return g.walkCells(row, col, step, sm.isSelectable, sm);
62368 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
62375 // handled by onEditorKey
62376 if (g.isEditor && g.editing) {
62380 newCell = walk(r, c-1, -1);
62382 newCell = walk(r, c+1, 1);
62387 newCell = walk(r+1, c, 1);
62391 newCell = walk(r-1, c, -1);
62395 newCell = walk(r, c+1, 1);
62399 newCell = walk(r, c-1, -1);
62404 if(g.isEditor && !g.editing){
62405 g.startEditing(r, c);
62414 this.select(newCell[0], newCell[1]);
62420 acceptsNav : function(row, col, cm){
62421 return !cm.isHidden(col) && cm.isCellEditable(col, row);
62425 * @param {Number} field (not used) - as it's normally used as a listener
62426 * @param {Number} e - event - fake it by using
62428 * var e = Roo.EventObjectImpl.prototype;
62429 * e.keyCode = e.TAB
62433 onEditorKey : function(field, e){
62435 var k = e.getKey(),
62438 ed = g.activeEditor,
62440 ///Roo.log('onEditorKey' + k);
62443 if (this.enter_is_tab && k == e.ENTER) {
62449 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
62451 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
62457 } else if(k == e.ENTER && !e.ctrlKey){
62460 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
62462 } else if(k == e.ESC){
62467 var ecall = { cell : newCell, forward : forward };
62468 this.fireEvent('beforeeditnext', ecall );
62469 newCell = ecall.cell;
62470 forward = ecall.forward;
62474 //Roo.log('next cell after edit');
62475 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
62476 } else if (forward) {
62477 // tabbed past last
62478 this.fireEvent.defer(100, this, ['tabend',this]);
62483 * Ext JS Library 1.1.1
62484 * Copyright(c) 2006-2007, Ext JS, LLC.
62486 * Originally Released Under LGPL - original licence link has changed is not relivant.
62489 * <script type="text/javascript">
62493 * @class Roo.grid.EditorGrid
62494 * @extends Roo.grid.Grid
62495 * Class for creating and editable grid.
62496 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
62497 * The container MUST have some type of size defined for the grid to fill. The container will be
62498 * automatically set to position relative if it isn't already.
62499 * @param {Object} dataSource The data model to bind to
62500 * @param {Object} colModel The column model with info about this grid's columns
62502 Roo.grid.EditorGrid = function(container, config){
62503 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
62504 this.getGridEl().addClass("xedit-grid");
62506 if(!this.selModel){
62507 this.selModel = new Roo.grid.CellSelectionModel();
62510 this.activeEditor = null;
62514 * @event beforeedit
62515 * Fires before cell editing is triggered. The edit event object has the following properties <br />
62516 * <ul style="padding:5px;padding-left:16px;">
62517 * <li>grid - This grid</li>
62518 * <li>record - The record being edited</li>
62519 * <li>field - The field name being edited</li>
62520 * <li>value - The value for the field being edited.</li>
62521 * <li>row - The grid row index</li>
62522 * <li>column - The grid column index</li>
62523 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
62525 * @param {Object} e An edit event (see above for description)
62527 "beforeedit" : true,
62530 * Fires after a cell is edited. <br />
62531 * <ul style="padding:5px;padding-left:16px;">
62532 * <li>grid - This grid</li>
62533 * <li>record - The record being edited</li>
62534 * <li>field - The field name being edited</li>
62535 * <li>value - The value being set</li>
62536 * <li>originalValue - The original value for the field, before the edit.</li>
62537 * <li>row - The grid row index</li>
62538 * <li>column - The grid column index</li>
62540 * @param {Object} e An edit event (see above for description)
62542 "afteredit" : true,
62544 * @event validateedit
62545 * Fires after a cell is edited, but before the value is set in the record.
62546 * You can use this to modify the value being set in the field, Return false
62547 * to cancel the change. The edit event object has the following properties <br />
62548 * <ul style="padding:5px;padding-left:16px;">
62549 * <li>editor - This editor</li>
62550 * <li>grid - This grid</li>
62551 * <li>record - The record being edited</li>
62552 * <li>field - The field name being edited</li>
62553 * <li>value - The value being set</li>
62554 * <li>originalValue - The original value for the field, before the edit.</li>
62555 * <li>row - The grid row index</li>
62556 * <li>column - The grid column index</li>
62557 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
62559 * @param {Object} e An edit event (see above for description)
62561 "validateedit" : true
62563 this.on("bodyscroll", this.stopEditing, this);
62564 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
62567 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
62569 * @cfg {Number} clicksToEdit
62570 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
62577 trackMouseOver: false, // causes very odd FF errors
62579 onCellDblClick : function(g, row, col){
62580 this.startEditing(row, col);
62583 onEditComplete : function(ed, value, startValue){
62584 this.editing = false;
62585 this.activeEditor = null;
62586 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
62588 var field = this.colModel.getDataIndex(ed.col);
62593 originalValue: startValue,
62600 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
62603 if(String(value) !== String(startValue)){
62605 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
62606 r.set(field, e.value);
62607 // if we are dealing with a combo box..
62608 // then we also set the 'name' colum to be the displayField
62609 if (ed.field.displayField && ed.field.name) {
62610 r.set(ed.field.name, ed.field.el.dom.value);
62613 delete e.cancel; //?? why!!!
62614 this.fireEvent("afteredit", e);
62617 this.fireEvent("afteredit", e); // always fire it!
62619 this.view.focusCell(ed.row, ed.col);
62623 * Starts editing the specified for the specified row/column
62624 * @param {Number} rowIndex
62625 * @param {Number} colIndex
62627 startEditing : function(row, col){
62628 this.stopEditing();
62629 if(this.colModel.isCellEditable(col, row)){
62630 this.view.ensureVisible(row, col, true);
62632 var r = this.dataSource.getAt(row);
62633 var field = this.colModel.getDataIndex(col);
62634 var cell = Roo.get(this.view.getCell(row,col));
62639 value: r.data[field],
62644 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
62645 this.editing = true;
62646 var ed = this.colModel.getCellEditor(col, row);
62652 ed.render(ed.parentEl || document.body);
62658 (function(){ // complex but required for focus issues in safari, ie and opera
62662 ed.on("complete", this.onEditComplete, this, {single: true});
62663 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
62664 this.activeEditor = ed;
62665 var v = r.data[field];
62666 ed.startEdit(this.view.getCell(row, col), v);
62667 // combo's with 'displayField and name set
62668 if (ed.field.displayField && ed.field.name) {
62669 ed.field.el.dom.value = r.data[ed.field.name];
62673 }).defer(50, this);
62679 * Stops any active editing
62681 stopEditing : function(){
62682 if(this.activeEditor){
62683 this.activeEditor.completeEdit();
62685 this.activeEditor = null;
62689 * Called to get grid's drag proxy text, by default returns this.ddText.
62692 getDragDropText : function(){
62693 var count = this.selModel.getSelectedCell() ? 1 : 0;
62694 return String.format(this.ddText, count, count == 1 ? '' : 's');
62699 * Ext JS Library 1.1.1
62700 * Copyright(c) 2006-2007, Ext JS, LLC.
62702 * Originally Released Under LGPL - original licence link has changed is not relivant.
62705 * <script type="text/javascript">
62708 // private - not really -- you end up using it !
62709 // This is a support class used internally by the Grid components
62712 * @class Roo.grid.GridEditor
62713 * @extends Roo.Editor
62714 * Class for creating and editable grid elements.
62715 * @param {Object} config any settings (must include field)
62717 Roo.grid.GridEditor = function(field, config){
62718 if (!config && field.field) {
62720 field = Roo.factory(config.field, Roo.form);
62722 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
62723 field.monitorTab = false;
62726 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
62729 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
62732 alignment: "tl-tl",
62735 cls: "x-small-editor x-grid-editor",
62740 * Ext JS Library 1.1.1
62741 * Copyright(c) 2006-2007, Ext JS, LLC.
62743 * Originally Released Under LGPL - original licence link has changed is not relivant.
62746 * <script type="text/javascript">
62751 Roo.grid.PropertyRecord = Roo.data.Record.create([
62752 {name:'name',type:'string'}, 'value'
62756 Roo.grid.PropertyStore = function(grid, source){
62758 this.store = new Roo.data.Store({
62759 recordType : Roo.grid.PropertyRecord
62761 this.store.on('update', this.onUpdate, this);
62763 this.setSource(source);
62765 Roo.grid.PropertyStore.superclass.constructor.call(this);
62770 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
62771 setSource : function(o){
62773 this.store.removeAll();
62776 if(this.isEditableValue(o[k])){
62777 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
62780 this.store.loadRecords({records: data}, {}, true);
62783 onUpdate : function(ds, record, type){
62784 if(type == Roo.data.Record.EDIT){
62785 var v = record.data['value'];
62786 var oldValue = record.modified['value'];
62787 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
62788 this.source[record.id] = v;
62790 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
62797 getProperty : function(row){
62798 return this.store.getAt(row);
62801 isEditableValue: function(val){
62802 if(val && val instanceof Date){
62804 }else if(typeof val == 'object' || typeof val == 'function'){
62810 setValue : function(prop, value){
62811 this.source[prop] = value;
62812 this.store.getById(prop).set('value', value);
62815 getSource : function(){
62816 return this.source;
62820 Roo.grid.PropertyColumnModel = function(grid, store){
62823 g.PropertyColumnModel.superclass.constructor.call(this, [
62824 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
62825 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
62827 this.store = store;
62828 this.bselect = Roo.DomHelper.append(document.body, {
62829 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
62830 {tag: 'option', value: 'true', html: 'true'},
62831 {tag: 'option', value: 'false', html: 'false'}
62834 Roo.id(this.bselect);
62837 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
62838 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
62839 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
62840 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
62841 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
62843 this.renderCellDelegate = this.renderCell.createDelegate(this);
62844 this.renderPropDelegate = this.renderProp.createDelegate(this);
62847 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
62851 valueText : 'Value',
62853 dateFormat : 'm/j/Y',
62856 renderDate : function(dateVal){
62857 return dateVal.dateFormat(this.dateFormat);
62860 renderBool : function(bVal){
62861 return bVal ? 'true' : 'false';
62864 isCellEditable : function(colIndex, rowIndex){
62865 return colIndex == 1;
62868 getRenderer : function(col){
62870 this.renderCellDelegate : this.renderPropDelegate;
62873 renderProp : function(v){
62874 return this.getPropertyName(v);
62877 renderCell : function(val){
62879 if(val instanceof Date){
62880 rv = this.renderDate(val);
62881 }else if(typeof val == 'boolean'){
62882 rv = this.renderBool(val);
62884 return Roo.util.Format.htmlEncode(rv);
62887 getPropertyName : function(name){
62888 var pn = this.grid.propertyNames;
62889 return pn && pn[name] ? pn[name] : name;
62892 getCellEditor : function(colIndex, rowIndex){
62893 var p = this.store.getProperty(rowIndex);
62894 var n = p.data['name'], val = p.data['value'];
62896 if(typeof(this.grid.customEditors[n]) == 'string'){
62897 return this.editors[this.grid.customEditors[n]];
62899 if(typeof(this.grid.customEditors[n]) != 'undefined'){
62900 return this.grid.customEditors[n];
62902 if(val instanceof Date){
62903 return this.editors['date'];
62904 }else if(typeof val == 'number'){
62905 return this.editors['number'];
62906 }else if(typeof val == 'boolean'){
62907 return this.editors['boolean'];
62909 return this.editors['string'];
62915 * @class Roo.grid.PropertyGrid
62916 * @extends Roo.grid.EditorGrid
62917 * This class represents the interface of a component based property grid control.
62918 * <br><br>Usage:<pre><code>
62919 var grid = new Roo.grid.PropertyGrid("my-container-id", {
62927 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
62928 * The container MUST have some type of size defined for the grid to fill. The container will be
62929 * automatically set to position relative if it isn't already.
62930 * @param {Object} config A config object that sets properties on this grid.
62932 Roo.grid.PropertyGrid = function(container, config){
62933 config = config || {};
62934 var store = new Roo.grid.PropertyStore(this);
62935 this.store = store;
62936 var cm = new Roo.grid.PropertyColumnModel(this, store);
62937 store.store.sort('name', 'ASC');
62938 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
62941 enableColLock:false,
62942 enableColumnMove:false,
62944 trackMouseOver: false,
62947 this.getGridEl().addClass('x-props-grid');
62948 this.lastEditRow = null;
62949 this.on('columnresize', this.onColumnResize, this);
62952 * @event beforepropertychange
62953 * Fires before a property changes (return false to stop?)
62954 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
62955 * @param {String} id Record Id
62956 * @param {String} newval New Value
62957 * @param {String} oldval Old Value
62959 "beforepropertychange": true,
62961 * @event propertychange
62962 * Fires after a property changes
62963 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
62964 * @param {String} id Record Id
62965 * @param {String} newval New Value
62966 * @param {String} oldval Old Value
62968 "propertychange": true
62970 this.customEditors = this.customEditors || {};
62972 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
62975 * @cfg {Object} customEditors map of colnames=> custom editors.
62976 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
62977 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
62978 * false disables editing of the field.
62982 * @cfg {Object} propertyNames map of property Names to their displayed value
62985 render : function(){
62986 Roo.grid.PropertyGrid.superclass.render.call(this);
62987 this.autoSize.defer(100, this);
62990 autoSize : function(){
62991 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
62993 this.view.fitColumns();
62997 onColumnResize : function(){
62998 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
63002 * Sets the data for the Grid
63003 * accepts a Key => Value object of all the elements avaiable.
63004 * @param {Object} data to appear in grid.
63006 setSource : function(source){
63007 this.store.setSource(source);
63011 * Gets all the data from the grid.
63012 * @return {Object} data data stored in grid
63014 getSource : function(){
63015 return this.store.getSource();
63024 * @class Roo.grid.Calendar
63025 * @extends Roo.grid.Grid
63026 * This class extends the Grid to provide a calendar widget
63027 * <br><br>Usage:<pre><code>
63028 var grid = new Roo.grid.Calendar("my-container-id", {
63031 selModel: mySelectionModel,
63032 autoSizeColumns: true,
63033 monitorWindowResize: false,
63034 trackMouseOver: true
63035 eventstore : real data store..
63041 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
63042 * The container MUST have some type of size defined for the grid to fill. The container will be
63043 * automatically set to position relative if it isn't already.
63044 * @param {Object} config A config object that sets properties on this grid.
63046 Roo.grid.Calendar = function(container, config){
63047 // initialize the container
63048 this.container = Roo.get(container);
63049 this.container.update("");
63050 this.container.setStyle("overflow", "hidden");
63051 this.container.addClass('x-grid-container');
63053 this.id = this.container.id;
63055 Roo.apply(this, config);
63056 // check and correct shorthanded configs
63060 for (var r = 0;r < 6;r++) {
63063 for (var c =0;c < 7;c++) {
63067 if (this.eventStore) {
63068 this.eventStore= Roo.factory(this.eventStore, Roo.data);
63069 this.eventStore.on('load',this.onLoad, this);
63070 this.eventStore.on('beforeload',this.clearEvents, this);
63074 this.dataSource = new Roo.data.Store({
63075 proxy: new Roo.data.MemoryProxy(rows),
63076 reader: new Roo.data.ArrayReader({}, [
63077 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
63080 this.dataSource.load();
63081 this.ds = this.dataSource;
63082 this.ds.xmodule = this.xmodule || false;
63085 var cellRender = function(v,x,r)
63087 return String.format(
63088 '<div class="fc-day fc-widget-content"><div>' +
63089 '<div class="fc-event-container"></div>' +
63090 '<div class="fc-day-number">{0}</div>'+
63092 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
63093 '</div></div>', v);
63098 this.colModel = new Roo.grid.ColumnModel( [
63100 xtype: 'ColumnModel',
63102 dataIndex : 'weekday0',
63104 renderer : cellRender
63107 xtype: 'ColumnModel',
63109 dataIndex : 'weekday1',
63111 renderer : cellRender
63114 xtype: 'ColumnModel',
63116 dataIndex : 'weekday2',
63117 header : 'Tuesday',
63118 renderer : cellRender
63121 xtype: 'ColumnModel',
63123 dataIndex : 'weekday3',
63124 header : 'Wednesday',
63125 renderer : cellRender
63128 xtype: 'ColumnModel',
63130 dataIndex : 'weekday4',
63131 header : 'Thursday',
63132 renderer : cellRender
63135 xtype: 'ColumnModel',
63137 dataIndex : 'weekday5',
63139 renderer : cellRender
63142 xtype: 'ColumnModel',
63144 dataIndex : 'weekday6',
63145 header : 'Saturday',
63146 renderer : cellRender
63149 this.cm = this.colModel;
63150 this.cm.xmodule = this.xmodule || false;
63154 //this.selModel = new Roo.grid.CellSelectionModel();
63155 //this.sm = this.selModel;
63156 //this.selModel.init(this);
63160 this.container.setWidth(this.width);
63164 this.container.setHeight(this.height);
63171 * The raw click event for the entire grid.
63172 * @param {Roo.EventObject} e
63177 * The raw dblclick event for the entire grid.
63178 * @param {Roo.EventObject} e
63182 * @event contextmenu
63183 * The raw contextmenu event for the entire grid.
63184 * @param {Roo.EventObject} e
63186 "contextmenu" : true,
63189 * The raw mousedown event for the entire grid.
63190 * @param {Roo.EventObject} e
63192 "mousedown" : true,
63195 * The raw mouseup event for the entire grid.
63196 * @param {Roo.EventObject} e
63201 * The raw mouseover event for the entire grid.
63202 * @param {Roo.EventObject} e
63204 "mouseover" : true,
63207 * The raw mouseout event for the entire grid.
63208 * @param {Roo.EventObject} e
63213 * The raw keypress event for the entire grid.
63214 * @param {Roo.EventObject} e
63219 * The raw keydown event for the entire grid.
63220 * @param {Roo.EventObject} e
63228 * Fires when a cell is clicked
63229 * @param {Grid} this
63230 * @param {Number} rowIndex
63231 * @param {Number} columnIndex
63232 * @param {Roo.EventObject} e
63234 "cellclick" : true,
63236 * @event celldblclick
63237 * Fires when a cell is double clicked
63238 * @param {Grid} this
63239 * @param {Number} rowIndex
63240 * @param {Number} columnIndex
63241 * @param {Roo.EventObject} e
63243 "celldblclick" : true,
63246 * Fires when a row is clicked
63247 * @param {Grid} this
63248 * @param {Number} rowIndex
63249 * @param {Roo.EventObject} e
63253 * @event rowdblclick
63254 * Fires when a row is double clicked
63255 * @param {Grid} this
63256 * @param {Number} rowIndex
63257 * @param {Roo.EventObject} e
63259 "rowdblclick" : true,
63261 * @event headerclick
63262 * Fires when a header is clicked
63263 * @param {Grid} this
63264 * @param {Number} columnIndex
63265 * @param {Roo.EventObject} e
63267 "headerclick" : true,
63269 * @event headerdblclick
63270 * Fires when a header cell is double clicked
63271 * @param {Grid} this
63272 * @param {Number} columnIndex
63273 * @param {Roo.EventObject} e
63275 "headerdblclick" : true,
63277 * @event rowcontextmenu
63278 * Fires when a row is right clicked
63279 * @param {Grid} this
63280 * @param {Number} rowIndex
63281 * @param {Roo.EventObject} e
63283 "rowcontextmenu" : true,
63285 * @event cellcontextmenu
63286 * Fires when a cell is right clicked
63287 * @param {Grid} this
63288 * @param {Number} rowIndex
63289 * @param {Number} cellIndex
63290 * @param {Roo.EventObject} e
63292 "cellcontextmenu" : true,
63294 * @event headercontextmenu
63295 * Fires when a header is right clicked
63296 * @param {Grid} this
63297 * @param {Number} columnIndex
63298 * @param {Roo.EventObject} e
63300 "headercontextmenu" : true,
63302 * @event bodyscroll
63303 * Fires when the body element is scrolled
63304 * @param {Number} scrollLeft
63305 * @param {Number} scrollTop
63307 "bodyscroll" : true,
63309 * @event columnresize
63310 * Fires when the user resizes a column
63311 * @param {Number} columnIndex
63312 * @param {Number} newSize
63314 "columnresize" : true,
63316 * @event columnmove
63317 * Fires when the user moves a column
63318 * @param {Number} oldIndex
63319 * @param {Number} newIndex
63321 "columnmove" : true,
63324 * Fires when row(s) start being dragged
63325 * @param {Grid} this
63326 * @param {Roo.GridDD} dd The drag drop object
63327 * @param {event} e The raw browser event
63329 "startdrag" : true,
63332 * Fires when a drag operation is complete
63333 * @param {Grid} this
63334 * @param {Roo.GridDD} dd The drag drop object
63335 * @param {event} e The raw browser event
63340 * Fires when dragged row(s) are dropped on a valid DD target
63341 * @param {Grid} this
63342 * @param {Roo.GridDD} dd The drag drop object
63343 * @param {String} targetId The target drag drop object
63344 * @param {event} e The raw browser event
63349 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
63350 * @param {Grid} this
63351 * @param {Roo.GridDD} dd The drag drop object
63352 * @param {String} targetId The target drag drop object
63353 * @param {event} e The raw browser event
63358 * Fires when the dragged row(s) first cross another DD target while being dragged
63359 * @param {Grid} this
63360 * @param {Roo.GridDD} dd The drag drop object
63361 * @param {String} targetId The target drag drop object
63362 * @param {event} e The raw browser event
63364 "dragenter" : true,
63367 * Fires when the dragged row(s) leave another DD target while being dragged
63368 * @param {Grid} this
63369 * @param {Roo.GridDD} dd The drag drop object
63370 * @param {String} targetId The target drag drop object
63371 * @param {event} e The raw browser event
63376 * Fires when a row is rendered, so you can change add a style to it.
63377 * @param {GridView} gridview The grid view
63378 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
63384 * Fires when the grid is rendered
63385 * @param {Grid} grid
63390 * Fires when a date is selected
63391 * @param {DatePicker} this
63392 * @param {Date} date The selected date
63396 * @event monthchange
63397 * Fires when the displayed month changes
63398 * @param {DatePicker} this
63399 * @param {Date} date The selected month
63401 'monthchange': true,
63403 * @event evententer
63404 * Fires when mouse over an event
63405 * @param {Calendar} this
63406 * @param {event} Event
63408 'evententer': true,
63410 * @event eventleave
63411 * Fires when the mouse leaves an
63412 * @param {Calendar} this
63415 'eventleave': true,
63417 * @event eventclick
63418 * Fires when the mouse click an
63419 * @param {Calendar} this
63422 'eventclick': true,
63424 * @event eventrender
63425 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
63426 * @param {Calendar} this
63427 * @param {data} data to be modified
63429 'eventrender': true
63433 Roo.grid.Grid.superclass.constructor.call(this);
63434 this.on('render', function() {
63435 this.view.el.addClass('x-grid-cal');
63437 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
63441 if (!Roo.grid.Calendar.style) {
63442 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
63445 '.x-grid-cal .x-grid-col' : {
63446 height: 'auto !important',
63447 'vertical-align': 'top'
63449 '.x-grid-cal .fc-event-hori' : {
63460 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
63462 * @cfg {Store} eventStore The store that loads events.
63467 activeDate : false,
63470 monitorWindowResize : false,
63473 resizeColumns : function() {
63474 var col = (this.view.el.getWidth() / 7) - 3;
63475 // loop through cols, and setWidth
63476 for(var i =0 ; i < 7 ; i++){
63477 this.cm.setColumnWidth(i, col);
63480 setDate :function(date) {
63482 Roo.log('setDate?');
63484 this.resizeColumns();
63485 var vd = this.activeDate;
63486 this.activeDate = date;
63487 // if(vd && this.el){
63488 // var t = date.getTime();
63489 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
63490 // Roo.log('using add remove');
63492 // this.fireEvent('monthchange', this, date);
63494 // this.cells.removeClass("fc-state-highlight");
63495 // this.cells.each(function(c){
63496 // if(c.dateValue == t){
63497 // c.addClass("fc-state-highlight");
63498 // setTimeout(function(){
63499 // try{c.dom.firstChild.focus();}catch(e){}
63509 var days = date.getDaysInMonth();
63511 var firstOfMonth = date.getFirstDateOfMonth();
63512 var startingPos = firstOfMonth.getDay()-this.startDay;
63514 if(startingPos < this.startDay){
63518 var pm = date.add(Date.MONTH, -1);
63519 var prevStart = pm.getDaysInMonth()-startingPos;
63523 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
63525 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
63526 //this.cells.addClassOnOver('fc-state-hover');
63528 var cells = this.cells.elements;
63529 var textEls = this.textNodes;
63531 //Roo.each(cells, function(cell){
63532 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
63535 days += startingPos;
63537 // convert everything to numbers so it's fast
63538 var day = 86400000;
63539 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
63542 //Roo.log(prevStart);
63544 var today = new Date().clearTime().getTime();
63545 var sel = date.clearTime().getTime();
63546 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
63547 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
63548 var ddMatch = this.disabledDatesRE;
63549 var ddText = this.disabledDatesText;
63550 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
63551 var ddaysText = this.disabledDaysText;
63552 var format = this.format;
63554 var setCellClass = function(cal, cell){
63556 //Roo.log('set Cell Class');
63558 var t = d.getTime();
63563 cell.dateValue = t;
63565 cell.className += " fc-today";
63566 cell.className += " fc-state-highlight";
63567 cell.title = cal.todayText;
63570 // disable highlight in other month..
63571 cell.className += " fc-state-highlight";
63576 //cell.className = " fc-state-disabled";
63577 cell.title = cal.minText;
63581 //cell.className = " fc-state-disabled";
63582 cell.title = cal.maxText;
63586 if(ddays.indexOf(d.getDay()) != -1){
63587 // cell.title = ddaysText;
63588 // cell.className = " fc-state-disabled";
63591 if(ddMatch && format){
63592 var fvalue = d.dateFormat(format);
63593 if(ddMatch.test(fvalue)){
63594 cell.title = ddText.replace("%0", fvalue);
63595 cell.className = " fc-state-disabled";
63599 if (!cell.initialClassName) {
63600 cell.initialClassName = cell.dom.className;
63603 cell.dom.className = cell.initialClassName + ' ' + cell.className;
63608 for(; i < startingPos; i++) {
63609 cells[i].dayName = (++prevStart);
63610 Roo.log(textEls[i]);
63611 d.setDate(d.getDate()+1);
63613 //cells[i].className = "fc-past fc-other-month";
63614 setCellClass(this, cells[i]);
63619 for(; i < days; i++){
63620 intDay = i - startingPos + 1;
63621 cells[i].dayName = (intDay);
63622 d.setDate(d.getDate()+1);
63624 cells[i].className = ''; // "x-date-active";
63625 setCellClass(this, cells[i]);
63629 for(; i < 42; i++) {
63630 //textEls[i].innerHTML = (++extraDays);
63632 d.setDate(d.getDate()+1);
63633 cells[i].dayName = (++extraDays);
63634 cells[i].className = "fc-future fc-other-month";
63635 setCellClass(this, cells[i]);
63638 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
63640 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
63642 // this will cause all the cells to mis
63645 for (var r = 0;r < 6;r++) {
63646 for (var c =0;c < 7;c++) {
63647 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
63651 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
63652 for(i=0;i<cells.length;i++) {
63654 this.cells.elements[i].dayName = cells[i].dayName ;
63655 this.cells.elements[i].className = cells[i].className;
63656 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
63657 this.cells.elements[i].title = cells[i].title ;
63658 this.cells.elements[i].dateValue = cells[i].dateValue ;
63664 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
63665 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
63667 ////if(totalRows != 6){
63668 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
63669 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
63672 this.fireEvent('monthchange', this, date);
63677 * Returns the grid's SelectionModel.
63678 * @return {SelectionModel}
63680 getSelectionModel : function(){
63681 if(!this.selModel){
63682 this.selModel = new Roo.grid.CellSelectionModel();
63684 return this.selModel;
63688 this.eventStore.load()
63694 findCell : function(dt) {
63695 dt = dt.clearTime().getTime();
63697 this.cells.each(function(c){
63698 //Roo.log("check " +c.dateValue + '?=' + dt);
63699 if(c.dateValue == dt){
63709 findCells : function(rec) {
63710 var s = rec.data.start_dt.clone().clearTime().getTime();
63712 var e= rec.data.end_dt.clone().clearTime().getTime();
63715 this.cells.each(function(c){
63716 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
63718 if(c.dateValue > e){
63721 if(c.dateValue < s){
63730 findBestRow: function(cells)
63734 for (var i =0 ; i < cells.length;i++) {
63735 ret = Math.max(cells[i].rows || 0,ret);
63742 addItem : function(rec)
63744 // look for vertical location slot in
63745 var cells = this.findCells(rec);
63747 rec.row = this.findBestRow(cells);
63749 // work out the location.
63753 for(var i =0; i < cells.length; i++) {
63761 if (crow.start.getY() == cells[i].getY()) {
63763 crow.end = cells[i];
63779 for (var i = 0; i < cells.length;i++) {
63780 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
63787 clearEvents: function() {
63789 if (!this.eventStore.getCount()) {
63792 // reset number of rows in cells.
63793 Roo.each(this.cells.elements, function(c){
63797 this.eventStore.each(function(e) {
63798 this.clearEvent(e);
63803 clearEvent : function(ev)
63806 Roo.each(ev.els, function(el) {
63807 el.un('mouseenter' ,this.onEventEnter, this);
63808 el.un('mouseleave' ,this.onEventLeave, this);
63816 renderEvent : function(ev,ctr) {
63818 ctr = this.view.el.select('.fc-event-container',true).first();
63822 this.clearEvent(ev);
63828 var cells = ev.cells;
63829 var rows = ev.rows;
63830 this.fireEvent('eventrender', this, ev);
63832 for(var i =0; i < rows.length; i++) {
63836 cls += ' fc-event-start';
63838 if ((i+1) == rows.length) {
63839 cls += ' fc-event-end';
63842 //Roo.log(ev.data);
63843 // how many rows should it span..
63844 var cg = this.eventTmpl.append(ctr,Roo.apply({
63847 }, ev.data) , true);
63850 cg.on('mouseenter' ,this.onEventEnter, this, ev);
63851 cg.on('mouseleave' ,this.onEventLeave, this, ev);
63852 cg.on('click', this.onEventClick, this, ev);
63856 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
63857 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
63860 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
63861 cg.setWidth(ebox.right - sbox.x -2);
63865 renderEvents: function()
63867 // first make sure there is enough space..
63869 if (!this.eventTmpl) {
63870 this.eventTmpl = new Roo.Template(
63871 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
63872 '<div class="fc-event-inner">' +
63873 '<span class="fc-event-time">{time}</span>' +
63874 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
63876 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
63884 this.cells.each(function(c) {
63885 //Roo.log(c.select('.fc-day-content div',true).first());
63886 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
63889 var ctr = this.view.el.select('.fc-event-container',true).first();
63892 this.eventStore.each(function(ev){
63894 this.renderEvent(ev);
63898 this.view.layout();
63902 onEventEnter: function (e, el,event,d) {
63903 this.fireEvent('evententer', this, el, event);
63906 onEventLeave: function (e, el,event,d) {
63907 this.fireEvent('eventleave', this, el, event);
63910 onEventClick: function (e, el,event,d) {
63911 this.fireEvent('eventclick', this, el, event);
63914 onMonthChange: function () {
63918 onLoad: function () {
63920 //Roo.log('calendar onload');
63922 if(this.eventStore.getCount() > 0){
63926 this.eventStore.each(function(d){
63931 if (typeof(add.end_dt) == 'undefined') {
63932 Roo.log("Missing End time in calendar data: ");
63936 if (typeof(add.start_dt) == 'undefined') {
63937 Roo.log("Missing Start time in calendar data: ");
63941 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
63942 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
63943 add.id = add.id || d.id;
63944 add.title = add.title || '??';
63952 this.renderEvents();
63962 render : function ()
63966 if (!this.view.el.hasClass('course-timesheet')) {
63967 this.view.el.addClass('course-timesheet');
63969 if (this.tsStyle) {
63974 Roo.log(_this.grid.view.el.getWidth());
63977 this.tsStyle = Roo.util.CSS.createStyleSheet({
63978 '.course-timesheet .x-grid-row' : {
63981 '.x-grid-row td' : {
63982 'vertical-align' : 0
63984 '.course-edit-link' : {
63986 'text-overflow' : 'ellipsis',
63987 'overflow' : 'hidden',
63988 'white-space' : 'nowrap',
63989 'cursor' : 'pointer'
63994 '.de-act-sup-link' : {
63995 'color' : 'purple',
63996 'text-decoration' : 'line-through'
64000 'text-decoration' : 'line-through'
64002 '.course-timesheet .course-highlight' : {
64003 'border-top-style': 'dashed !important',
64004 'border-bottom-bottom': 'dashed !important'
64006 '.course-timesheet .course-item' : {
64007 'font-family' : 'tahoma, arial, helvetica',
64008 'font-size' : '11px',
64009 'overflow' : 'hidden',
64010 'padding-left' : '10px',
64011 'padding-right' : '10px',
64012 'padding-top' : '10px'
64020 monitorWindowResize : false,
64021 cellrenderer : function(v,x,r)
64026 xtype: 'CellSelectionModel',
64033 beforeload : function (_self, options)
64035 options.params = options.params || {};
64036 options.params._month = _this.monthField.getValue();
64037 options.params.limit = 9999;
64038 options.params['sort'] = 'when_dt';
64039 options.params['dir'] = 'ASC';
64040 this.proxy.loadResponse = this.loadResponse;
64042 //this.addColumns();
64044 load : function (_self, records, options)
64046 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
64047 // if you click on the translation.. you can edit it...
64048 var el = Roo.get(this);
64049 var id = el.dom.getAttribute('data-id');
64050 var d = el.dom.getAttribute('data-date');
64051 var t = el.dom.getAttribute('data-time');
64052 //var id = this.child('span').dom.textContent;
64055 Pman.Dialog.CourseCalendar.show({
64059 productitem_active : id ? 1 : 0
64061 _this.grid.ds.load({});
64066 _this.panel.fireEvent('resize', [ '', '' ]);
64069 loadResponse : function(o, success, response){
64070 // this is overridden on before load..
64072 Roo.log("our code?");
64073 //Roo.log(success);
64074 //Roo.log(response)
64075 delete this.activeRequest;
64077 this.fireEvent("loadexception", this, o, response);
64078 o.request.callback.call(o.request.scope, null, o.request.arg, false);
64083 result = o.reader.read(response);
64085 Roo.log("load exception?");
64086 this.fireEvent("loadexception", this, o, response, e);
64087 o.request.callback.call(o.request.scope, null, o.request.arg, false);
64090 Roo.log("ready...");
64091 // loop through result.records;
64092 // and set this.tdate[date] = [] << array of records..
64094 Roo.each(result.records, function(r){
64096 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
64097 _this.tdata[r.data.when_dt.format('j')] = [];
64099 _this.tdata[r.data.when_dt.format('j')].push(r.data);
64102 //Roo.log(_this.tdata);
64104 result.records = [];
64105 result.totalRecords = 6;
64107 // let's generate some duumy records for the rows.
64108 //var st = _this.dateField.getValue();
64110 // work out monday..
64111 //st = st.add(Date.DAY, -1 * st.format('w'));
64113 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
64115 var firstOfMonth = date.getFirstDayOfMonth();
64116 var days = date.getDaysInMonth();
64118 var firstAdded = false;
64119 for (var i = 0; i < result.totalRecords ; i++) {
64120 //var d= st.add(Date.DAY, i);
64123 for(var w = 0 ; w < 7 ; w++){
64124 if(!firstAdded && firstOfMonth != w){
64131 var dd = (d > 0 && d < 10) ? "0"+d : d;
64132 row['weekday'+w] = String.format(
64133 '<span style="font-size: 16px;"><b>{0}</b></span>'+
64134 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
64136 date.format('Y-m-')+dd
64139 if(typeof(_this.tdata[d]) != 'undefined'){
64140 Roo.each(_this.tdata[d], function(r){
64144 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
64145 if(r.parent_id*1>0){
64146 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
64149 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
64150 deactive = 'de-act-link';
64153 row['weekday'+w] += String.format(
64154 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
64156 r.product_id_name, //1
64157 r.when_dt.format('h:ia'), //2
64167 // only do this if something added..
64169 result.records.push(_this.grid.dataSource.reader.newRow(row));
64173 // push it twice. (second one with an hour..
64177 this.fireEvent("load", this, o, o.request.arg);
64178 o.request.callback.call(o.request.scope, result, o.request.arg, true);
64180 sortInfo : {field: 'when_dt', direction : 'ASC' },
64182 xtype: 'HttpProxy',
64185 url : baseURL + '/Roo/Shop_course.php'
64188 xtype: 'JsonReader',
64205 'name': 'parent_id',
64209 'name': 'product_id',
64213 'name': 'productitem_id',
64231 click : function (_self, e)
64233 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
64234 sd.setMonth(sd.getMonth()-1);
64235 _this.monthField.setValue(sd.format('Y-m-d'));
64236 _this.grid.ds.load({});
64242 xtype: 'Separator',
64246 xtype: 'MonthField',
64249 render : function (_self)
64251 _this.monthField = _self;
64252 // _this.monthField.set today
64254 select : function (combo, date)
64256 _this.grid.ds.load({});
64259 value : (function() { return new Date(); })()
64262 xtype: 'Separator',
64268 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
64278 click : function (_self, e)
64280 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
64281 sd.setMonth(sd.getMonth()+1);
64282 _this.monthField.setValue(sd.format('Y-m-d'));
64283 _this.grid.ds.load({});
64296 * Ext JS Library 1.1.1
64297 * Copyright(c) 2006-2007, Ext JS, LLC.
64299 * Originally Released Under LGPL - original licence link has changed is not relivant.
64302 * <script type="text/javascript">
64306 * @class Roo.LoadMask
64307 * A simple utility class for generically masking elements while loading data. If the element being masked has
64308 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
64309 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
64310 * element's UpdateManager load indicator and will be destroyed after the initial load.
64312 * Create a new LoadMask
64313 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
64314 * @param {Object} config The config object
64316 Roo.LoadMask = function(el, config){
64317 this.el = Roo.get(el);
64318 Roo.apply(this, config);
64320 this.store.on('beforeload', this.onBeforeLoad, this);
64321 this.store.on('load', this.onLoad, this);
64322 this.store.on('loadexception', this.onLoadException, this);
64323 this.removeMask = false;
64325 var um = this.el.getUpdateManager();
64326 um.showLoadIndicator = false; // disable the default indicator
64327 um.on('beforeupdate', this.onBeforeLoad, this);
64328 um.on('update', this.onLoad, this);
64329 um.on('failure', this.onLoad, this);
64330 this.removeMask = true;
64334 Roo.LoadMask.prototype = {
64336 * @cfg {Boolean} removeMask
64337 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
64338 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
64340 removeMask : false,
64342 * @cfg {String} msg
64343 * The text to display in a centered loading message box (defaults to 'Loading...')
64345 msg : 'Loading...',
64347 * @cfg {String} msgCls
64348 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
64350 msgCls : 'x-mask-loading',
64353 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
64359 * Disables the mask to prevent it from being displayed
64361 disable : function(){
64362 this.disabled = true;
64366 * Enables the mask so that it can be displayed
64368 enable : function(){
64369 this.disabled = false;
64372 onLoadException : function()
64374 Roo.log(arguments);
64376 if (typeof(arguments[3]) != 'undefined') {
64377 Roo.MessageBox.alert("Error loading",arguments[3]);
64381 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
64382 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
64389 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
64392 onLoad : function()
64394 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
64398 onBeforeLoad : function(){
64399 if(!this.disabled){
64400 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
64405 destroy : function(){
64407 this.store.un('beforeload', this.onBeforeLoad, this);
64408 this.store.un('load', this.onLoad, this);
64409 this.store.un('loadexception', this.onLoadException, this);
64411 var um = this.el.getUpdateManager();
64412 um.un('beforeupdate', this.onBeforeLoad, this);
64413 um.un('update', this.onLoad, this);
64414 um.un('failure', this.onLoad, this);
64419 * Ext JS Library 1.1.1
64420 * Copyright(c) 2006-2007, Ext JS, LLC.
64422 * Originally Released Under LGPL - original licence link has changed is not relivant.
64425 * <script type="text/javascript">
64430 * @class Roo.XTemplate
64431 * @extends Roo.Template
64432 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
64434 var t = new Roo.XTemplate(
64435 '<select name="{name}">',
64436 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
64440 // then append, applying the master template values
64443 * Supported features:
64448 {a_variable} - output encoded.
64449 {a_variable.format:("Y-m-d")} - call a method on the variable
64450 {a_variable:raw} - unencoded output
64451 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
64452 {a_variable:this.method_on_template(...)} - call a method on the template object.
64457 <tpl for="a_variable or condition.."></tpl>
64458 <tpl if="a_variable or condition"></tpl>
64459 <tpl exec="some javascript"></tpl>
64460 <tpl name="named_template"></tpl> (experimental)
64462 <tpl for="."></tpl> - just iterate the property..
64463 <tpl for=".."></tpl> - iterates with the parent (probably the template)
64467 Roo.XTemplate = function()
64469 Roo.XTemplate.superclass.constructor.apply(this, arguments);
64476 Roo.extend(Roo.XTemplate, Roo.Template, {
64479 * The various sub templates
64484 * basic tag replacing syntax
64487 * // you can fake an object call by doing this
64491 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
64494 * compile the template
64496 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
64499 compile: function()
64503 s = ['<tpl>', s, '</tpl>'].join('');
64505 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
64506 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
64507 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
64508 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
64509 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
64514 while(true == !!(m = s.match(re))){
64515 var forMatch = m[0].match(nameRe),
64516 ifMatch = m[0].match(ifRe),
64517 execMatch = m[0].match(execRe),
64518 namedMatch = m[0].match(namedRe),
64523 name = forMatch && forMatch[1] ? forMatch[1] : '';
64526 // if - puts fn into test..
64527 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
64529 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
64534 // exec - calls a function... returns empty if true is returned.
64535 exp = execMatch && execMatch[1] ? execMatch[1] : null;
64537 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
64545 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
64546 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
64547 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
64550 var uid = namedMatch ? namedMatch[1] : id;
64554 id: namedMatch ? namedMatch[1] : id,
64561 s = s.replace(m[0], '');
64563 s = s.replace(m[0], '{xtpl'+ id + '}');
64568 for(var i = tpls.length-1; i >= 0; --i){
64569 this.compileTpl(tpls[i]);
64570 this.tpls[tpls[i].id] = tpls[i];
64572 this.master = tpls[tpls.length-1];
64576 * same as applyTemplate, except it's done to one of the subTemplates
64577 * when using named templates, you can do:
64579 * var str = pl.applySubTemplate('your-name', values);
64582 * @param {Number} id of the template
64583 * @param {Object} values to apply to template
64584 * @param {Object} parent (normaly the instance of this object)
64586 applySubTemplate : function(id, values, parent)
64590 var t = this.tpls[id];
64594 if(t.test && !t.test.call(this, values, parent)){
64598 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
64599 Roo.log(e.toString());
64605 if(t.exec && t.exec.call(this, values, parent)){
64609 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
64610 Roo.log(e.toString());
64615 var vs = t.target ? t.target.call(this, values, parent) : values;
64616 parent = t.target ? values : parent;
64617 if(t.target && vs instanceof Array){
64619 for(var i = 0, len = vs.length; i < len; i++){
64620 buf[buf.length] = t.compiled.call(this, vs[i], parent);
64622 return buf.join('');
64624 return t.compiled.call(this, vs, parent);
64626 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
64627 Roo.log(e.toString());
64628 Roo.log(t.compiled);
64633 compileTpl : function(tpl)
64635 var fm = Roo.util.Format;
64636 var useF = this.disableFormats !== true;
64637 var sep = Roo.isGecko ? "+" : ",";
64638 var undef = function(str) {
64639 Roo.log("Property not found :" + str);
64643 var fn = function(m, name, format, args)
64645 //Roo.log(arguments);
64646 args = args ? args.replace(/\\'/g,"'") : args;
64647 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
64648 if (typeof(format) == 'undefined') {
64649 format= 'htmlEncode';
64651 if (format == 'raw' ) {
64655 if(name.substr(0, 4) == 'xtpl'){
64656 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
64659 // build an array of options to determine if value is undefined..
64661 // basically get 'xxxx.yyyy' then do
64662 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
64663 // (function () { Roo.log("Property not found"); return ''; })() :
64668 Roo.each(name.split('.'), function(st) {
64669 lookfor += (lookfor.length ? '.': '') + st;
64670 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
64673 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
64676 if(format && useF){
64678 args = args ? ',' + args : "";
64680 if(format.substr(0, 5) != "this."){
64681 format = "fm." + format + '(';
64683 format = 'this.call("'+ format.substr(5) + '", ';
64687 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
64691 // called with xxyx.yuu:(test,test)
64693 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
64695 // raw.. - :raw modifier..
64696 return "'"+ sep + udef_st + name + ")"+sep+"'";
64700 // branched to use + in gecko and [].join() in others
64702 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
64703 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
64706 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
64707 body.push(tpl.body.replace(/(\r\n|\n)/g,
64708 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
64709 body.push("'].join('');};};");
64710 body = body.join('');
64713 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
64715 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
64721 applyTemplate : function(values){
64722 return this.master.compiled.call(this, values, {});
64723 //var s = this.subs;
64726 apply : function(){
64727 return this.applyTemplate.apply(this, arguments);
64732 Roo.XTemplate.from = function(el){
64733 el = Roo.getDom(el);
64734 return new Roo.XTemplate(el.value || el.innerHTML);