ext-all-debug.js
资源名称:ext-3.0.0.zip [点击查看]
上传用户:shuoshiled
上传日期:2018-01-28
资源大小:10124k
文件大小:2341k
源码类别:
中间件编程
开发平台:
JavaScript
- * @param {Number} v The number to format.
- * @param {String} format The way you would like to format this text.
- * @return {String} The formatted number.
- */
- number: function(v, format) {
- if(!format){
- return v;
- }
- v = Ext.num(v, NaN);
- if (isNaN(v)){
- return '';
- }
- var comma = ',',
- dec = '.',
- i18n = false,
- neg = v < 0;
- v = Math.abs(v);
- if(format.substr(format.length - 2) == '/i'){
- format = format.substr(0, format.length - 2);
- i18n = true;
- comma = '.';
- dec = ',';
- }
- var hasComma = format.indexOf(comma) != -1,
- psplit = (i18n ? format.replace(/[^d,]/g, '') : format.replace(/[^d.]/g, '')).split(dec);
- if(1 < psplit.length){
- v = v.toFixed(psplit[1].length);
- }else if(2 < psplit.length){
- throw ('NumberFormatException: invalid format, formats should have no more than 1 period: ' + format);
- }else{
- v = v.toFixed(0);
- }
- var fnum = v.toString();
- if(hasComma){
- psplit = fnum.split('.');
- var cnum = psplit[0], parr = [], j = cnum.length, m = Math.floor(j / 3), n = cnum.length % 3 || 3;
- for(var i = 0; i < j; i += n){
- if(i != 0){
- n = 3;
- }
- parr[parr.length] = cnum.substr(i, n);
- m -= 1;
- }
- fnum = parr.join(comma);
- if(psplit[1]){
- fnum += dec + psplit[1];
- }
- }
- return (neg ? '-' : '') + format.replace(/[d,?.?]+/, fnum);
- },
- /**
- * Returns a number rendering function that can be reused to apply a number format multiple times efficiently
- * @param {String} format Any valid number format string for {@link #number}
- * @return {Function} The number formatting function
- */
- numberRenderer : function(format){
- return function(v){
- return Ext.util.Format.number(v, format);
- };
- },
- /**
- * Selectively do a plural form of a word based on a numeric value. For example, in a template,
- * {commentCount:plural("Comment")} would result in "1 Comment" if commentCount was 1 or would be "x Comments"
- * if the value is 0 or greater than 1.
- * @param {Number} value The value to compare against
- * @param {String} singular The singular form of the word
- * @param {String} plural (optional) The plural form of the word (defaults to the singular with an "s")
- */
- plural : function(v, s, p){
- return v +' ' + (v == 1 ? s : (p ? p : s+'s'));
- },
- /**
- * Converts newline characters to the HTML tag <br/>
- * @param {String} The string value to format.
- * @return {String} The string with embedded <br/> tags in place of newlines.
- */
- nl2br : function(v){
- return v === undefined || v === null ? '' : v.replace(/n/g, '<br/>');
- }
- }
- }();/** * @class Ext.XTemplate * @extends Ext.Template * <p>A template class that supports advanced functionality like autofilling arrays, conditional processing with * basic comparison operators, sub-templates, basic math function support, special built-in template variables, * inline code execution and more. XTemplate also provides the templating mechanism built into {@link Ext.DataView}.</p> * <p>XTemplate supports many special tags and built-in operators that aren't defined as part of the API, but are * supported in the templates that can be created. The following examples demonstrate all of the supported features. * This is the data object used for reference in each code example:</p> * <pre><code> var data = { name: 'Jack Slocum', title: 'Lead Developer', company: 'Ext JS, LLC', email: 'jack@extjs.com', address: '4 Red Bulls Drive', city: 'Cleveland', state: 'Ohio', zip: '44102', drinks: ['Red Bull', 'Coffee', 'Water'], kids: [{ name: 'Sara Grace', age:3 },{ name: 'Zachary', age:2 },{ name: 'John James', age:0 }] }; * </code></pre> * <p><b>Auto filling of arrays</b><br/>The <tt>tpl</tt> tag and the <tt>for</tt> operator are used * to process the provided data object. If <tt>for="."</tt> is specified, the data object provided * is examined. If the variable in <tt>for</tt> is an array, it will auto-fill, repeating the template * block inside the <tt>tpl</tt> tag for each item in the array:</p> * <pre><code> var tpl = new Ext.XTemplate( '<p>Kids: ', '<tpl for=".">', '<p>{name}</p>', '</tpl></p>' ); tpl.overwrite(panel.body, data.kids); // pass the kids property of the data object * </code></pre> * <p><b>Scope switching</b><br/>The <tt>for</tt> property can be leveraged to access specified members * of the provided data object to populate the template:</p> * <pre><code> var tpl = new Ext.XTemplate( '<p>Name: {name}</p>', '<p>Title: {title}</p>', '<p>Company: {company}</p>', '<p>Kids: ', '<tpl <b>for="kids"</b>>', // interrogate the kids property within the data '<p>{name}</p>', '</tpl></p>' ); tpl.overwrite(panel.body, data); * </code></pre> * <p><b>Access to parent object from within sub-template scope</b><br/>When processing a sub-template, for example while * looping through a child array, you can access the parent object's members via the <tt>parent</tt> object:</p> * <pre><code> var tpl = new Ext.XTemplate( '<p>Name: {name}</p>', '<p>Kids: ', '<tpl for="kids">', '<tpl if="age &gt; 1">', // <-- Note that the > is encoded '<p>{name}</p>', '<p>Dad: {parent.name}</p>', '</tpl>', '</tpl></p>' ); tpl.overwrite(panel.body, data); </code></pre> * <p><b>Array item index and basic math support</b> <br/>While processing an array, the special variable <tt>{#}</tt> * will provide the current array index + 1 (starts at 1, not 0). Templates also support the basic math operators * + - * and / that can be applied directly on numeric data values:</p> * <pre><code> var tpl = new Ext.XTemplate( '<p>Name: {name}</p>', '<p>Kids: ', '<tpl for="kids">', '<tpl if="age &gt; 1">', // <-- Note that the > is encoded '<p>{#}: {name}</p>', // <-- Auto-number each item '<p>In 5 Years: {age+5}</p>', // <-- Basic math '<p>Dad: {parent.name}</p>', '</tpl>', '</tpl></p>' ); tpl.overwrite(panel.body, data); </code></pre> * <p><b>Auto-rendering of flat arrays</b> <br/>Flat arrays that contain values (and not objects) can be auto-rendered * using the special <tt>{.}</tt> variable inside a loop. This variable will represent the value of * the array at the current index:</p> * <pre><code> var tpl = new Ext.XTemplate( '<p>{name}'s favorite beverages:</p>', '<tpl for="drinks">', '<div> - {.}</div>', '</tpl>' ); tpl.overwrite(panel.body, data); </code></pre> * <p><b>Basic conditional logic</b> <br/>Using the <tt>tpl</tt> tag and the <tt>if</tt> * operator you can provide conditional checks for deciding whether or not to render specific parts of the template. * Note that there is no <tt>else</tt> operator — if needed, you should use two opposite <tt>if</tt> statements. * Properly-encoded attributes are required as seen in the following example:</p> * <pre><code> var tpl = new Ext.XTemplate( '<p>Name: {name}</p>', '<p>Kids: ', '<tpl for="kids">', '<tpl if="age &gt; 1">', // <-- Note that the > is encoded '<p>{name}</p>', '</tpl>', '</tpl></p>' ); tpl.overwrite(panel.body, data); </code></pre> * <p><b>Ability to execute arbitrary inline code</b> <br/>In an XTemplate, anything between {[ ... ]} is considered * code to be executed in the scope of the template. There are some special variables available in that code: * <ul> * <li><b><tt>values</tt></b>: The values in the current scope. If you are using scope changing sub-templates, you * can change what <tt>values</tt> is.</li> * <li><b><tt>parent</tt></b>: The scope (values) of the ancestor template.</li> * <li><b><tt>xindex</tt></b>: If you are in a looping template, the index of the loop you are in (1-based).</li> * <li><b><tt>xcount</tt></b>: If you are in a looping template, the total length of the array you are looping.</li> * <li><b><tt>fm</tt></b>: An alias for <tt>Ext.util.Format</tt>.</li> * </ul> * This example demonstrates basic row striping using an inline code block and the <tt>xindex</tt> variable:</p> * <pre><code> var tpl = new Ext.XTemplate( '<p>Name: {name}</p>', '<p>Company: {[values.company.toUpperCase() + ", " + values.title]}</p>', '<p>Kids: ', '<tpl for="kids">', '<div class="{[xindex % 2 === 0 ? "even" : "odd"]}">', '{name}', '</div>', '</tpl></p>' ); tpl.overwrite(panel.body, data); </code></pre> * <p><b>Template member functions</b> <br/>One or more member functions can be defined directly on the config * object passed into the XTemplate constructor for more complex processing:</p> * <pre><code> var tpl = new Ext.XTemplate( '<p>Name: {name}</p>', '<p>Kids: ', '<tpl for="kids">', '<tpl if="this.isGirl(name)">', '<p>Girl: {name} - {age}</p>', '</tpl>', '<tpl if="this.isGirl(name) == false">', '<p>Boy: {name} - {age}</p>', '</tpl>', '<tpl if="this.isBaby(age)">', '<p>{name} is a baby!</p>', '</tpl>', '</tpl></p>', { isGirl: function(name){ return name == 'Sara Grace'; }, isBaby: function(age){ return age < 1; } }); tpl.overwrite(panel.body, data); </code></pre> * @constructor * @param {String/Array/Object} parts The HTML fragment or an array of fragments to join(""), or multiple arguments * to join("") that can also include a config object */ Ext.XTemplate = function(){ Ext.XTemplate.superclass.constructor.apply(this, arguments); var me = this, s = me.html, re = /<tplb[^>]*>((?:(?=([^<]+))2|<(?!tplb[^>]*>))*?)</tpl>/, nameRe = /^<tplb[^>]*?for="(.*?)"/, ifRe = /^<tplb[^>]*?if="(.*?)"/, execRe = /^<tplb[^>]*?exec="(.*?)"/, m, id = 0, tpls = [], VALUES = 'values', PARENT = 'parent', XINDEX = 'xindex', XCOUNT = 'xcount', RETURN = 'return ', WITHVALUES = 'with(values){ '; s = ['<tpl>', s, '</tpl>'].join(''); while((m = s.match(re))){ var m2 = m[0].match(nameRe), m3 = m[0].match(ifRe), m4 = m[0].match(execRe), exp = null, fn = null, exec = null, name = m2 && m2[1] ? m2[1] : ''; if (m3) { exp = m3 && m3[1] ? m3[1] : null; if(exp){ fn = new Function(VALUES, PARENT, XINDEX, XCOUNT, WITHVALUES + RETURN +(Ext.util.Format.htmlDecode(exp))+'; }'); } } if (m4) { exp = m4 && m4[1] ? m4[1] : null; if(exp){ exec = new Function(VALUES, PARENT, XINDEX, XCOUNT, WITHVALUES +(Ext.util.Format.htmlDecode(exp))+'; }'); } } if(name){ switch(name){ case '.': name = new Function(VALUES, PARENT, WITHVALUES + RETURN + VALUES + '; }'); break; case '..': name = new Function(VALUES, PARENT, WITHVALUES + RETURN + PARENT + '; }'); break; default: name = new Function(VALUES, PARENT, WITHVALUES + RETURN + name + '; }'); } } tpls.push({ id: id, target: name, exec: exec, test: fn, body: m[1]||'' }); s = s.replace(m[0], '{xtpl'+ id + '}'); ++id; } Ext.each(tpls, function(t) { me.compileTpl(t); }); me.master = tpls[tpls.length-1]; me.tpls = tpls; }; Ext.extend(Ext.XTemplate, Ext.Template, { // private re : /{([w-.#]+)(?::([w.]*)(?:((.*?)?))?)?(s?[+-*\]s?[d.+-*\()]+)?}/g, // private codeRe : /{[((?:\]|.|n)*?)]}/g, // private applySubTemplate : function(id, values, parent, xindex, xcount){ var me = this, len, t = me.tpls[id], vs, buf = []; if ((t.test && !t.test.call(me, values, parent, xindex, xcount)) || (t.exec && t.exec.call(me, values, parent, xindex, xcount))) { return ''; } vs = t.target ? t.target.call(me, values, parent) : values; len = vs.length; parent = t.target ? values : parent; if(t.target && Ext.isArray(vs)){ Ext.each(vs, function(v, i) { buf[buf.length] = t.compiled.call(me, v, parent, i+1, len); }); return buf.join(''); } return t.compiled.call(me, vs, parent, xindex, xcount); }, // private compileTpl : function(tpl){ var fm = Ext.util.Format, useF = this.disableFormats !== true, sep = Ext.isGecko ? "+" : ",", body; function fn(m, name, format, args, math){ if(name.substr(0, 4) == 'xtpl'){ return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent, xindex, xcount)'+sep+"'"; } var v; if(name === '.'){ v = 'values'; }else if(name === '#'){ v = 'xindex'; }else if(name.indexOf('.') != -1){ v = name; }else{ v = "values['" + name + "']"; } if(math){ v = '(' + v + math + ')'; } if (format && useF) { args = args ? ',' + args : ""; if(format.substr(0, 5) != "this."){ format = "fm." + format + '('; }else{ format = 'this.call("'+ format.substr(5) + '", '; args = ", values"; } } else { args= ''; format = "("+v+" === undefined ? '' : "; } return "'"+ sep + format + v + args + ")"+sep+"'"; } function codeFn(m, code){ return "'"+ sep +'('+code+')'+sep+"'"; } // branched to use + in gecko and [].join() in others if(Ext.isGecko){ body = "tpl.compiled = function(values, parent, xindex, xcount){ return '" + tpl.body.replace(/(rn|n)/g, '\n').replace(/'/g, "\'").replace(this.re, fn).replace(this.codeRe, codeFn) + "';};"; }else{ body = ["tpl.compiled = function(values, parent, xindex, xcount){ return ['"]; body.push(tpl.body.replace(/(rn|n)/g, '\n').replace(/'/g, "\'").replace(this.re, fn).replace(this.codeRe, codeFn)); body.push("'].join('');};"); body = body.join(''); } eval(body); return this; }, /** * Returns an HTML fragment of this template with the specified values applied. * @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'}) * @return {String} The HTML fragment */ applyTemplate : function(values){ return this.master.compiled.call(this, values, {}, 1, 1); }, /** * Compile the template to a function for optimized performance. Recommended if the template will be used frequently. * @return {Function} The compiled function */ compile : function(){return this;} /** * @property re * @hide */ /** * @property disableFormats * @hide */ /** * @method set * @hide */ }); /** * Alias for {@link #applyTemplate} * Returns an HTML fragment of this template with the specified values applied. * @param {Object/Array} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'}) * @return {String} The HTML fragment * @member Ext.XTemplate * @method apply */ Ext.XTemplate.prototype.apply = Ext.XTemplate.prototype.applyTemplate; /** * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML. * @param {String/HTMLElement} el A DOM element or its id * @return {Ext.Template} The created template * @static */ Ext.XTemplate.from = function(el){ el = Ext.getDom(el); return new Ext.XTemplate(el.value || el.innerHTML); };/**
- * @class Ext.util.CSS
- * Utility class for manipulating CSS rules
- * @singleton
- */
- Ext.util.CSS = function(){
- var rules = null;
- var doc = document;
- var camelRe = /(-[a-z])/gi;
- var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
- return {
- /**
- * Creates a stylesheet from a text blob of rules.
- * These rules will be wrapped in a STYLE tag and appended to the HEAD of the document.
- * @param {String} cssText The text containing the css rules
- * @param {String} id An id to add to the stylesheet for later removal
- * @return {StyleSheet}
- */
- createStyleSheet : function(cssText, id){
- var ss;
- var head = doc.getElementsByTagName("head")[0];
- var rules = doc.createElement("style");
- rules.setAttribute("type", "text/css");
- if(id){
- rules.setAttribute("id", id);
- }
- if(Ext.isIE){
- head.appendChild(rules);
- ss = rules.styleSheet;
- ss.cssText = cssText;
- }else{
- try{
- rules.appendChild(doc.createTextNode(cssText));
- }catch(e){
- rules.cssText = cssText;
- }
- head.appendChild(rules);
- ss = rules.styleSheet ? rules.styleSheet : (rules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
- }
- this.cacheStyleSheet(ss);
- return ss;
- },
- /**
- * Removes a style or link tag by id
- * @param {String} id The id of the tag
- */
- removeStyleSheet : function(id){
- var existing = doc.getElementById(id);
- if(existing){
- existing.parentNode.removeChild(existing);
- }
- },
- /**
- * Dynamically swaps an existing stylesheet reference for a new one
- * @param {String} id The id of an existing link tag to remove
- * @param {String} url The href of the new stylesheet to include
- */
- swapStyleSheet : function(id, url){
- this.removeStyleSheet(id);
- var ss = doc.createElement("link");
- ss.setAttribute("rel", "stylesheet");
- ss.setAttribute("type", "text/css");
- ss.setAttribute("id", id);
- ss.setAttribute("href", url);
- doc.getElementsByTagName("head")[0].appendChild(ss);
- },
- /**
- * Refresh the rule cache if you have dynamically added stylesheets
- * @return {Object} An object (hash) of rules indexed by selector
- */
- refreshCache : function(){
- return this.getRules(true);
- },
- // private
- cacheStyleSheet : function(ss){
- if(!rules){
- rules = {};
- }
- try{// try catch for cross domain access issue
- var ssRules = ss.cssRules || ss.rules;
- for(var j = ssRules.length-1; j >= 0; --j){
- rules[ssRules[j].selectorText] = ssRules[j];
- }
- }catch(e){}
- },
- /**
- * Gets all css rules for the document
- * @param {Boolean} refreshCache true to refresh the internal cache
- * @return {Object} An object (hash) of rules indexed by selector
- */
- getRules : function(refreshCache){
- if(rules === null || refreshCache){
- rules = {};
- var ds = doc.styleSheets;
- for(var i =0, len = ds.length; i < len; i++){
- try{
- this.cacheStyleSheet(ds[i]);
- }catch(e){}
- }
- }
- return rules;
- },
- /**
- * Gets an an individual CSS rule by selector(s)
- * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
- * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
- * @return {CSSRule} The CSS rule or null if one is not found
- */
- getRule : function(selector, refreshCache){
- var rs = this.getRules(refreshCache);
- if(!Ext.isArray(selector)){
- return rs[selector];
- }
- for(var i = 0; i < selector.length; i++){
- if(rs[selector[i]]){
- return rs[selector[i]];
- }
- }
- return null;
- },
- /**
- * Updates a rule property
- * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
- * @param {String} property The css property
- * @param {String} value The new value for the property
- * @return {Boolean} true If a rule was found and updated
- */
- updateRule : function(selector, property, value){
- if(!Ext.isArray(selector)){
- var rule = this.getRule(selector);
- if(rule){
- rule.style[property.replace(camelRe, camelFn)] = value;
- return true;
- }
- }else{
- for(var i = 0; i < selector.length; i++){
- if(this.updateRule(selector[i], property, value)){
- return true;
- }
- }
- }
- return false;
- }
- };
- }();/** @class Ext.util.ClickRepeater @extends Ext.util.Observable A wrapper class which can be applied to any element. Fires a "click" event while the mouse is pressed. The interval between firings may be specified in the config but defaults to 20 milliseconds. Optionally, a CSS class may be applied to the element during the time it is pressed. @cfg {Mixed} el The element to act as a button. @cfg {Number} delay The initial delay before the repeating event begins firing. Similar to an autorepeat key delay. @cfg {Number} interval The interval between firings of the "click" event. Default 20 ms. @cfg {String} pressClass A CSS class name to be applied to the element while pressed. @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate. "interval" and "delay" are ignored. @cfg {Boolean} preventDefault True to prevent the default click event @cfg {Boolean} stopDefault True to stop the default click event @history 2007-02-02 jvs Original code contributed by Nige "Animal" White 2007-02-02 jvs Renamed to ClickRepeater 2007-02-03 jvs Modifications for FF Mac and Safari @constructor @param {Mixed} el The element to listen on @param {Object} config */ Ext.util.ClickRepeater = function(el, config) { this.el = Ext.get(el); this.el.unselectable(); Ext.apply(this, config); this.addEvents( /** * @event mousedown * Fires when the mouse button is depressed. * @param {Ext.util.ClickRepeater} this */ "mousedown", /** * @event click * Fires on a specified interval during the time the element is pressed. * @param {Ext.util.ClickRepeater} this */ "click", /** * @event mouseup * Fires when the mouse key is released. * @param {Ext.util.ClickRepeater} this */ "mouseup" ); if(!this.disabled){ this.disabled = true; this.enable(); } // allow inline handler if(this.handler){ this.on("click", this.handler, this.scope || this); } Ext.util.ClickRepeater.superclass.constructor.call(this); }; Ext.extend(Ext.util.ClickRepeater, Ext.util.Observable, { interval : 20, delay: 250, preventDefault : true, stopDefault : false, timer : 0, /** * Enables the repeater and allows events to fire. */ enable: function(){ if(this.disabled){ this.el.on('mousedown', this.handleMouseDown, this); if(this.preventDefault || this.stopDefault){ this.el.on('click', this.eventOptions, this); } } this.disabled = false; }, /** * Disables the repeater and stops events from firing. */ disable: function(/* private */ force){ if(force || !this.disabled){ clearTimeout(this.timer); if(this.pressClass){ this.el.removeClass(this.pressClass); } Ext.getDoc().un('mouseup', this.handleMouseUp, this); this.el.removeAllListeners(); } this.disabled = true; }, /** * Convenience function for setting disabled/enabled by boolean. * @param {Boolean} disabled */ setDisabled: function(disabled){ this[disabled ? 'disable' : 'enable'](); }, eventOptions: function(e){ if(this.preventDefault){ e.preventDefault(); } if(this.stopDefault){ e.stopEvent(); } }, // private destroy : function() { this.disable(true); Ext.destroy(this.el); this.purgeListeners(); }, // private handleMouseDown : function(){ clearTimeout(this.timer); this.el.blur(); if(this.pressClass){ this.el.addClass(this.pressClass); } this.mousedownTime = new Date(); Ext.getDoc().on("mouseup", this.handleMouseUp, this); this.el.on("mouseout", this.handleMouseOut, this); this.fireEvent("mousedown", this); this.fireEvent("click", this); // Do not honor delay or interval if acceleration wanted. if (this.accelerate) { this.delay = 400; } this.timer = this.click.defer(this.delay || this.interval, this); }, // private click : function(){ this.fireEvent("click", this); this.timer = this.click.defer(this.accelerate ? this.easeOutExpo(this.mousedownTime.getElapsed(), 400, -390, 12000) : this.interval, this); }, easeOutExpo : function (t, b, c, d) { return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; }, // private handleMouseOut : function(){ clearTimeout(this.timer); if(this.pressClass){ this.el.removeClass(this.pressClass); } this.el.on("mouseover", this.handleMouseReturn, this); }, // private handleMouseReturn : function(){ this.el.un("mouseover", this.handleMouseReturn, this); if(this.pressClass){ this.el.addClass(this.pressClass); } this.click(); }, // private handleMouseUp : function(){ clearTimeout(this.timer); this.el.un("mouseover", this.handleMouseReturn, this); this.el.un("mouseout", this.handleMouseOut, this); Ext.getDoc().un("mouseup", this.handleMouseUp, this); this.el.removeClass(this.pressClass); this.fireEvent("mouseup", this); } });/** * @class Ext.KeyNav * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind * navigation keys to function calls that will get called when the keys are pressed, providing an easy * way to implement custom navigation schemes for any UI component.</p> * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc, * pageUp, pageDown, del, home, end. Usage:</p> <pre><code> var nav = new Ext.KeyNav("my-element", { "left" : function(e){ this.moveLeft(e.ctrlKey); }, "right" : function(e){ this.moveRight(e.ctrlKey); }, "enter" : function(e){ this.save(); }, scope : this }); </code></pre> * @constructor * @param {Mixed} el The element to bind to * @param {Object} config The config */ Ext.KeyNav = function(el, config){ this.el = Ext.get(el); Ext.apply(this, config); if(!this.disabled){ this.disabled = true; this.enable(); } }; Ext.KeyNav.prototype = { /** * @cfg {Boolean} disabled * True to disable this KeyNav instance (defaults to false) */ disabled : false, /** * @cfg {String} defaultEventAction * The method to call on the {@link Ext.EventObject} after this KeyNav intercepts a key. Valid values are * {@link Ext.EventObject#stopEvent}, {@link Ext.EventObject#preventDefault} and * {@link Ext.EventObject#stopPropagation} (defaults to 'stopEvent') */ defaultEventAction: "stopEvent", /** * @cfg {Boolean} forceKeyDown * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also * handle keydown instead of keypress. */ forceKeyDown : false, // private prepareEvent : function(e){ var k = e.getKey(); var h = this.keyToHandler[k]; if(Ext.isSafari2 && h && k >= 37 && k <= 40){ e.stopEvent(); } }, // private relay : function(e){ var k = e.getKey(); var h = this.keyToHandler[k]; if(h && this[h]){ if(this.doRelay(e, this[h], h) !== true){ e[this.defaultEventAction](); } } }, // private doRelay : function(e, h, hname){ return h.call(this.scope || this, e); }, // possible handlers enter : false, left : false, right : false, up : false, down : false, tab : false, esc : false, pageUp : false, pageDown : false, del : false, home : false, end : false, // quick lookup hash keyToHandler : { 37 : "left", 39 : "right", 38 : "up", 40 : "down", 33 : "pageUp", 34 : "pageDown", 46 : "del", 36 : "home", 35 : "end", 13 : "enter", 27 : "esc", 9 : "tab" }, /** * Enable this KeyNav */ enable: function(){ if(this.disabled){ // ie won't do special keys on keypress, no one else will repeat keys with keydown // the EventObject will normalize Safari automatically if(this.isKeydown()){ this.el.on("keydown", this.relay, this); }else{ this.el.on("keydown", this.prepareEvent, this); this.el.on("keypress", this.relay, this); } this.disabled = false; } }, /** * Disable this KeyNav */ disable: function(){ if(!this.disabled){ if(this.isKeydown()){ this.el.un("keydown", this.relay, this); }else{ this.el.un("keydown", this.prepareEvent, this); this.el.un("keypress", this.relay, this); } this.disabled = true; } }, /** * Convenience function for setting disabled/enabled by boolean. * @param {Boolean} disabled */ setDisabled : function(disabled){ this[disabled ? "disable" : "enable"](); }, // private isKeydown: function(){ return this.forceKeyDown || Ext.EventManager.useKeydown; } }; /**
- * @class Ext.KeyMap
- * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
- * The constructor accepts the same config object as defined by {@link #addBinding}.
- * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
- * combination it will call the function with this signature (if the match is a multi-key
- * combination the callback will still be called only once): (String key, Ext.EventObject e)
- * A KeyMap can also handle a string representation of keys.<br />
- * Usage:
- <pre><code>
- // map one key by key code
- var map = new Ext.KeyMap("my-element", {
- key: 13, // or Ext.EventObject.ENTER
- fn: myHandler,
- scope: myObject
- });
- // map multiple keys to one action by string
- var map = new Ext.KeyMap("my-element", {
- key: "arnt",
- fn: myHandler,
- scope: myObject
- });
- // map multiple keys to multiple actions by strings and array of codes
- var map = new Ext.KeyMap("my-element", [
- {
- key: [10,13],
- fn: function(){ alert("Return was pressed"); }
- }, {
- key: "abc",
- fn: function(){ alert('a, b or c was pressed'); }
- }, {
- key: "t",
- ctrl:true,
- shift:true,
- fn: function(){ alert('Control + shift + tab was pressed.'); }
- }
- ]);
- </code></pre>
- * <b>Note: A KeyMap starts enabled</b>
- * @constructor
- * @param {Mixed} el The element to bind to
- * @param {Object} config The config (see {@link #addBinding})
- * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
- */
- Ext.KeyMap = function(el, config, eventName){
- this.el = Ext.get(el);
- this.eventName = eventName || "keydown";
- this.bindings = [];
- if(config){
- this.addBinding(config);
- }
- this.enable();
- };
- Ext.KeyMap.prototype = {
- /**
- * True to stop the event from bubbling and prevent the default browser action if the
- * key was handled by the KeyMap (defaults to false)
- * @type Boolean
- */
- stopEvent : false,
- /**
- * Add a new binding to this KeyMap. The following config object properties are supported:
- * <pre>
- Property Type Description
- ---------- --------------- ----------------------------------------------------------------------
- key String/Array A single keycode or an array of keycodes to handle
- shift Boolean True to handle key only when shift is pressed, False to handle the key only when shift is not pressed (defaults to undefined)
- ctrl Boolean True to handle key only when ctrl is pressed, False to handle the key only when ctrl is not pressed (defaults to undefined)
- alt Boolean True to handle key only when alt is pressed, False to handle the key only when alt is not pressed (defaults to undefined)
- handler Function The function to call when KeyMap finds the expected key combination
- fn Function Alias of handler (for backwards-compatibility)
- scope Object The scope of the callback function
- stopEvent Boolean True to stop the event from bubbling and prevent the default browser action if the key was handled by the KeyMap (defaults to false)
- </pre>
- *
- * Usage:
- * <pre><code>
- // Create a KeyMap
- var map = new Ext.KeyMap(document, {
- key: Ext.EventObject.ENTER,
- fn: handleKey,
- scope: this
- });
- //Add a new binding to the existing KeyMap later
- map.addBinding({
- key: 'abc',
- shift: true,
- fn: handleKey,
- scope: this
- });
- </code></pre>
- * @param {Object/Array} config A single KeyMap config or an array of configs
- */
- addBinding : function(config){
- if(Ext.isArray(config)){
- Ext.each(config, function(c){
- this.addBinding(c);
- }, this);
- return;
- }
- var keyCode = config.key,
- fn = config.fn || config.handler,
- scope = config.scope;
- if (config.stopEvent) {
- this.stopEvent = config.stopEvent;
- }
- if(typeof keyCode == "string"){
- var ks = [];
- var keyString = keyCode.toUpperCase();
- for(var j = 0, len = keyString.length; j < len; j++){
- ks.push(keyString.charCodeAt(j));
- }
- keyCode = ks;
- }
- var keyArray = Ext.isArray(keyCode);
- var handler = function(e){
- if(this.checkModifiers(config, e)){
- var k = e.getKey();
- if(keyArray){
- for(var i = 0, len = keyCode.length; i < len; i++){
- if(keyCode[i] == k){
- if(this.stopEvent){
- e.stopEvent();
- }
- fn.call(scope || window, k, e);
- return;
- }
- }
- }else{
- if(k == keyCode){
- if(this.stopEvent){
- e.stopEvent();
- }
- fn.call(scope || window, k, e);
- }
- }
- }
- };
- this.bindings.push(handler);
- },
- // private
- checkModifiers: function(config, e){
- var val, key, keys = ['shift', 'ctrl', 'alt'];
- for (var i = 0, len = keys.length; i < len; ++i){
- key = keys[i];
- val = config[key];
- if(!(val === undefined || (val === e[key + 'Key']))){
- return false;
- }
- }
- return true;
- },
- /**
- * Shorthand for adding a single key listener
- * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
- * following options:
- * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
- * @param {Function} fn The function to call
- * @param {Object} scope (optional) The scope of the function
- */
- on : function(key, fn, scope){
- var keyCode, shift, ctrl, alt;
- if(typeof key == "object" && !Ext.isArray(key)){
- keyCode = key.key;
- shift = key.shift;
- ctrl = key.ctrl;
- alt = key.alt;
- }else{
- keyCode = key;
- }
- this.addBinding({
- key: keyCode,
- shift: shift,
- ctrl: ctrl,
- alt: alt,
- fn: fn,
- scope: scope
- });
- },
- // private
- handleKeyDown : function(e){
- if(this.enabled){ //just in case
- var b = this.bindings;
- for(var i = 0, len = b.length; i < len; i++){
- b[i].call(this, e);
- }
- }
- },
- /**
- * Returns true if this KeyMap is enabled
- * @return {Boolean}
- */
- isEnabled : function(){
- return this.enabled;
- },
- /**
- * Enables this KeyMap
- */
- enable: function(){
- if(!this.enabled){
- this.el.on(this.eventName, this.handleKeyDown, this);
- this.enabled = true;
- }
- },
- /**
- * Disable this KeyMap
- */
- disable: function(){
- if(this.enabled){
- this.el.removeListener(this.eventName, this.handleKeyDown, this);
- this.enabled = false;
- }
- },
- /**
- * Convenience function for setting disabled/enabled by boolean.
- * @param {Boolean} disabled
- */
- setDisabled : function(disabled){
- this[disabled ? "disable" : "enable"]();
- }
- };/** * @class Ext.util.TextMetrics * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and * wide, in pixels, a given block of text will be. Note that when measuring text, it should be plain text and * should not contain any HTML, otherwise it may not be measured correctly. * @singleton */ Ext.util.TextMetrics = function(){ var shared; return { /** * Measures the size of the specified text * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles * that can affect the size of the rendered text * @param {String} text The text to measure * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width * in order to accurately measure the text height * @return {Object} An object containing the text's size {width: (width), height: (height)} */ measure : function(el, text, fixedWidth){ if(!shared){ shared = Ext.util.TextMetrics.Instance(el, fixedWidth); } shared.bind(el); shared.setFixedWidth(fixedWidth || 'auto'); return shared.getSize(text); }, /** * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces * the overhead of multiple calls to initialize the style properties on each measurement. * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width * in order to accurately measure the text height * @return {Ext.util.TextMetrics.Instance} instance The new instance */ createInstance : function(el, fixedWidth){ return Ext.util.TextMetrics.Instance(el, fixedWidth); } }; }(); Ext.util.TextMetrics.Instance = function(bindTo, fixedWidth){ var ml = new Ext.Element(document.createElement('div')); document.body.appendChild(ml.dom); ml.position('absolute'); ml.setLeftTop(-1000, -1000); ml.hide(); if(fixedWidth){ ml.setWidth(fixedWidth); } var instance = { /** * Returns the size of the specified text based on the internal element's style and width properties * @param {String} text The text to measure * @return {Object} An object containing the text's size {width: (width), height: (height)} */ getSize : function(text){ ml.update(text); var s = ml.getSize(); ml.update(''); return s; }, /** * Binds this TextMetrics instance to an element from which to copy existing CSS styles * that can affect the size of the rendered text * @param {String/HTMLElement} el The element, dom node or id */ bind : function(el){ ml.setStyle( Ext.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height', 'text-transform', 'letter-spacing') ); }, /** * Sets a fixed width on the internal measurement element. If the text will be multiline, you have * to set a fixed width in order to accurately measure the text height. * @param {Number} width The width to set on the element */ setFixedWidth : function(width){ ml.setWidth(width); }, /** * Returns the measured width of the specified text * @param {String} text The text to measure * @return {Number} width The width in pixels */ getWidth : function(text){ ml.dom.style.width = 'auto'; return this.getSize(text).width; }, /** * Returns the measured height of the specified text. For multiline text, be sure to call * {@link #setFixedWidth} if necessary. * @param {String} text The text to measure * @return {Number} height The height in pixels */ getHeight : function(text){ return this.getSize(text).height; } }; instance.bind(bindTo); return instance; }; Ext.Element.addMethods({ /** * Returns the width in pixels of the passed text, or the width of the text in this Element. * @param {String} text The text to measure. Defaults to the innerHTML of the element. * @param {Number} min (Optional) The minumum value to return. * @param {Number} max (Optional) The maximum value to return. * @return {Number} The text width in pixels. * @member Ext.Element getTextWidth */ getTextWidth : function(text, min, max){ return (Ext.util.TextMetrics.measure(this.dom, Ext.value(text, this.dom.innerHTML, true)).width).constrain(min || 0, max || 1000000); } }); /**
- * @class Ext.util.Cookies
- * Utility class for managing and interacting with cookies.
- * @singleton
- */
- Ext.util.Cookies = {
- /**
- * Create a cookie with the specified name and value. Additional settings
- * for the cookie may be optionally specified (for example: expiration,
- * access restriction, SSL).
- * @param {Object} name
- * @param {Object} value
- * @param {Object} expires (Optional) Specify an expiration date the
- * cookie is to persist until. Note that the specified Date object will
- * be converted to Greenwich Mean Time (GMT).
- * @param {String} path (Optional) Setting a path on the cookie restricts
- * access to pages that match that path. Defaults to all pages (<tt>'/'</tt>).
- * @param {String} domain (Optional) Setting a domain restricts access to
- * pages on a given domain (typically used to allow cookie access across
- * subdomains). For example, "extjs.com" will create a cookie that can be
- * accessed from any subdomain of extjs.com, including www.extjs.com,
- * support.extjs.com, etc.
- * @param {Boolean} secure (Optional) Specify true to indicate that the cookie
- * should only be accessible via SSL on a page using the HTTPS protocol.
- * Defaults to <tt>false</tt>. Note that this will only work if the page
- * calling this code uses the HTTPS protocol, otherwise the cookie will be
- * created with default options.
- */
- set : function(name, value){
- var argv = arguments;
- var argc = arguments.length;
- var expires = (argc > 2) ? argv[2] : null;
- var path = (argc > 3) ? argv[3] : '/';
- var domain = (argc > 4) ? argv[4] : null;
- var secure = (argc > 5) ? argv[5] : false;
- document.cookie = name + "=" + escape(value) + ((expires === null) ? "" : ("; expires=" + expires.toGMTString())) + ((path === null) ? "" : ("; path=" + path)) + ((domain === null) ? "" : ("; domain=" + domain)) + ((secure === true) ? "; secure" : "");
- },
- /**
- * Retrieves cookies that are accessible by the current page. If a cookie
- * does not exist, <code>get()</code> returns <tt>null</tt>. The following
- * example retrieves the cookie called "valid" and stores the String value
- * in the variable <tt>validStatus</tt>.
- * <pre><code>
- * var validStatus = Ext.util.Cookies.get("valid");
- * </code></pre>
- * @param {Object} name The name of the cookie to get
- * @return {Mixed} Returns the cookie value for the specified name;
- * null if the cookie name does not exist.
- */
- get : function(name){
- var arg = name + "=";
- var alen = arg.length;
- var clen = document.cookie.length;
- var i = 0;
- var j = 0;
- while(i < clen){
- j = i + alen;
- if(document.cookie.substring(i, j) == arg){
- return Ext.util.Cookies.getCookieVal(j);
- }
- i = document.cookie.indexOf(" ", i) + 1;
- if(i === 0){
- break;
- }
- }
- return null;
- },
- /**
- * Removes a cookie with the provided name from the browser
- * if found.
- * @param {Object} name The name of the cookie to remove
- */
- clear : function(name){
- if(Ext.util.Cookies.get(name)){
- document.cookie = name + "=" + "; expires=Thu, 01-Jan-70 00:00:01 GMT";
- }
- },
- /**
- * @private
- */
- getCookieVal : function(offset){
- var endstr = document.cookie.indexOf(";", offset);
- if(endstr == -1){
- endstr = document.cookie.length;
- }
- return unescape(document.cookie.substring(offset, endstr));
- }
- };/** * Framework-wide error-handler. Developers can override this method to provide * custom exception-handling. Framework errors will often extend from the base * Ext.Error class. * @param {Object/Error} e The thrown exception object. */ Ext.handleError = function(e) { throw e; }; /** * @class Ext.Error * @extends Error * <p>A base error class. Future implementations are intended to provide more * robust error handling throughout the framework (<b>in the debug build only</b>) * to check for common errors and problems. The messages issued by this class * will aid error checking. Error checks will be automatically removed in the * production build so that performance is not negatively impacted.</p> * <p>Some sample messages currently implemented:</p><pre> "DataProxy attempted to execute an API-action but found an undefined url / function. Please review your Proxy url/api-configuration." * </pre><pre> "Could not locate your "root" property in your server response. Please review your JsonReader config to ensure the config-property "root" matches the property your server-response. See the JsonReader docs for additional assistance." * </pre> * <p>An example of the code used for generating error messages:</p><pre><code> try { generateError({ foo: 'bar' }); } catch (e) { console.error(e); } function generateError(data) { throw new Ext.Error('foo-error', data); } * </code></pre> * @param {String} message */ Ext.Error = function(message) { // Try to read the message from Ext.Error.lang this.message = (this.lang[message]) ? this.lang[message] : message; } Ext.Error.prototype = new Error(); Ext.apply(Ext.Error.prototype, { // protected. Extensions place their error-strings here. lang: {}, name: 'Ext.Error', /** * getName * @return {String} */ getName : function() { return this.name; }, /** * getMessage * @return {String} */ getMessage : function() { return this.message; }, /** * toJson * @return {String} */ toJson : function() { return Ext.encode(this); } }); /** * @class Ext.ComponentMgr * <p>Provides a registry of all Components (instances of {@link Ext.Component} or any subclass * thereof) on a page so that they can be easily accessed by {@link Ext.Component component} * {@link Ext.Component#id id} (see {@link #get}, or the convenience method {@link Ext#getCmp Ext.getCmp}).</p> * <p>This object also provides a registry of available Component <i>classes</i> * indexed by a mnemonic code known as the Component's {@link Ext.Component#xtype xtype}. * The <tt>{@link Ext.Component#xtype xtype}</tt> provides a way to avoid instantiating child Components * when creating a full, nested config object for a complete Ext page.</p> * <p>A child Component may be specified simply as a <i>config object</i> * as long as the correct <tt>{@link Ext.Component#xtype xtype}</tt> is specified so that if and when the Component * needs rendering, the correct type can be looked up for lazy instantiation.</p> * <p>For a list of all available <tt>{@link Ext.Component#xtype xtypes}</tt>, see {@link Ext.Component}.</p> * @singleton */ Ext.ComponentMgr = function(){ var all = new Ext.util.MixedCollection(); var types = {}; var ptypes = {}; return { /** * Registers a component. * @param {Ext.Component} c The component */ register : function(c){ all.add(c); }, /** * Unregisters a component. * @param {Ext.Component} c The component */ unregister : function(c){ all.remove(c); }, /** * Returns a component by {@link Ext.Component#id id}. * For additional details see {@link Ext.util.MixedCollection#get}. * @param {String} id The component {@link Ext.Component#id id} * @return Ext.Component The Component, <tt>undefined</tt> if not found, or <tt>null</tt> if a * Class was found. */ get : function(id){ return all.get(id); }, /** * Registers a function that will be called when a specified component is added to ComponentMgr * @param {String} id The component {@link Ext.Component#id id} * @param {Function} fn The callback function * @param {Object} scope The scope of the callback */ onAvailable : function(id, fn, scope){ all.on("add", function(index, o){ if(o.id == id){ fn.call(scope || o, o); all.un("add", fn, scope); } }); }, /** * The MixedCollection used internally for the component cache. An example usage may be subscribing to * events on the MixedCollection to monitor addition or removal. Read-only. * @type {MixedCollection} */ all : all, /** * Checks if a Component type is registered. * @param {Ext.Component} xtype The mnemonic string by which the Component class may be looked up * @return {Boolean} Whether the type is registered. */ isRegistered : function(xtype){ return types[xtype] !== undefined; }, /** * <p>Registers a new Component constructor, keyed by a new * {@link Ext.Component#xtype}.</p> * <p>Use this method (or its alias {@link Ext#reg Ext.reg}) to register new * subclasses of {@link Ext.Component} so that lazy instantiation may be used when specifying * child Components. * see {@link Ext.Container#items}</p> * @param {String} xtype The mnemonic string by which the Component class may be looked up. * @param {Constructor} cls The new Component class. */ registerType : function(xtype, cls){ types[xtype] = cls; cls.xtype = xtype; }, /** * Creates a new Component from the specified config object using the * config object's {@link Ext.component#xtype xtype} to determine the class to instantiate. * @param {Object} config A configuration object for the Component you wish to create. * @param {Constructor} defaultType The constructor to provide the default Component type if * the config object does not contain a <tt>xtype</tt>. (Optional if the config contains a <tt>xtype</tt>). * @return {Ext.Component} The newly instantiated Component. */ create : function(config, defaultType){ return config.render ? config : new types[config.xtype || defaultType](config); }, /** * <p>Registers a new Plugin constructor, keyed by a new * {@link Ext.Component#ptype}.</p> * <p>Use this method (or its alias {@link Ext#preg Ext.preg}) to register new * plugins for {@link Ext.Component}s so that lazy instantiation may be used when specifying * Plugins.</p> * @param {String} ptype The mnemonic string by which the Plugin class may be looked up. * @param {Constructor} cls The new Plugin class. */ registerPlugin : function(ptype, cls){ ptypes[ptype] = cls; cls.ptype = ptype; }, /** * Creates a new Plugin from the specified config object using the * config object's {@link Ext.component#ptype ptype} to determine the class to instantiate. * @param {Object} config A configuration object for the Plugin you wish to create. * @param {Constructor} defaultType The constructor to provide the default Plugin type if * the config object does not contain a <tt>ptype</tt>. (Optional if the config contains a <tt>ptype</tt>). * @return {Ext.Component} The newly instantiated Plugin. */ createPlugin : function(config, defaultType){ return new ptypes[config.ptype || defaultType](config); } }; }(); /** * Shorthand for {@link Ext.ComponentMgr#registerType} * @param {String} xtype The {@link Ext.component#xtype mnemonic string} by which the Component class * may be looked up. * @param {Constructor} cls The new Component class. * @member Ext * @method reg */ Ext.reg = Ext.ComponentMgr.registerType; // this will be called a lot internally, shorthand to keep the bytes down /** * Shorthand for {@link Ext.ComponentMgr#registerPlugin} * @param {String} ptype The {@link Ext.component#ptype mnemonic string} by which the Plugin class * may be looked up. * @param {Constructor} cls The new Plugin class. * @member Ext * @method preg */ Ext.preg = Ext.ComponentMgr.registerPlugin; Ext.create = Ext.ComponentMgr.create; /** * @class Ext.Component * @extends Ext.util.Observable * <p>Base class for all Ext components. All subclasses of Component may participate in the automated * Ext component lifecycle of creation, rendering and destruction which is provided by the {@link Ext.Container Container} class. * Components may be added to a Container through the {@link Ext.Container#items items} config option at the time the Container is created, * or they may be added dynamically via the {@link Ext.Container#add add} method.</p> * <p>The Component base class has built-in support for basic hide/show and enable/disable behavior.</p> * <p>All Components are registered with the {@link Ext.ComponentMgr} on construction so that they can be referenced at any time via * {@link Ext#getCmp}, passing the {@link #id}.</p> * <p>All user-developed visual widgets that are required to participate in automated lifecycle and size management should subclass Component (or * {@link Ext.BoxComponent} if managed box model handling is required, ie height and width management).</p> * <p>See the <a href="http://extjs.com/learn/Tutorial:Creating_new_UI_controls">Creating new UI controls</a> tutorial for details on how * and to either extend or augment ExtJs base classes to create custom Components.</p> * <p>Every component has a specific xtype, which is its Ext-specific type name, along with methods for checking the * xtype like {@link #getXType} and {@link #isXType}. This is the list of all valid xtypes:</p> * <pre> xtype Class ------------- ------------------ box {@link Ext.BoxComponent} button {@link Ext.Button} buttongroup {@link Ext.ButtonGroup} colorpalette {@link Ext.ColorPalette} component {@link Ext.Component} container {@link Ext.Container} cycle {@link Ext.CycleButton} dataview {@link Ext.DataView} datepicker {@link Ext.DatePicker} editor {@link Ext.Editor} editorgrid {@link Ext.grid.EditorGridPanel} flash {@link Ext.FlashComponent} grid {@link Ext.grid.GridPanel} listview {@link Ext.ListView} panel {@link Ext.Panel} progress {@link Ext.ProgressBar} propertygrid {@link Ext.grid.PropertyGrid} slider {@link Ext.Slider} spacer {@link Ext.Spacer} splitbutton {@link Ext.SplitButton} tabpanel {@link Ext.TabPanel} treepanel {@link Ext.tree.TreePanel} viewport {@link Ext.ViewPort} window {@link Ext.Window} Toolbar components --------------------------------------- paging {@link Ext.PagingToolbar} toolbar {@link Ext.Toolbar} tbbutton {@link Ext.Toolbar.Button} (deprecated; use button) tbfill {@link Ext.Toolbar.Fill} tbitem {@link Ext.Toolbar.Item} tbseparator {@link Ext.Toolbar.Separator} tbspacer {@link Ext.Toolbar.Spacer} tbsplit {@link Ext.Toolbar.SplitButton} (deprecated; use splitbutton) tbtext {@link Ext.Toolbar.TextItem} Menu components --------------------------------------- menu {@link Ext.menu.Menu} colormenu {@link Ext.menu.ColorMenu} datemenu {@link Ext.menu.DateMenu} menubaseitem {@link Ext.menu.BaseItem} menucheckitem {@link Ext.menu.CheckItem} menuitem {@link Ext.menu.Item} menuseparator {@link Ext.menu.Separator} menutextitem {@link Ext.menu.TextItem} Form components --------------------------------------- form {@link Ext.FormPanel} checkbox {@link Ext.form.Checkbox} checkboxgroup {@link Ext.form.CheckboxGroup} combo {@link Ext.form.ComboBox} datefield {@link Ext.form.DateField} displayfield {@link Ext.form.DisplayField} field {@link Ext.form.Field} fieldset {@link Ext.form.FieldSet} hidden {@link Ext.form.Hidden} htmleditor {@link Ext.form.HtmlEditor} label {@link Ext.form.Label} numberfield {@link Ext.form.NumberField} radio {@link Ext.form.Radio} radiogroup {@link Ext.form.RadioGroup} textarea {@link Ext.form.TextArea} textfield {@link Ext.form.TextField} timefield {@link Ext.form.TimeField} trigger {@link Ext.form.TriggerField} Chart components --------------------------------------- chart {@link Ext.chart.Chart} barchart {@link Ext.chart.BarChart} cartesianchart {@link Ext.chart.CartesianChart} columnchart {@link Ext.chart.ColumnChart} linechart {@link Ext.chart.LineChart} piechart {@link Ext.chart.PieChart} Store xtypes --------------------------------------- arraystore {@link Ext.data.ArrayStore} directstore {@link Ext.data.DirectStore} groupingstore {@link Ext.data.GroupingStore} jsonstore {@link Ext.data.JsonStore} simplestore {@link Ext.data.SimpleStore} (deprecated; use arraystore) store {@link Ext.data.Store} xmlstore {@link Ext.data.XmlStore} </pre> * @constructor * @param {Ext.Element/String/Object} config The configuration options may be specified as either: * <div class="mdetail-params"><ul> * <li><b>an element</b> : * <p class="sub-desc">it is set as the internal element and its id used as the component id</p></li> * <li><b>a string</b> : * <p class="sub-desc">it is assumed to be the id of an existing element and is used as the component id</p></li> * <li><b>anything else</b> : * <p class="sub-desc">it is assumed to be a standard config object and is applied to the component</p></li> * </ul></div> */ Ext.Component = function(config){ config = config || {}; if(config.initialConfig){ if(config.isAction){ // actions this.baseAction = config; } config = config.initialConfig; // component cloning / action set up }else if(config.tagName || config.dom || Ext.isString(config)){ // element object config = {applyTo: config, id: config.id || config}; } /** * This Component's initial configuration specification. Read-only. * @type Object * @property initialConfig */ this.initialConfig = config; Ext.apply(this, config); this.addEvents( /** * @event disable * Fires after the component is disabled. * @param {Ext.Component} this */ 'disable', /** * @event enable * Fires after the component is enabled. * @param {Ext.Component} this */ 'enable', /** * @event beforeshow * Fires before the component is shown by calling the {@link #show} method. * Return false from an event handler to stop the show. * @param {Ext.Component} this */ 'beforeshow', /** * @event show * Fires after the component is shown when calling the {@link #show} method. * @param {Ext.Component} this */ 'show', /** * @event beforehide * Fires before the component is hidden by calling the {@link #hide} method. * Return false from an event handler to stop the hide. * @param {Ext.Component} this */ 'beforehide', /** * @event hide * Fires after the component is hidden. * Fires after the component is hidden when calling the {@link #hide} method. * @param {Ext.Component} this */ 'hide', /** * @event beforerender * Fires before the component is {@link #rendered}. Return false from an * event handler to stop the {@link #render}. * @param {Ext.Component} this */ 'beforerender', /** * @event render * Fires after the component markup is {@link #rendered}. * @param {Ext.Component} this */ 'render', /** * @event afterrender * <p>Fires after the component rendering is finished.</p> * <p>The afterrender event is fired after this Component has been {@link #rendered}, been postprocesed * by any afterRender method defined for the Component, and, if {@link #stateful}, after state * has been restored.</p> * @param {Ext.Component} this */ 'afterrender', /** * @event beforedestroy * Fires before the component is {@link #destroy}ed. Return false from an event handler to stop the {@link #destroy}. * @param {Ext.Component} this */ 'beforedestroy', /** * @event destroy * Fires after the component is {@link #destroy}ed. * @param {Ext.Component} this */ 'destroy', /** * @event beforestaterestore * Fires before the state of the component is restored. Return false from an event handler to stop the restore. * @param {Ext.Component} this * @param {Object} state The hash of state values returned from the StateProvider. If this * event is not vetoed, then the state object is passed to <b><tt>applyState</tt></b>. By default, * that simply copies property values into this Component. The method maybe overriden to * provide custom state restoration. */ 'beforestaterestore', /** * @event staterestore * Fires after the state of the component is restored. * @param {Ext.Component} this * @param {Object} state The hash of state values returned from the StateProvider. This is passed * to <b><tt>applyState</tt></b>. By default, that simply copies property values into this * Component. The method maybe overriden to provide custom state restoration. */ 'staterestore', /** * @event beforestatesave * Fires before the state of the component is saved to the configured state provider. Return false to stop the save. * @param {Ext.Component} this * @param {Object} state The hash of state values. This is determined by calling * <b><tt>getState()</tt></b> on the Component. This method must be provided by the * developer to return whetever representation of state is required, by default, Ext.Component * has a null implementation. */ 'beforestatesave', /** * @event statesave * Fires after the state of the component is saved to the configured state provider. * @param {Ext.Component} this * @param {Object} state The hash of state values. This is determined by calling * <b><tt>getState()</tt></b> on the Component. This method must be provided by the * developer to return whetever representation of state is required, by default, Ext.Component * has a null implementation. */ 'statesave' ); this.getId(); Ext.ComponentMgr.register(this); Ext.Component.superclass.constructor.call(this); if(this.baseAction){ this.baseAction.addComponent(this); } this.initComponent(); if(this.plugins){ if(Ext.isArray(this.plugins)){ for(var i = 0, len = this.plugins.length; i < len; i++){ this.plugins[i] = this.initPlugin(this.plugins[i]); } }else{ this.plugins = this.initPlugin(this.plugins); } } if(this.stateful !== false){ this.initState(config); } if(this.applyTo){ this.applyToMarkup(this.applyTo); delete this.applyTo; }else if(this.renderTo){ this.render(this.renderTo); delete this.renderTo; } }; // private Ext.Component.AUTO_ID = 1000; Ext.extend(Ext.Component, Ext.util.Observable, { // Configs below are used for all Components when rendered by FormLayout. /** * @cfg {String} fieldLabel <p>The label text to display next to this Component (defaults to '').</p> * <br><p><b>Note</b>: this config is only used when this Component is rendered by a Container which * has been configured to use the <b>{@link Ext.layout.FormLayout FormLayout}</b> layout manager (e.g. * {@link Ext.form.FormPanel} or specifying <tt>layout:'form'</tt>).</p><br> * <p>Also see <tt>{@link #hideLabel}</tt> and * {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl}.</p> * Example use:<pre><code> new Ext.FormPanel({ height: 100, renderTo: Ext.getBody(), items: [{ xtype: 'textfield', fieldLabel: 'Name' }] }); </code></pre> */ /** * @cfg {String} labelStyle <p>A CSS style specification string to apply directly to this field's * label. Defaults to the container's labelStyle value if set (e.g., * <tt>{@link Ext.layout.FormLayout#labelStyle}</tt> , or '').</p> * <br><p><b>Note</b>: see the note for <code>{@link #clearCls}</code>.</p><br> * <p>Also see <code>{@link #hideLabel}</code> and * <code>{@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl}.</code></p> * Example use:<pre><code> new Ext.FormPanel({ height: 100, renderTo: Ext.getBody(), items: [{ xtype: 'textfield', fieldLabel: 'Name', labelStyle: 'font-weight:bold;' }] }); </code></pre> */ /** * @cfg {String} labelSeparator <p>The separator to display after the text of each * <tt>{@link #fieldLabel}</tt>. This property may be configured at various levels. * The order of precedence is: * <div class="mdetail-params"><ul> * <li>field / component level</li> * <li>container level</li> * <li>{@link Ext.layout.FormLayout#labelSeparator layout level} (defaults to colon <tt>':'</tt>)</li> * </ul></div> * To display no separator for this field's label specify empty string ''.</p> * <br><p><b>Note</b>: see the note for <tt>{@link #clearCls}</tt>.</p><br> * <p>Also see <tt>{@link #hideLabel}</tt> and * {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl}.</p> * Example use:<pre><code> new Ext.FormPanel({ height: 100, renderTo: Ext.getBody(), layoutConfig: { labelSeparator: '~' // layout config has lowest priority (defaults to ':') }, {@link Ext.layout.FormLayout#labelSeparator labelSeparator}: '>>', // config at container level items: [{ xtype: 'textfield', fieldLabel: 'Field 1', labelSeparator: '...' // field/component level config supersedes others },{ xtype: 'textfield', fieldLabel: 'Field 2' // labelSeparator will be '=' }] }); </code></pre> */ /** * @cfg {Boolean} hideLabel <p><tt>true</tt> to completely hide the label element * ({@link #fieldLabel label} and {@link #labelSeparator separator}). Defaults to <tt>false</tt>. * By default, even if you do not specify a <tt>{@link #fieldLabel}</tt> the space will still be * reserved so that the field will line up with other fields that do have labels. * Setting this to <tt>true</tt> will cause the field to not reserve that space.</p> * <br><p><b>Note</b>: see the note for <tt>{@link #clearCls}</tt>.</p><br> * Example use:<pre><code> new Ext.FormPanel({ height: 100, renderTo: Ext.getBody(), items: [{ xtype: 'textfield' hideLabel: true }] }); </code></pre> */ /** * @cfg {String} clearCls <p>The CSS class used to to apply to the special clearing div rendered * directly after each form field wrapper to provide field clearing (defaults to * <tt>'x-form-clear-left'</tt>).</p> * <br><p><b>Note</b>: this config is only used when this Component is rendered by a Container * which has been configured to use the <b>{@link Ext.layout.FormLayout FormLayout}</b> layout * manager (e.g. {@link Ext.form.FormPanel} or specifying <tt>layout:'form'</tt>) and either a * <tt>{@link #fieldLabel}</tt> is specified or <tt>isFormField=true</tt> is specified.</p><br> * <p>See {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl} also.</p> */ /** * @cfg {String} itemCls <p>An additional CSS class to apply to the div wrapping the form item * element of this field. If supplied, <tt>itemCls</tt> at the <b>field</b> level will override * the default <tt>itemCls</tt> supplied at the <b>container</b> level. The value specified for * <tt>itemCls</tt> will be added to the default class (<tt>'x-form-item'</tt>).</p> * <p>Since it is applied to the item wrapper (see * {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl}), it allows * you to write standard CSS rules that can apply to the field, the label (if specified), or * any other element within the markup for the field.</p> * <br><p><b>Note</b>: see the note for <tt>{@link #fieldLabel}</tt>.</p><br> * Example use:<pre><code> // Apply a style to the field's label: <style> .required .x-form-item-label {font-weight:bold;color:red;} </style> new Ext.FormPanel({ height: 100, renderTo: Ext.getBody(), items: [{ xtype: 'textfield', fieldLabel: 'Name', itemCls: 'required' //this label will be styled },{ xtype: 'textfield', fieldLabel: 'Favorite Color' }] }); </code></pre> */ // Configs below are used for all Components when rendered by AnchorLayout. /** * @cfg {String} anchor <p><b>Note</b>: this config is only used when this Component is rendered * by a Container which has been configured to use an <b>{@link Ext.layout.AnchorLayout AnchorLayout}</b> * based layout manager, for example:<div class="mdetail-params"><ul> * <li>{@link Ext.form.FormPanel}</li> * <li>specifying <code>layout: 'anchor' // or 'form', or 'absolute'</code></li> * </ul></div></p> * <p>See {@link Ext.layout.AnchorLayout}.{@link Ext.layout.AnchorLayout#anchor anchor} also.</p> */ /** * @cfg {String} id * <p>The <b>unique</b> id of this component (defaults to an {@link #getId auto-assigned id}). * You should assign an id if you need to be able to access the component later and you do * not have an object reference available (e.g., using {@link Ext}.{@link Ext#getCmp getCmp}).</p> * <p>Note that this id will also be used as the element id for the containing HTML element * that is rendered to the page for this component. This allows you to write id-based CSS * rules to style the specific instance of this component uniquely, and also to select * sub-elements using this component's id as the parent.</p> * <p><b>Note</b>: to avoid complications imposed by a unique <tt>id</tt> also see * <code>{@link #itemId}</code> and <code>{@link #ref}</code>.</p> * <p><b>Note</b>: to access the container of an item see <code>{@link #ownerCt}</code>.</p> */ /** * @cfg {String} itemId * <p>An <tt>itemId</tt> can be used as an alternative way to get a reference to a component * when no object reference is available. Instead of using an <code>{@link #id}</code> with * {@link Ext}.{@link Ext#getCmp getCmp}, use <code>itemId</code> with * {@link Ext.Container}.{@link Ext.Container#getComponent getComponent} which will retrieve * <code>itemId</code>'s or <tt>{@link #id}</tt>'s. Since <code>itemId</code>'s are an index to the * container's internal MixedCollection, the <code>itemId</code> is scoped locally to the container -- * avoiding potential conflicts with {@link Ext.ComponentMgr} which requires a <b>unique</b> * <code>{@link #id}</code>.</p> * <pre><code> var c = new Ext.Panel({ // {@link Ext.BoxComponent#height height}: 300, {@link #renderTo}: document.body, {@link Ext.Container#layout layout}: 'auto', {@link Ext.Container#items items}: [ { itemId: 'p1', {@link Ext.Panel#title title}: 'Panel 1', {@link Ext.BoxComponent#height height}: 150 }, { itemId: 'p2', {@link Ext.Panel#title title}: 'Panel 2', {@link Ext.BoxComponent#height height}: 150 } ] }) p1 = c.{@link Ext.Container#getComponent getComponent}('p1'); // not the same as {@link Ext#getCmp Ext.getCmp()} p2 = p1.{@link #ownerCt}.{@link Ext.Container#getComponent getComponent}('p2'); // reference via a sibling * </code></pre> * <p>Also see <tt>{@link #id}</tt> and <code>{@link #ref}</code>.</p> * <p><b>Note</b>: to access the container of an item see <tt>{@link #ownerCt}</tt>.</p> */ /** * @cfg {String} xtype * The registered <tt>xtype</tt> to create. This config option is not used when passing * a config object into a constructor. This config option is used only when * lazy instantiation is being used, and a child item of a Container is being * specified not as a fully instantiated Component, but as a <i>Component config * object</i>. The <tt>xtype</tt> will be looked up at render time up to determine what * type of child Component to create.<br><br> * The predefined xtypes are listed {@link Ext.Component here}. * <br><br> * If you subclass Components to create your own Components, you may register * them using {@link Ext.ComponentMgr#registerType} in order to be able to * take advantage of lazy instantiation and rendering. */ /** * @cfg {String} ptype * The registered <tt>ptype</tt> to create. This config option is not used when passing * a config object into a constructor. This config option is used only when * lazy instantiation is being used, and a Plugin is being * specified not as a fully instantiated Component, but as a <i>Component config * object</i>. The <tt>ptype</tt> will be looked up at render time up to determine what * type of Plugin to create.<br><br> * If you create your own Plugins, you may register them using * {@link Ext.ComponentMgr#registerPlugin} in order to be able to * take advantage of lazy instantiation and rendering. */ /** * @cfg {String} cls * An optional extra CSS class that will be added to this component's Element (defaults to ''). This can be * useful for adding customized styles to the component or any of its children using standard CSS rules. */ /** * @cfg {String} overCls * An optional extra CSS class that will be added to this component's Element when the mouse moves * over the Element, and removed when the mouse moves out. (defaults to ''). This can be * useful for adding customized 'active' or 'hover' styles to the component or any of its children using standard CSS rules. */ /** * @cfg {String} style * A custom style specification to be applied to this component's Element. Should be a valid argument to * {@link Ext.Element#applyStyles}. * <pre><code> new Ext.Panel({ title: 'Some Title', renderTo: Ext.getBody(), width: 400, height: 300, layout: 'form', items: [{ xtype: 'textarea', style: { width: '95%', marginBottom: '10px' } }, new Ext.Button({ text: 'Send', minWidth: '100', style: { marginBottom: '10px' } }) ] }); * </code></pre> */ /** * @cfg {String} ctCls * <p>An optional extra CSS class that will be added to this component's container. This can be useful for * adding customized styles to the container or any of its children using standard CSS rules. See * {@link Ext.layout.ContainerLayout}.{@link Ext.layout.ContainerLayout#extraCls extraCls} also.</p> * <p><b>Note</b>: <tt>ctCls</tt> defaults to <tt>''</tt> except for the following class * which assigns a value by default: * <div class="mdetail-params"><ul> * <li>{@link Ext.layout.Box Box Layout} : <tt>'x-box-layout-ct'</tt></li> * </ul></div> * To configure the above Class with an extra CSS class append to the default. For example, * for BoxLayout (Hbox and Vbox):<pre><code> * ctCls: 'x-box-layout-ct custom-class' * </code></pre> * </p> */ /** * @cfg {Boolean} disabled * Render this component disabled (default is false). */ disabled : false, /** * @cfg {Boolean} hidden * Render this component hidden (default is false). If <tt>true</tt>, the * {@link #hide} method will be called internally. */ hidden : false, /** * @cfg {Object/Array} plugins * An object or array of objects that will provide custom functionality for this component. The only * requirement for a valid plugin is that it contain an init method that accepts a reference of type Ext.Component. * When a component is created, if any plugins are available, the component will call the init method on each * plugin, passing a reference to itself. Each plugin can then call methods or respond to events on the * component as needed to provide its functionality. */ /** * @cfg {Mixed} applyTo * <p>Specify the id of the element, a DOM element or an existing Element corresponding to a DIV * that is already present in the document that specifies some structural markup for this * component.</p><div><ul> * <li><b>Description</b> : <ul> * <div class="sub-desc">When <tt>applyTo</tt> is used, constituent parts of the component can also be specified * by id or CSS class name within the main element, and the component being created may attempt * to create its subcomponents from that markup if applicable.</div> * </ul></li> * <li><b>Notes</b> : <ul> * <div class="sub-desc">When using this config, a call to render() is not required.</div> * <div class="sub-desc">If applyTo is specified, any value passed for {@link #renderTo} will be ignored and the target * element's parent node will automatically be used as the component's container.</div> * </ul></li> * </ul></div> */ /** * @cfg {Mixed} renderTo * <p>Specify the id of the element, a DOM element or an existing Element that this component * will be rendered into.</p><div><ul> * <li><b>Notes</b> : <ul> * <div class="sub-desc">Do <u>not</u> use this option if the Component is to be a child item of * a {@link Ext.Container Container}. It is the responsibility of the * {@link Ext.Container Container}'s {@link Ext.Container#layout layout manager} * to render and manage its child items.</div> * <div class="sub-desc">When using this config, a call to render() is not required.</div> * </ul></li> * </ul></div> * <p>See <tt>{@link #render}</tt> also.</p> */ /** * @cfg {Boolean} stateful * <p>A flag which causes the Component to attempt to restore the state of * internal properties from a saved state on startup. The component must have * either a <code>{@link #stateId}</code> or <code>{@link #id}</code> assigned * for state to be managed. Auto-generated ids are not guaranteed to be stable * across page loads and cannot be relied upon to save and restore the same * state for a component.<p> * <p>For state saving to work, the state manager's provider must have been * set to an implementation of {@link Ext.state.Provider} which overrides the * {@link Ext.state.Provider#set set} and {@link Ext.state.Provider#get get} * methods to save and recall name/value pairs. A built-in implementation, * {@link Ext.state.CookieProvider} is available.</p> * <p>To set the state provider for the current page:</p> * <pre><code> Ext.state.Manager.setProvider(new Ext.state.CookieProvider({ expires: new Date(new Date().getTime()+(1000*60*60*24*7)), //7 days from now })); * </code></pre> * <p>A stateful Component attempts to save state when one of the events * listed in the <code>{@link #stateEvents}</code> configuration fires.</p> * <p>To save state, a stateful Component first serializes its state by * calling <b><code>getState</code></b>. By default, this function does * nothing. The developer must provide an implementation which returns an * object hash which represents the Component's restorable state.</p> * <p>The value yielded by getState is passed to {@link Ext.state.Manager#set} * which uses the configured {@link Ext.state.Provider} to save the object * keyed by the Component's <code>{@link stateId}</code>, or, if that is not * specified, its <code>{@link #id}</code>.</p> * <p>During construction, a stateful Component attempts to <i>restore</i> * its state by calling {@link Ext.state.Manager#get} passing the * <code>{@link #stateId}</code>, or, if that is not specified, the * <code>{@link #id}</code>.</p> * <p>The resulting object is passed to <b><code>applyState</code></b>. * The default implementation of <code>applyState</code> simply copies * properties into the object, but a developer may override this to support * more behaviour.</p> * <p>You can perform extra processing on state save and restore by attaching * handlers to the {@link #beforestaterestore}, {@link #staterestore}, * {@link #beforestatesave} and {@link #statesave} events.</p> */ /** * @cfg {String} stateId * The unique id for this component to use for state management purposes * (defaults to the component id if one was set, otherwise null if the * component is using a generated id). * <p>See <code>{@link #stateful}</code> for an explanation of saving and * restoring Component state.</p> */ /** * @cfg {Array} stateEvents * <p>An array of events that, when fired, should trigger this component to * save its state (defaults to none). <code>stateEvents</code> may be any type * of event supported by this component, including browser or custom events * (e.g., <tt>['click', 'customerchange']</tt>).</p> * <p>See <code>{@link #stateful}</code> for an explanation of saving and * restoring Component state.</p> */ /** * @cfg {Mixed} autoEl * <p>A tag name or {@link Ext.DomHelper DomHelper} spec used to create the {@link #getEl Element} which will * encapsulate this Component.</p> * <p>You do not normally need to specify this. For the base classes {@link Ext.Component}, {@link Ext.BoxComponent}, * and {@link Ext.Container}, this defaults to <b><tt>'div'</tt></b>. The more complex Ext classes use a more complex * DOM structure created by their own onRender methods.</p> * <p>This is intended to allow the developer to create application-specific utility Components encapsulated by * different DOM elements. Example usage:</p><pre><code> { xtype: 'box', autoEl: { tag: 'img', src: 'http://www.example.com/example.jpg' } }, { xtype: 'box', autoEl: { tag: 'blockquote', html: 'autoEl is cool!' } }, { xtype: 'container', autoEl: 'ul', cls: 'ux-unordered-list', items: { xtype: 'box', autoEl: 'li', html: 'First list item' } } </code></pre> */ autoEl : 'div', /** * @cfg {String} disabledClass * CSS class added to the component when it is disabled (defaults to 'x-item-disabled'). */ disabledClass : 'x-item-disabled', /** * @cfg {Boolean} allowDomMove * Whether the component can move the Dom node when rendering (defaults to true). */ allowDomMove : true, /** * @cfg {Boolean} autoShow * True if the component should check for hidden classes (e.g. 'x-hidden' or 'x-hide-display') and remove * them on render (defaults to false). */ autoShow : false, /** * @cfg {String} hideMode * <p>How this component should be hidden. Supported values are <tt>'visibility'</tt> * (css visibility), <tt>'offsets'</tt> (negative offset position) and <tt>'display'</tt> * (css display).</p> * <br><p><b>Note</b>: the default of <tt>'display'</tt> is generally preferred * since items are automatically laid out when they are first shown (no sizing * is done while hidden).</p> */ hideMode : 'display', /** * @cfg {Boolean} hideParent * True to hide and show the component's container when hide/show is called on the component, false to hide * and show the component itself (defaults to false). For example, this can be used as a shortcut for a hide * button on a window by setting hide:true on the button when adding it to its parent container. */ hideParent : false, /** * <p>The {@link Ext.Element} which encapsulates this Component. Read-only.</p> * <p>This will <i>usually</i> be a <DIV> element created by the class's onRender method, but * that may be overridden using the <code>{@link #autoEl}</code> config.</p> * <br><p><b>Note</b>: this element will not be available until this Component has been rendered.</p><br> * <p>To add listeners for <b>DOM events</b> to this Component (as opposed to listeners * for this Component's own Observable events), see the {@link Ext.util.Observable#listeners listeners} * config for a suggestion, or use a render listener directly:</p><pre><code> new Ext.Panel({ title: 'The Clickable Panel', listeners: { render: function(p) { // Append the Panel to the click handler's argument list. p.getEl().on('click', handlePanelClick.createDelegate(null, [p], true)); }, single: true // Remove the listener after first invocation } }); </code></pre> * <p>See also <tt>{@link #getEl getEl}</p> * @type Ext.Element * @property el */ /** * The component's owner {@link Ext.Container} (defaults to undefined, and is set automatically when * the component is added to a container). Read-only. * <p><b>Note</b>: to access items within the container see <tt>{@link #itemId}</tt>.</p> * @type Ext.Container * @property ownerCt */ /** * True if this component is hidden. Read-only. * @type Boolean * @property */ /** * True if this component is disabled. Read-only. * @type Boolean * @property */ /** * True if this component has been rendered. Read-only. * @type Boolean * @property */ rendered : false, // private ctype : 'Ext.Component', // private actionMode : 'el', // private getActionEl : function(){ return this[this.actionMode]; }, initPlugin : function(p){ if(p.ptype && !Ext.isFunction(p.init)){ p = Ext.ComponentMgr.createPlugin(p); }else if(Ext.isString(p)){ p = Ext.ComponentMgr.createPlugin({ ptype: p }); } p.init(this); return p; }, /* // protected * Function to be implemented by Component subclasses to be part of standard component initialization flow (it is empty by default). * <pre><code> // Traditional constructor: Ext.Foo = function(config){ // call superclass constructor: Ext.Foo.superclass.constructor.call(this, config); this.addEvents({ // add events }); }; Ext.extend(Ext.Foo, Ext.Bar, { // class body } // initComponent replaces the constructor: Ext.Foo = Ext.extend(Ext.Bar, { initComponent : function(){ // call superclass initComponent Ext.Container.superclass.initComponent.call(this); this.addEvents({ // add events }); } } </code></pre> */ initComponent : Ext.emptyFn, /** * <p>Render this Component into the passed HTML element.</p> * <p><b>If you are using a {@link Ext.Container Container} object to house this Component, then * do not use the render method.</b></p> * <p>A Container's child Components are rendered by that Container's * {@link Ext.Container#layout layout} manager when the Container is first rendered.</p> * <p>Certain layout managers allow dynamic addition of child components. Those that do * include {@link Ext.layout.CardLayout}, {@link Ext.layout.AnchorLayout}, * {@link Ext.layout.FormLayout}, {@link Ext.layout.TableLayout}.</p> * <p>If the Container is already rendered when a new child Component is added, you may need to call * the Container's {@link Ext.Container#doLayout doLayout} to refresh the view which causes any * unrendered child Components to be rendered. This is required so that you can add multiple * child components if needed while only refreshing the layout once.</p> * <p>When creating complex UIs, it is important to remember that sizing and positioning * of child items is the responsibility of the Container's {@link Ext.Container#layout layout} manager. * If you expect child items to be sized in response to user interactions, you must * configure the Container with a layout manager which creates and manages the type of layout you * have in mind.</p> * <p><b>Omitting the Container's {@link Ext.Container#layout layout} config means that a basic * layout manager is used which does nothing but render child components sequentially into the * Container. No sizing or positioning will be performed in this situation.</b></p> * @param {Element/HTMLElement/String} container (optional) The element this Component should be * rendered into. If it is being created from existing markup, this should be omitted. * @param {String/Number} position (optional) The element ID or DOM node index within the container <b>before</b> * which this component will be inserted (defaults to appending to the end of the container) */ render : function(container, position){ if(!this.rendered && this.fireEvent('beforerender', this) !== false){ if(!container && this.el){ this.el = Ext.get(this.el); container = this.el.dom.parentNode; this.allowDomMove = false; } this.container = Ext.get(container); if(this.ctCls){ this.container.addClass(this.ctCls); } this.rendered = true; if(position !== undefined){ if(Ext.isNumber(position)){ position = this.container.dom.childNodes[position]; }else{ position = Ext.getDom(position); } } this.onRender(this.container, position || null); if(this.autoShow){ this.el.removeClass(['x-hidden','x-hide-' + this.hideMode]); } if(this.cls){ this.el.addClass(this.cls); delete this.cls; } if(this.style){ this.el.applyStyles(this.style); delete this.style; } if(this.overCls){ this.el.addClassOnOver(this.overCls); } this.fireEvent('render', this); this.afterRender(this.container); if(this.hidden){ // call this so we don't fire initial hide events. this.doHide(); } if(this.disabled){ // pass silent so the event doesn't fire the first time. this.disable(true); } if(this.stateful !== false){ this.initStateEvents(); } this.initRef(); this.fireEvent('afterrender', this); } return this; }, initRef : function(){ /** * @cfg {String} ref * <p>A path specification, relative to the Component's {@link #ownerCt} specifying into which * ancestor Container to place a named reference to this Component.</p> * <p>The ancestor axis can be traversed by using '/' characters in the path. * For example, to put a reference to a Toolbar Button into <i>the Panel which owns the Toolbar</i>:</p><pre><code> var myGrid = new Ext.grid.EditorGridPanel({ title: 'My EditorGridPanel', store: myStore, colModel: myColModel, tbar: [{ text: 'Save', handler: saveChanges, disabled: true, ref: '../saveButton' }], listeners: { afteredit: function() { // The button reference is in the GridPanel myGrid.saveButton.enable(); } } }); </code></pre> * <p>In the code above, if the ref had been <code>'saveButton'</code> the reference would * have been placed into the Toolbar. Each '/' in the ref moves up one level from the * Component's {@link #ownerCt}.</p> */ if(this.ref){ var levels = this.ref.split('/'); var last = levels.length, i = 0; var t = this; while(i < last){ if(t.ownerCt){ t = t.ownerCt; } i++; } t[levels[--i]] = this; } }, // private initState : function(config){ if(Ext.state.Manager){ var id = this.getStateId(); if(id){ var state = Ext.state.Manager.get(id); if(state){ if(this.fireEvent('beforestaterestore', this, state) !== false){ this.applyState(state); this.fireEvent('staterestore', this, state); } } } } }, // private getStateId : function(){ return this.stateId || ((this.id.indexOf('ext-comp-') == 0 || this.id.indexOf('ext-gen') == 0) ? null : this.id); }, // private initStateEvents : function(){ if(this.stateEvents){ for(var i = 0, e; e = this.stateEvents[i]; i++){ this.on(e, this.saveState, this, {delay:100}); } } }, // private applyState : function(state, config){ if(state){ Ext.apply(this, state); } }, // private getState : function(){ return null; }, // private saveState : function(){ if(Ext.state.Manager && this.stateful !== false){ var id = this.getStateId(); if(id){ var state = this.getState(); if(this.fireEvent('beforestatesave', this, state) !== false){ Ext.state.Manager.set(id, state); this.fireEvent('statesave', this, state); } } } }, /** * Apply this component to existing markup that is valid. With this function, no call to render() is required. * @param {String/HTMLElement} el */ applyToMarkup : function(el){ this.allowDomMove = false; this.el = Ext.get(el); this.render(this.el.dom.parentNode); }, /** * Adds a CSS class to the component's underlying element. * @param {string} cls The CSS class name to add * @return {Ext.Component} this */ addClass : function(cls){ if(this.el){ this.el.addClass(cls); }else{ this.cls = this.cls ? this.cls + ' ' + cls : cls; } return this; }, /** * Removes a CSS class from the component's underlying element. * @param {string} cls The CSS class name to remove * @return {Ext.Component} this */ removeClass : function(cls){ if(this.el){ this.el.removeClass(cls); }else if(this.cls){ this.cls = this.cls.split(' ').remove(cls).join(' '); } return this; }, // private // default function is not really useful onRender : function(ct, position){ if(!this.el && this.autoEl){ if(Ext.isString(this.autoEl)){ this.el = document.createElement(this.autoEl); }else{ var div = document.createElement('div'); Ext.DomHelper.overwrite(div, this.autoEl); this.el = div.firstChild; } if (!this.el.id) { this.el.id = this.getId(); } } if(this.el){ this.el = Ext.get(this.el); if(this.allowDomMove !== false){ ct.dom.insertBefore(this.el.dom, position); } } }, // private getAutoCreate : function(){ var cfg = Ext.isObject(this.autoCreate) ? this.autoCreate : Ext.apply({}, this.defaultAutoCreate); if(this.id && !cfg.id){ cfg.id = this.id; } return cfg; }, // private afterRender : Ext.emptyFn, /** * Destroys this component by purging any event listeners, removing the component's element from the DOM, * removing the component from its {@link Ext.Container} (if applicable) and unregistering it from * {@link Ext.ComponentMgr}. Destruction is generally handled automatically by the framework and this method * should usually not need to be called directly. * */ destroy : function(){ if(this.fireEvent('beforedestroy', this) !== false){ this.beforeDestroy(); if(this.rendered){ this.el.removeAllListeners(); this.el.remove(); if(this.actionMode == 'container' || this.removeMode == 'container'){ this.container.remove(); } } this.onDestroy(); Ext.ComponentMgr.unregister(this); this.fireEvent('destroy', this); this.purgeListeners(); } }, // private beforeDestroy : Ext.emptyFn, // private onDestroy : Ext.emptyFn, /** * <p>Returns the {@link Ext.Element} which encapsulates this Component.</p> * <p>This will <i>usually</i> be a <DIV> element created by the class's onRender method, but * that may be overridden using the {@link #autoEl} config.</p> * <br><p><b>Note</b>: this element will not be available until this Component has been rendered.</p><br> * <p>To add listeners for <b>DOM events</b> to this Component (as opposed to listeners * for this Component's own Observable events), see the {@link #listeners} config for a suggestion, * or use a render listener directly:</p><pre><code> new Ext.Panel({ title: 'The Clickable Panel', listeners: { render: function(p) { // Append the Panel to the click handler's argument list. p.getEl().on('click', handlePanelClick.createDelegate(null, [p], true)); }, single: true // Remove the listener after first invocation } }); </code></pre> * @return {Ext.Element} The Element which encapsulates this Component. */ getEl : function(){ return this.el; }, /** * Returns the <code>id</code> of this component or automatically generates and * returns an <code>id</code> if an <code>id</code> is not defined yet:<pre><code> * 'ext-comp-' + (++Ext.Component.AUTO_ID) * </code></pre> * @return {String} id */ getId : function(){ return this.id || (this.id = 'ext-comp-' + (++Ext.Component.AUTO_ID)); }, /** * Returns the <code>{@link #itemId}</code> of this component. If an * <code>{@link #itemId}</code> was not assigned through configuration the * <code>id</code> is returned using <code>{@link #getId}</code>. * @return {String} */ getItemId : function(){ return this.itemId || this.getId(); }, /** * Try to focus this component. * @param {Boolean} selectText (optional) If applicable, true to also select the text in this component * @param {Boolean/Number} delay (optional) Delay the focus this number of milliseconds (true for 10 milliseconds) * @return {Ext.Component} this */ focus : function(selectText, delay){ if(delay){ this.focus.defer(Ext.isNumber(delay) ? delay : 10, this, [selectText, false]); return; } if(this.rendered){ this.el.focus(); if(selectText === true){ this.el.dom.select(); } } return this; }, // private blur : function(){ if(this.rendered){ this.el.blur(); } return this; }, /** * Disable this component and fire the 'disable' event. * @return {Ext.Component} this */ disable : function(/* private */ silent){ if(this.rendered){ this.onDisable(); } this.disabled = true; if(silent !== true){ this.fireEvent('disable', this); } return this; }, // private onDisable : function(){ this.getActionEl().addClass(this.disabledClass); this.el.dom.disabled = true; }, /** * Enable this component and fire the 'enable' event. * @return {Ext.Component} this */ enable : function(){ if(this.rendered){ this.onEnable(); } this.disabled = false; this.fireEvent('enable', this); return this; }, // private onEnable : function(){ this.getActionEl().removeClass(this.disabledClass); this.el.dom.disabled = false; }, /** * Convenience function for setting disabled/enabled by boolean. * @param {Boolean} disabled * @return {Ext.Component} this */ setDisabled : function(disabled){ return this[disabled ? 'disable' : 'enable'](); }, /** * Show this component. Listen to the '{@link #beforeshow}' event and return * <tt>false</tt> to cancel showing the component. Fires the '{@link #show}' * event after showing the component. * @return {Ext.Component} this */ show : function(){ if(this.fireEvent('beforeshow', this) !== false){ this.hidden = false; if(this.autoRender){ this.render(Ext.isBoolean(this.autoRender) ? Ext.getBody() : this.autoRender); } if(this.rendered){ this.onShow(); } this.fireEvent('show', this); } return this; }, // private onShow : function(){ this.getVisibiltyEl().removeClass('x-hide-' + this.hideMode); }, /** * Hide this component. Listen to the '{@link #beforehide}' event and return * <tt>false</tt> to cancel hiding the component. Fires the '{@link #hide}' * event after hiding the component. Note this method is called internally if * the component is configured to be <code>{@link #hidden}</code>. * @return {Ext.Component} this */ hide : function(){ if(this.fireEvent('beforehide', this) !== false){ this.doHide(); this.fireEvent('hide', this); } return this; }, // private doHide: function(){ this.hidden = true; if(this.rendered){ this.onHide(); } }, // private onHide : function(){ this.getVisibiltyEl().addClass('x-hide-' + this.hideMode); }, // private getVisibiltyEl : function(){ return this.hideParent ? this.container : this.getActionEl(); }, /** * Convenience function to hide or show this component by boolean. * @param {Boolean} visible True to show, false to hide * @return {Ext.Component} this */ setVisible : function(visible){ return this[visible ? 'show' : 'hide'](); }, /** * Returns true if this component is visible. * @return {Boolean} True if this component is visible, false otherwise. */ isVisible : function(){ return this.rendered && this.getVisibiltyEl().isVisible(); }, /** * Clone the current component using the original config values passed into this instance by default. * @param {Object} overrides A new config containing any properties to override in the cloned version. * An id property can be passed on this object, otherwise one will be generated to avoid duplicates. * @return {Ext.Component} clone The cloned copy of this component */ cloneConfig : function(overrides){ overrides = overrides || {}; var id = overrides.id || Ext.id(); var cfg = Ext.applyIf(overrides, this.initialConfig); cfg.id = id; // prevent dup id return new this.constructor(cfg); }, /** * Gets the xtype for this component as registered with {@link Ext.ComponentMgr}. For a list of all * available xtypes, see the {@link Ext.Component} header. Example usage: * <pre><code> var t = new Ext.form.TextField(); alert(t.getXType()); // alerts 'textfield' </code></pre> * @return {String} The xtype */ getXType : function(){ return this.constructor.xtype; }, /** * <p>Tests whether or not this Component is of a specific xtype. This can test whether this Component is descended * from the xtype (default) or whether it is directly of the xtype specified (shallow = true).</p> * <p><b>If using your own subclasses, be aware that a Component must register its own xtype * to participate in determination of inherited xtypes.</b></p> * <p>For a list of all available xtypes, see the {@link Ext.Component} header.</p> * <p>Example usage:</p> * <pre><code> var t = new Ext.form.TextField(); var isText = t.isXType('textfield'); // true var isBoxSubclass = t.isXType('box'); // true, descended from BoxComponent var isBoxInstance = t.isXType('box', true); // false, not a direct BoxComponent instance </code></pre> * @param {String} xtype The xtype to check for this Component * @param {Boolean} shallow (optional) False to check whether this Component is descended from the xtype (this is * the default), or true to check whether this Component is directly of the specified xtype. * @return {Boolean} True if this component descends from the specified xtype, false otherwise. */ isXType : function(xtype, shallow){ //assume a string by default if (Ext.isFunction(xtype)){ xtype = xtype.xtype; //handle being passed the class, e.g. Ext.Component }else if (Ext.isObject(xtype)){ xtype = xtype.constructor.xtype; //handle being passed an instance } return !shallow ? ('/' + this.getXTypes() + '/').indexOf('/' + xtype + '/') != -1 : this.constructor.xtype == xtype; }, /** * <p>Returns this Component's xtype hierarchy as a slash-delimited string. For a list of all * available xtypes, see the {@link Ext.Component} header.</p> * <p><b>If using your own subclasses, be aware that a Component must register its own xtype * to participate in determination of inherited xtypes.</b></p> * <p>Example usage:</p> * <pre><code> var t = new Ext.form.TextField(); alert(t.getXTypes()); // alerts 'component/box/field/textfield' </code></pre> * @return {String} The xtype hierarchy string */ getXTypes : function(){ var tc = this.constructor; if(!tc.xtypes){ var c = [], sc = this; while(sc && sc.constructor.xtype){ c.unshift(sc.constructor.xtype); sc = sc.constructor.superclass; } tc.xtypeChain = c; tc.xtypes = c.join('/'); } return tc.xtypes; }, /** * Find a container above this component at any level by a custom function. If the passed function returns * true, the container will be returned. * @param {Function} fn The custom function to call with the arguments (container, this component). * @return {Ext.Container} The first Container for which the custom function returns true */ findParentBy : function(fn) { for (var p = this.ownerCt; (p != null) && !fn(p, this); p = p.ownerCt); return p || null; }, /** * Find a container above this component at any level by xtype or class * @param {String/Class} xtype The xtype string for a component, or the class of the component directly * @return {Ext.Container} The first Container which matches the given xtype or class */ findParentByType : function(xtype) { return Ext.isFunction(xtype) ? this.findParentBy(function(p){ return p.constructor === xtype; }) : this.findParentBy(function(p){ return p.constructor.xtype === xtype; }); }, getDomPositionEl : function(){ return this.getPositionEl ? this.getPositionEl() : this.getEl(); }, // private purgeListeners : function(){ Ext.Component.superclass.purgeListeners.call(this); if(this.mons){ this.on('beforedestroy', this.clearMons, this, {single: true}); } }, // private clearMons : function(){ Ext.each(this.mons, function(m){ m.item.un(m.ename, m.fn, m.scope); }, this); this.mons = []; }, // internal function for auto removal of assigned event handlers on destruction mon : function(item, ename, fn, scope, opt){ if(!this.mons){ this.mons = []; this.on('beforedestroy', this.clearMons, this, {single: true}); } if(Ext.isObject(ename)){ var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/; var o = ename; for(var e in o){ if(propRe.test(e)){ continue; } if(Ext.isFunction(o[e])){ // shared options this.mons.push({ item: item, ename: e, fn: o[e], scope: o.scope }); item.on(e, o[e], o.scope, o); }else{ // individual options this.mons.push({ item: item, ename: e, fn: o[e], scope: o.scope }); item.on(e, o[e]); } } return; } this.mons.push({ item: item, ename: ename, fn: fn, scope: scope }); item.on(ename, fn, scope, opt); }, // protected, opposite of mon mun : function(item, ename, fn, scope){ var found, mon; for(var i = 0, len = this.mons.length; i < len; ++i){ mon = this.mons[i]; if(item === mon.item && ename == mon.ename && fn === mon.fn && scope === mon.scope){ this.mons.splice(i, 1); item.un(ename, fn, scope); found = true; break; } } return found; }, /** * Returns the next component in the owning container * @return Ext.Component */ nextSibling : function(){ if(this.ownerCt){ var index = this.ownerCt.items.indexOf(this); if(index != -1 && index+1 < this.ownerCt.items.getCount()){ return this.ownerCt.items.itemAt(index+1); } } return null; }, /** * Returns the previous component in the owning container * @return Ext.Component */ previousSibling : function(){ if(this.ownerCt){ var index = this.ownerCt.items.indexOf(this); if(index > 0){ return this.ownerCt.items.itemAt(index-1); } } return null; }, /** * Provides the link for Observable's fireEvent method to bubble up the ownership hierarchy. * @return {Ext.Container} the Container which owns this Component. */ getBubbleTarget : function(){ return this.ownerCt; } }); Ext.reg('component', Ext.Component); /**
- * @class Ext.Action
- * <p>An Action is a piece of reusable functionality that can be abstracted out of any particular component so that it
- * can be usefully shared among multiple components. Actions let you share handlers, configuration options and UI
- * updates across any components that support the Action interface (primarily {@link Ext.Toolbar}, {@link Ext.Button}
- * and {@link Ext.menu.Menu} components).</p>
- * <p>Aside from supporting the config object interface, any component that needs to use Actions must also support
- * the following method list, as these will be called as needed by the Action class: setText(string), setIconCls(string),
- * setDisabled(boolean), setVisible(boolean) and setHandler(function).</p>
- * Example usage:<br>
- * <pre><code>
- // Define the shared action. Each component below will have the same
- // display text and icon, and will display the same message on click.
- var action = new Ext.Action({
- {@link #text}: 'Do something',
- {@link #handler}: function(){
- Ext.Msg.alert('Click', 'You did something.');
- },
- {@link #iconCls}: 'do-something',
- {@link #itemId}: 'myAction'
- });
- var panel = new Ext.Panel({
- title: 'Actions',
- width: 500,
- height: 300,
- tbar: [
- // Add the action directly to a toolbar as a menu button
- action,
- {
- text: 'Action Menu',
- // Add the action to a menu as a text item
- menu: [action]
- }
- ],
- items: [
- // Add the action to the panel body as a standard button
- new Ext.Button(action)
- ],
- renderTo: Ext.getBody()
- });
- // Change the text for all components using the action
- action.setText('Something else');
- // Reference an action through a container using the itemId
- var btn = panel.getComponent('myAction');
- var aRef = btn.baseAction;
- aRef.setText('New text');
- </code></pre>
- * @constructor
- * @param {Object} config The configuration options
- */
- Ext.Action = function(config){
- this.initialConfig = config;
- this.itemId = config.itemId = (config.itemId || config.id || Ext.id());
- this.items = [];
- }
- Ext.Action.prototype = {
- /**
- * @cfg {String} text The text to set for all components using this action (defaults to '').
- */
- /**
- * @cfg {String} iconCls
- * The CSS class selector that specifies a background image to be used as the header icon for
- * all components using this action (defaults to '').
- * <p>An example of specifying a custom icon class would be something like:
- * </p><pre><code>
- // specify the property in the config for the class:
- ...
- iconCls: 'do-something'
- // css class that specifies background image to be used as the icon image:
- .do-something { background-image: url(../images/my-icon.gif) 0 6px no-repeat !important; }
- </code></pre>
- */
- /**
- * @cfg {Boolean} disabled True to disable all components using this action, false to enable them (defaults to false).
- */
- /**
- * @cfg {Boolean} hidden True to hide all components using this action, false to show them (defaults to false).
- */
- /**
- * @cfg {Function} handler The function that will be invoked by each component tied to this action
- * when the component's primary event is triggered (defaults to undefined).
- */
- /**
- * @cfg {String} itemId
- * See {@link Ext.Component}.{@link Ext.Component#itemId itemId}.
- */
- /**
- * @cfg {Object} scope The scope in which the {@link #handler} function will execute.
- */
- // private
- isAction : true,
- /**
- * Sets the text to be displayed by all components using this action.
- * @param {String} text The text to display
- */
- setText : function(text){
- this.initialConfig.text = text;
- this.callEach('setText', [text]);
- },
- /**
- * Gets the text currently displayed by all components using this action.
- */
- getText : function(){
- return this.initialConfig.text;
- },
- /**
- * Sets the icon CSS class for all components using this action. The class should supply
- * a background image that will be used as the icon image.
- * @param {String} cls The CSS class supplying the icon image
- */
- setIconClass : function(cls){
- this.initialConfig.iconCls = cls;
- this.callEach('setIconClass', [cls]);
- },
- /**
- * Gets the icon CSS class currently used by all components using this action.
- */
- getIconClass : function(){
- return this.initialConfig.iconCls;
- },
- /**
- * Sets the disabled state of all components using this action. Shortcut method
- * for {@link #enable} and {@link #disable}.
- * @param {Boolean} disabled True to disable the component, false to enable it
- */
- setDisabled : function(v){
- this.initialConfig.disabled = v;
- this.callEach('setDisabled', [v]);
- },
- /**
- * Enables all components using this action.
- */
- enable : function(){
- this.setDisabled(false);
- },
- /**
- * Disables all components using this action.
- */
- disable : function(){
- this.setDisabled(true);
- },
- /**
- * Returns true if the components using this action are currently disabled, else returns false.
- */
- isDisabled : function(){
- return this.initialConfig.disabled;
- },
- /**
- * Sets the hidden state of all components using this action. Shortcut method
- * for <code>{@link #hide}</code> and <code>{@link #show}</code>.
- * @param {Boolean} hidden True to hide the component, false to show it
- */
- setHidden : function(v){
- this.initialConfig.hidden = v;
- this.callEach('setVisible', [!v]);
- },
- /**
- * Shows all components using this action.
- */
- show : function(){
- this.setHidden(false);
- },
- /**
- * Hides all components using this action.
- */
- hide : function(){
- this.setHidden(true);
- },
- /**
- * Returns true if the components using this action are currently hidden, else returns false.
- */
- isHidden : function(){
- return this.initialConfig.hidden;
- },
- /**
- * Sets the function that will be called by each component using this action when its primary event is triggered.
- * @param {Function} fn The function that will be invoked by the action's components. The function
- * will be called with no arguments.
- * @param {Object} scope The scope in which the function will execute
- */
- setHandler : function(fn, scope){
- this.initialConfig.handler = fn;
- this.initialConfig.scope = scope;
- this.callEach('setHandler', [fn, scope]);
- },
- /**
- * Executes the specified function once for each component currently tied to this action. The function passed
- * in should accept a single argument that will be an object that supports the basic Action config/method interface.
- * @param {Function} fn The function to execute for each component
- * @param {Object} scope The scope in which the function will execute
- */
- each : function(fn, scope){
- Ext.each(this.items, fn, scope);
- },
- // private
- callEach : function(fnName, args){
- var cs = this.items;
- for(var i = 0, len = cs.length; i < len; i++){
- cs[i][fnName].apply(cs[i], args);
- }
- },
- // private
- addComponent : function(comp){
- this.items.push(comp);
- comp.on('destroy', this.removeComponent, this);
- },
- // private
- removeComponent : function(comp){
- this.items.remove(comp);
- },
- /**
- * Executes this action manually using the handler function specified in the original config object
- * or the handler function set with <code>{@link #setHandler}</code>. Any arguments passed to this
- * function will be passed on to the handler function.
- * @param {Mixed} arg1 (optional) Variable number of arguments passed to the handler function
- * @param {Mixed} arg2 (optional)
- * @param {Mixed} etc... (optional)
- */
- execute : function(){
- this.initialConfig.handler.apply(this.initialConfig.scope || window, arguments);
- }
- }; /** * @class Ext.Layer * @extends Ext.Element * An extended {@link Ext.Element} object that supports a shadow and shim, constrain to viewport and * automatic maintaining of shadow/shim positions. * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true) * @cfg {String/Boolean} shadow True to automatically create an {@link Ext.Shadow}, or a string indicating the * shadow's display {@link Ext.Shadow#mode}. False to disable the shadow. (defaults to false) * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: 'div', cls: 'x-layer'}). * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true) * @cfg {String} cls CSS class to add to the element * @cfg {Number} zindex Starting z-index (defaults to 11000) * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 4) * @cfg {Boolean} useDisplay * Defaults to use css offsets to hide the Layer. Specify <tt>true</tt> * to use css style <tt>'display:none;'</tt> to hide the Layer. * @constructor * @param {Object} config An object with config options. * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it. */ (function(){ Ext.Layer = function(config, existingEl){ config = config || {}; var dh = Ext.DomHelper; var cp = config.parentEl, pel = cp ? Ext.getDom(cp) : document.body; if(existingEl){ this.dom = Ext.getDom(existingEl); } if(!this.dom){ var o = config.dh || {tag: 'div', cls: 'x-layer'}; this.dom = dh.append(pel, o); } if(config.cls){ this.addClass(config.cls); } this.constrain = config.constrain !== false; this.setVisibilityMode(Ext.Element.VISIBILITY); if(config.id){ this.id = this.dom.id = config.id; }else{ this.id = Ext.id(this.dom); } this.zindex = config.zindex || this.getZIndex(); this.position('absolute', this.zindex); if(config.shadow){ this.shadowOffset = config.shadowOffset || 4; this.shadow = new Ext.Shadow({ offset : this.shadowOffset, mode : config.shadow }); }else{ this.shadowOffset = 0; } this.useShim = config.shim !== false && Ext.useShims; this.useDisplay = config.useDisplay; this.hide(); }; var supr = Ext.Element.prototype; // shims are shared among layer to keep from having 100 iframes var shims = []; Ext.extend(Ext.Layer, Ext.Element, { getZIndex : function(){ return this.zindex || parseInt((this.getShim() || this).getStyle('z-index'), 10) || 11000; }, getShim : function(){ if(!this.useShim){ return null; } if(this.shim){ return this.shim; } var shim = shims.shift(); if(!shim){ shim = this.createShim(); shim.enableDisplayMode('block'); shim.dom.style.display = 'none'; shim.dom.style.visibility = 'visible'; } var pn = this.dom.parentNode; if(shim.dom.parentNode != pn){ pn.insertBefore(shim.dom, this.dom); } shim.setStyle('z-index', this.getZIndex()-2); this.shim = shim; return shim; }, hideShim : function(){ if(this.shim){ this.shim.setDisplayed(false); shims.push(this.shim); delete this.shim; } }, disableShadow : function(){ if(this.shadow){ this.shadowDisabled = true; this.shadow.hide(); this.lastShadowOffset = this.shadowOffset; this.shadowOffset = 0; } }, enableShadow : function(show){ if(this.shadow){ this.shadowDisabled = false; this.shadowOffset = this.lastShadowOffset; delete this.lastShadowOffset; if(show){ this.sync(true); } } }, // private // this code can execute repeatedly in milliseconds (i.e. during a drag) so // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls) sync : function(doShow){ var sw = this.shadow; if(!this.updating && this.isVisible() && (sw || this.useShim)){ var sh = this.getShim(); var w = this.getWidth(), h = this.getHeight(); var l = this.getLeft(true), t = this.getTop(true); if(sw && !this.shadowDisabled){ if(doShow && !sw.isVisible()){ sw.show(this); }else{ sw.realign(l, t, w, h); } if(sh){ if(doShow){ sh.show(); } // fit the shim behind the shadow, so it is shimmed too var a = sw.adjusts, s = sh.dom.style; s.left = (Math.min(l, l+a.l))+'px'; s.top = (Math.min(t, t+a.t))+'px'; s.width = (w+a.w)+'px'; s.height = (h+a.h)+'px'; } }else if(sh){ if(doShow){ sh.show(); } sh.setSize(w, h); sh.setLeftTop(l, t); } } }, // private destroy : function(){ this.hideShim(); if(this.shadow){ this.shadow.hide(); } this.removeAllListeners(); Ext.removeNode(this.dom); Ext.Element.uncache(this.id); }, remove : function(){ this.destroy(); }, // private beginUpdate : function(){ this.updating = true; }, // private endUpdate : function(){ this.updating = false; this.sync(true); }, // private hideUnders : function(negOffset){ if(this.shadow){ this.shadow.hide(); } this.hideShim(); }, // private constrainXY : function(){ if(this.constrain){ var vw = Ext.lib.Dom.getViewWidth(), vh = Ext.lib.Dom.getViewHeight(); var s = Ext.getDoc().getScroll(); var xy = this.getXY(); var x = xy[0], y = xy[1]; var so = this.shadowOffset; var w = this.dom.offsetWidth+so, h = this.dom.offsetHeight+so; // only move it if it needs it var moved = false; // first validate right/bottom if((x + w) > vw+s.left){ x = vw - w - so; moved = true; } if((y + h) > vh+s.top){ y = vh - h - so; moved = true; } // then make sure top/left isn't negative if(x < s.left){ x = s.left; moved = true; } if(y < s.top){ y = s.top; moved = true; } if(moved){ if(this.avoidY){ var ay = this.avoidY; if(y <= ay && (y+h) >= ay){ y = ay-h-5; } } xy = [x, y]; this.storeXY(xy); supr.setXY.call(this, xy); this.sync(); } } return this; }, isVisible : function(){ return this.visible; }, // private showAction : function(){ this.visible = true; // track visibility to prevent getStyle calls if(this.useDisplay === true){ this.setDisplayed(''); }else if(this.lastXY){ supr.setXY.call(this, this.lastXY); }else if(this.lastLT){ supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]); } }, // private hideAction : function(){ this.visible = false; if(this.useDisplay === true){ this.setDisplayed(false); }else{ this.setLeftTop(-10000,-10000); } }, // overridden Element method setVisible : function(v, a, d, c, e){ if(v){ this.showAction(); } if(a && v){ var cb = function(){ this.sync(true); if(c){ c(); } }.createDelegate(this); supr.setVisible.call(this, true, true, d, cb, e); }else{ if(!v){ this.hideUnders(true); } var cb = c; if(a){ cb = function(){ this.hideAction(); if(c){ c(); } }.createDelegate(this); } supr.setVisible.call(this, v, a, d, cb, e); if(v){ this.sync(true); }else if(!a){ this.hideAction(); } } return this; }, storeXY : function(xy){ delete this.lastLT; this.lastXY = xy; }, storeLeftTop : function(left, top){ delete this.lastXY; this.lastLT = [left, top]; }, // private beforeFx : function(){ this.beforeAction(); return Ext.Layer.superclass.beforeFx.apply(this, arguments); }, // private afterFx : function(){ Ext.Layer.superclass.afterFx.apply(this, arguments); this.sync(this.isVisible()); }, // private beforeAction : function(){ if(!this.updating && this.shadow){ this.shadow.hide(); } }, // overridden Element method setLeft : function(left){ this.storeLeftTop(left, this.getTop(true)); supr.setLeft.apply(this, arguments); this.sync(); return this; }, setTop : function(top){ this.storeLeftTop(this.getLeft(true), top); supr.setTop.apply(this, arguments); this.sync(); return this; }, setLeftTop : function(left, top){ this.storeLeftTop(left, top); supr.setLeftTop.apply(this, arguments); this.sync(); return this; }, setXY : function(xy, a, d, c, e){ this.fixDisplay(); this.beforeAction(); this.storeXY(xy); var cb = this.createCB(c); supr.setXY.call(this, xy, a, d, cb, e); if(!a){ cb(); } return this; }, // private createCB : function(c){ var el = this; return function(){ el.constrainXY(); el.sync(true); if(c){ c(); } }; }, // overridden Element method setX : function(x, a, d, c, e){ this.setXY([x, this.getY()], a, d, c, e); return this; }, // overridden Element method setY : function(y, a, d, c, e){ this.setXY([this.getX(), y], a, d, c, e); return this; }, // overridden Element method setSize : function(w, h, a, d, c, e){ this.beforeAction(); var cb = this.createCB(c); supr.setSize.call(this, w, h, a, d, cb, e); if(!a){ cb(); } return this; }, // overridden Element method setWidth : function(w, a, d, c, e){ this.beforeAction(); var cb = this.createCB(c); supr.setWidth.call(this, w, a, d, cb, e); if(!a){ cb(); } return this; }, // overridden Element method setHeight : function(h, a, d, c, e){ this.beforeAction(); var cb = this.createCB(c); supr.setHeight.call(this, h, a, d, cb, e); if(!a){ cb(); } return this; }, // overridden Element method setBounds : function(x, y, w, h, a, d, c, e){ this.beforeAction(); var cb = this.createCB(c); if(!a){ this.storeXY([x, y]); supr.setXY.call(this, [x, y]); supr.setSize.call(this, w, h, a, d, cb, e); cb(); }else{ supr.setBounds.call(this, x, y, w, h, a, d, cb, e); } return this; }, /** * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index). * @param {Number} zindex The new z-index to set * @return {this} The Layer */ setZIndex : function(zindex){ this.zindex = zindex; this.setStyle('z-index', zindex + 2); if(this.shadow){ this.shadow.setZIndex(zindex + 1); } if(this.shim){ this.shim.setStyle('z-index', zindex); } return this; } }); })();/** * @class Ext.Shadow * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned, * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced * functionality that can also provide the same shadow effect, see the {@link Ext.Layer} class. * @constructor * Create a new Shadow * @param {Object} config The config object */ Ext.Shadow = function(config){ Ext.apply(this, config); if(typeof this.mode != "string"){ this.mode = this.defaultMode; } var o = this.offset, a = {h: 0}; var rad = Math.floor(this.offset/2); switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows case "drop": a.w = 0; a.l = a.t = o; a.t -= 1; if(Ext.isIE){ a.l -= this.offset + rad; a.t -= this.offset + rad; a.w -= rad; a.h -= rad; a.t += 1; } break; case "sides": a.w = (o*2); a.l = -o; a.t = o-1; if(Ext.isIE){ a.l -= (this.offset - rad); a.t -= this.offset + rad; a.l += 1; a.w -= (this.offset - rad)*2; a.w -= rad + 1; a.h -= 1; } break; case "frame": a.w = a.h = (o*2); a.l = a.t = -o; a.t += 1; a.h -= 2; if(Ext.isIE){ a.l -= (this.offset - rad); a.t -= (this.offset - rad); a.l += 1; a.w -= (this.offset + rad + 1); a.h -= (this.offset + rad); a.h += 1; } break; }; this.adjusts = a; }; Ext.Shadow.prototype = { /** * @cfg {String} mode * The shadow display mode. Supports the following options:<div class="mdetail-params"><ul> * <li><b><tt>sides</tt></b> : Shadow displays on both sides and bottom only</li> * <li><b><tt>frame</tt></b> : Shadow displays equally on all four sides</li> * <li><b><tt>drop</tt></b> : Traditional bottom-right drop shadow</li> * </ul></div> */ /** * @cfg {String} offset * The number of pixels to offset the shadow from the element (defaults to <tt>4</tt>) */ offset: 4, // private defaultMode: "drop", /** * Displays the shadow under the target element * @param {Mixed} targetEl The id or element under which the shadow should display */ show : function(target){ target = Ext.get(target); if(!this.el){ this.el = Ext.Shadow.Pool.pull(); if(this.el.dom.nextSibling != target.dom){ this.el.insertBefore(target); } } this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1); if(Ext.isIE){ this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")"; } this.realign( target.getLeft(true), target.getTop(true), target.getWidth(), target.getHeight() ); this.el.dom.style.display = "block"; }, /** * Returns true if the shadow is visible, else false */ isVisible : function(){ return this.el ? true : false; }, /** * Direct alignment when values are already available. Show must be called at least once before * calling this method to ensure it is initialized. * @param {Number} left The target element left position * @param {Number} top The target element top position * @param {Number} width The target element width * @param {Number} height The target element height */ realign : function(l, t, w, h){ if(!this.el){ return; } var a = this.adjusts, d = this.el.dom, s = d.style; var iea = 0; s.left = (l+a.l)+"px"; s.top = (t+a.t)+"px"; var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px"; if(s.width != sws || s.height != shs){ s.width = sws; s.height = shs; if(!Ext.isIE){ var cn = d.childNodes; var sww = Math.max(0, (sw-12))+"px"; cn[0].childNodes[1].style.width = sww; cn[1].childNodes[1].style.width = sww; cn[2].childNodes[1].style.width = sww; cn[1].style.height = Math.max(0, (sh-12))+"px"; } } }, /** * Hides this shadow */ hide : function(){ if(this.el){ this.el.dom.style.display = "none"; Ext.Shadow.Pool.push(this.el); delete this.el; } }, /** * Adjust the z-index of this shadow * @param {Number} zindex The new z-index */ setZIndex : function(z){ this.zIndex = z; if(this.el){ this.el.setStyle("z-index", z); } } }; // Private utility class that manages the internal Shadow cache Ext.Shadow.Pool = function(){ var p = []; var markup = Ext.isIE ? '<div class="x-ie-shadow"></div>' : '<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>'; return { pull : function(){ var sh = p.shift(); if(!sh){ sh = Ext.get(Ext.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup)); sh.autoBoxAdjust = false; } return sh; }, push : function(sh){ p.push(sh); } }; }();/** * @class Ext.BoxComponent * @extends Ext.Component * <p>Base class for any {@link Ext.Component Component} that is to be sized as a box, using width and height.</p> * <p>BoxComponent provides automatic box model adjustments for sizing and positioning and will work correctly * within the Component rendering model.</p> * <p>A BoxComponent may be created as a custom Component which encapsulates any HTML element, either a pre-existing * element, or one that is created to your specifications at render time. Usually, to participate in layouts, * a Component will need to be a <b>Box</b>Component in order to have its width and height managed.</p> * <p>To use a pre-existing element as a BoxComponent, configure it so that you preset the <b>el</b> property to the * element to reference:<pre><code> var pageHeader = new Ext.BoxComponent({ el: 'my-header-div' });</code></pre> * This may then be {@link Ext.Container#add added} to a {@link Ext.Container Container} as a child item.</p> * <p>To create a BoxComponent based around a HTML element to be created at render time, use the * {@link Ext.Component#autoEl autoEl} config option which takes the form of a * {@link Ext.DomHelper DomHelper} specification:<pre><code> var myImage = new Ext.BoxComponent({ autoEl: { tag: 'img', src: '/images/my-image.jpg' } });</code></pre></p> * @constructor * @param {Ext.Element/String/Object} config The configuration options. * @xtype box */ Ext.BoxComponent = Ext.extend(Ext.Component, { // Configs below are used for all Components when rendered by BorderLayout. /** * @cfg {String} region <p><b>Note</b>: this config is only used when this BoxComponent is rendered * by a Container which has been configured to use the <b>{@link Ext.layout.BorderLayout BorderLayout}</b> * layout manager (e.g. specifying <tt>layout:'border'</tt>).</p><br> * <p>See {@link Ext.layout.BorderLayout} also.</p> */ // margins config is used when a BoxComponent is rendered by BorderLayout or BoxLayout. /** * @cfg {Object} margins <p><b>Note</b>: this config is only used when this BoxComponent is rendered * by a Container which has been configured to use the <b>{@link Ext.layout.BorderLayout BorderLayout}</b> * or one of the two <b>{@link Ext.layout.BoxLayout BoxLayout} subclasses.</b></p> * <p>An object containing margins to apply to this BoxComponent in the * format:</p><pre><code> { top: (top margin), right: (right margin), bottom: (bottom margin), left: (left margin) }</code></pre> * <p>May also be a string containing space-separated, numeric margin values. The order of the * sides associated with each value matches the way CSS processes margin values:</p> * <p><div class="mdetail-params"><ul> * <li>If there is only one value, it applies to all sides.</li> * <li>If there are two values, the top and bottom borders are set to the first value and the * right and left are set to the second.</li> * <li>If there are three values, the top is set to the first value, the left and right are set * to the second, and the bottom is set to the third.</li> * <li>If there are four values, they apply to the top, right, bottom, and left, respectively.</li> * </ul></div></p> * <p>Defaults to:</p><pre><code> * {top:0, right:0, bottom:0, left:0} * </code></pre> */ /** * @cfg {Number} x * The local x (left) coordinate for this component if contained within a positioning container. */ /** * @cfg {Number} y * The local y (top) coordinate for this component if contained within a positioning container. */ /** * @cfg {Number} pageX * The page level x coordinate for this component if contained within a positioning container. */ /** * @cfg {Number} pageY * The page level y coordinate for this component if contained within a positioning container. */ /** * @cfg {Number} height * The height of this component in pixels (defaults to auto). * <b>Note</b> to express this dimension as a percentage or offset see {@link Ext.Component#anchor}. */ /** * @cfg {Number} width * The width of this component in pixels (defaults to auto). * <b>Note</b> to express this dimension as a percentage or offset see {@link Ext.Component#anchor}. */ /** * @cfg {Boolean} autoHeight * <p>True to use height:'auto', false to use fixed height (or allow it to be managed by its parent * Container's {@link Ext.Container#layout layout manager}. Defaults to false.</p> * <p><b>Note</b>: Although many components inherit this config option, not all will * function as expected with a height of 'auto'. Setting autoHeight:true means that the * browser will manage height based on the element's contents, and that Ext will not manage it at all.</p> * <p>If the <i>browser</i> is managing the height, be aware that resizes performed by the browser in response * to changes within the structure of the Component cannot be detected. Therefore changes to the height might * result in elements needing to be synchronized with the new height. Example:</p><pre><code> var w = new Ext.Window({ title: 'Window', width: 600, autoHeight: true, items: { title: 'Collapse Me', height: 400, collapsible: true, border: false, listeners: { beforecollapse: function() { w.el.shadow.hide(); }, beforeexpand: function() { w.el.shadow.hide(); }, collapse: function() { w.syncShadow(); }, expand: function() { w.syncShadow(); } } } }).show(); </code></pre> */ /** * @cfg {Boolean} autoWidth * <p>True to use width:'auto', false to use fixed width (or allow it to be managed by its parent * Container's {@link Ext.Container#layout layout manager}. Defaults to false.</p> * <p><b>Note</b>: Although many components inherit this config option, not all will * function as expected with a width of 'auto'. Setting autoWidth:true means that the * browser will manage width based on the element's contents, and that Ext will not manage it at all.</p> * <p>If the <i>browser</i> is managing the width, be aware that resizes performed by the browser in response * to changes within the structure of the Component cannot be detected. Therefore changes to the width might * result in elements needing to be synchronized with the new width. For example, where the target element is:</p><pre><code> <div id='grid-container' style='margin-left:25%;width:50%'></div> </code></pre> * A Panel rendered into that target element must listen for browser window resize in order to relay its * child items when the browser changes its width:<pre><code> var myPanel = new Ext.Panel({ renderTo: 'grid-container', monitorResize: true, // relay on browser resize title: 'Panel', height: 400, autoWidth: true, layout: 'hbox', layoutConfig: { align: 'stretch' }, defaults: { flex: 1 }, items: [{ title: 'Box 1', }, { title: 'Box 2' }, { title: 'Box 3' }], }); </code></pre> */ /* // private internal config * {Boolean} deferHeight * True to defer height calculations to an external component, false to allow this component to set its own * height (defaults to false). */ // private initComponent : function(){ Ext.BoxComponent.superclass.initComponent.call(this); this.addEvents( /** * @event resize * Fires after the component is resized. * @param {Ext.Component} this * @param {Number} adjWidth The box-adjusted width that was set * @param {Number} adjHeight The box-adjusted height that was set * @param {Number} rawWidth The width that was originally specified * @param {Number} rawHeight The height that was originally specified */ 'resize', /** * @event move * Fires after the component is moved. * @param {Ext.Component} this * @param {Number} x The new x position * @param {Number} y The new y position */ 'move' ); }, // private, set in afterRender to signify that the component has been rendered boxReady : false, // private, used to defer height settings to subclasses deferHeight: false, /** * Sets the width and height of this BoxComponent. This method fires the {@link #resize} event. This method can accept * either width and height as separate arguments, or you can pass a size object like <code>{width:10, height:20}</code>. * @param {Mixed} width The new width to set. This may be one of:<div class="mdetail-params"><ul> * <li>A Number specifying the new width in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).</li> * <li>A String used to set the CSS width style.</li> * <li>A size object in the format <code>{width: widthValue, height: heightValue}</code>.</li> * <li><code>undefined</code> to leave the width unchanged.</li> * </ul></div> * @param {Mixed} height The new height to set (not required if a size object is passed as the first arg). * This may be one of:<div class="mdetail-params"><ul> * <li>A Number specifying the new height in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).</li> * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li> * <li><code>undefined</code> to leave the height unchanged.</li> * </ul></div> * @return {Ext.BoxComponent} this */ setSize : function(w, h){ // support for standard size objects if(typeof w == 'object'){ h = w.height; w = w.width; } // not rendered if(!this.boxReady){ this.width = w; this.height = h; return this; } // prevent recalcs when not needed if(this.cacheSizes !== false && this.lastSize && this.lastSize.width == w && this.lastSize.height == h){ return this; } this.lastSize = {width: w, height: h}; var adj = this.adjustSize(w, h); var aw = adj.width, ah = adj.height; if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters var rz = this.getResizeEl(); if(!this.deferHeight && aw !== undefined && ah !== undefined){ rz.setSize(aw, ah); }else if(!this.deferHeight && ah !== undefined){ rz.setHeight(ah); }else if(aw !== undefined){ rz.setWidth(aw); } this.onResize(aw, ah, w, h); this.fireEvent('resize', this, aw, ah, w, h); } return this; }, /** * Sets the width of the component. This method fires the {@link #resize} event. * @param {Number} width The new width to setThis may be one of:<div class="mdetail-params"><ul> * <li>A Number specifying the new width in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).</li> * <li>A String used to set the CSS width style.</li> * </ul></div> * @return {Ext.BoxComponent} this */ setWidth : function(width){ return this.setSize(width); }, /** * Sets the height of the component. This method fires the {@link #resize} event. * @param {Number} height The new height to set. This may be one of:<div class="mdetail-params"><ul> * <li>A Number specifying the new height in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).</li> * <li>A String used to set the CSS height style.</li> * <li><i>undefined</i> to leave the height unchanged.</li> * </ul></div> * @return {Ext.BoxComponent} this */ setHeight : function(height){ return this.setSize(undefined, height); }, /** * Gets the current size of the component's underlying element. * @return {Object} An object containing the element's size {width: (element width), height: (element height)} */ getSize : function(){ return this.getResizeEl().getSize(); }, /** * Gets the current width of the component's underlying element. * @return {Number} */ getWidth : function(){ return this.getResizeEl().getWidth(); }, /** * Gets the current height of the component's underlying element. * @return {Number} */ getHeight : function(){ return this.getResizeEl().getHeight(); }, /** * Gets the current size of the component's underlying element, including space taken by its margins. * @return {Object} An object containing the element's size {width: (element width + left/right margins), height: (element height + top/bottom margins)} */ getOuterSize : function(){ var el = this.getResizeEl(); return {width: el.getWidth() + el.getMargins('lr'), height: el.getHeight() + el.getMargins('tb')}; }, /** * Gets the current XY position of the component's underlying element. * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false) * @return {Array} The XY position of the element (e.g., [100, 200]) */ getPosition : function(local){ var el = this.getPositionEl(); if(local === true){ return [el.getLeft(true), el.getTop(true)]; } return this.xy || el.getXY(); }, /** * Gets the current box measurements of the component's underlying element. * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false) * @return {Object} box An object in the format {x, y, width, height} */ getBox : function(local){ var pos = this.getPosition(local); var s = this.getSize(); s.x = pos[0]; s.y = pos[1]; return s; }, /** * Sets the current box measurements of the component's underlying element. * @param {Object} box An object in the format {x, y, width, height} * @return {Ext.BoxComponent} this */ updateBox : function(box){ this.setSize(box.width, box.height); this.setPagePosition(box.x, box.y); return this; }, /** * <p>Returns the outermost Element of this Component which defines the Components overall size.</p> * <p><i>Usually</i> this will return the same Element as <code>{@link #getEl}</code>, * but in some cases, a Component may have some more wrapping Elements around its main * active Element.</p> * <p>An example is a ComboBox. It is encased in a <i>wrapping</i> Element which * contains both the <code><input></code> Element (which is what would be returned * by its <code>{@link #getEl}</code> method, <i>and</i> the trigger button Element. * This Element is returned as the <code>resizeEl</code>. */ getResizeEl : function(){ return this.resizeEl || this.el; }, // protected getPositionEl : function(){ return this.positionEl || this.el; }, /** * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}. * This method fires the {@link #move} event. * @param {Number} left The new left * @param {Number} top The new top * @return {Ext.BoxComponent} this */ setPosition : function(x, y){ if(x && typeof x[1] == 'number'){ y = x[1]; x = x[0]; } this.x = x; this.y = y; if(!this.boxReady){ return this; } var adj = this.adjustPosition(x, y); var ax = adj.x, ay = adj.y; var el = this.getPositionEl(); if(ax !== undefined || ay !== undefined){ if(ax !== undefined && ay !== undefined){ el.setLeftTop(ax, ay); }else if(ax !== undefined){ el.setLeft(ax); }else if(ay !== undefined){ el.setTop(ay); } this.onPosition(ax, ay); this.fireEvent('move', this, ax, ay); } return this; }, /** * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}. * This method fires the {@link #move} event. * @param {Number} x The new x position * @param {Number} y The new y position * @return {Ext.BoxComponent} this */ setPagePosition : function(x, y){ if(x && typeof x[1] == 'number'){ y = x[1]; x = x[0]; } this.pageX = x; this.pageY = y; if(!this.boxReady){ return; } if(x === undefined || y === undefined){ // cannot translate undefined points return; } var p = this.getPositionEl().translatePoints(x, y); this.setPosition(p.left, p.top); return this; }, // private onRender : function(ct, position){ Ext.BoxComponent.superclass.onRender.call(this, ct, position); if(this.resizeEl){ this.resizeEl = Ext.get(this.resizeEl); } if(this.positionEl){ this.positionEl = Ext.get(this.positionEl); } }, // private afterRender : function(){ Ext.BoxComponent.superclass.afterRender.call(this); this.boxReady = true; this.setSize(this.width, this.height); if(this.x || this.y){ this.setPosition(this.x, this.y); }else if(this.pageX || this.pageY){ this.setPagePosition(this.pageX, this.pageY); } }, /** * Force the component's size to recalculate based on the underlying element's current height and width. * @return {Ext.BoxComponent} this */ syncSize : function(){ delete this.lastSize; this.setSize(this.autoWidth ? undefined : this.getResizeEl().getWidth(), this.autoHeight ? undefined : this.getResizeEl().getHeight()); return this; }, /* // protected * Called after the component is resized, this method is empty by default but can be implemented by any * subclass that needs to perform custom logic after a resize occurs. * @param {Number} adjWidth The box-adjusted width that was set * @param {Number} adjHeight The box-adjusted height that was set * @param {Number} rawWidth The width that was originally specified * @param {Number} rawHeight The height that was originally specified */ onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){ }, /* // protected * Called after the component is moved, this method is empty by default but can be implemented by any * subclass that needs to perform custom logic after a move occurs. * @param {Number} x The new x position * @param {Number} y The new y position */ onPosition : function(x, y){ }, // private adjustSize : function(w, h){ if(this.autoWidth){ w = 'auto'; } if(this.autoHeight){ h = 'auto'; } return {width : w, height: h}; }, // private adjustPosition : function(x, y){ return {x : x, y: y}; } }); Ext.reg('box', Ext.BoxComponent); /** * @class Ext.Spacer * @extends Ext.BoxComponent * <p>Used to provide a sizable space in a layout.</p> * @constructor * @param {Object} config */ Ext.Spacer = Ext.extend(Ext.BoxComponent, { autoEl:'div' }); Ext.reg('spacer', Ext.Spacer);/**
- * @class Ext.SplitBar
- * @extends Ext.util.Observable
- * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
- * <br><br>
- * Usage:
- * <pre><code>
- var split = new Ext.SplitBar("elementToDrag", "elementToSize",
- Ext.SplitBar.HORIZONTAL, Ext.SplitBar.LEFT);
- split.setAdapter(new Ext.SplitBar.AbsoluteLayoutAdapter("container"));
- split.minSize = 100;
- split.maxSize = 600;
- split.animate = true;
- split.on('moved', splitterMoved);
- </code></pre>
- * @constructor
- * Create a new SplitBar
- * @param {Mixed} dragElement The element to be dragged and act as the SplitBar.
- * @param {Mixed} resizingElement The element to be resized based on where the SplitBar element is dragged
- * @param {Number} orientation (optional) Either Ext.SplitBar.HORIZONTAL or Ext.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
- * @param {Number} placement (optional) Either Ext.SplitBar.LEFT or Ext.SplitBar.RIGHT for horizontal or
- Ext.SplitBar.TOP or Ext.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
- position of the SplitBar).
- */
- Ext.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
- /** @private */
- this.el = Ext.get(dragElement, true);
- this.el.dom.unselectable = "on";
- /** @private */
- this.resizingEl = Ext.get(resizingElement, true);
- /**
- * @private
- * The orientation of the split. Either Ext.SplitBar.HORIZONTAL or Ext.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
- * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
- * @type Number
- */
- this.orientation = orientation || Ext.SplitBar.HORIZONTAL;
- /**
- * The increment, in pixels by which to move this SplitBar. When <i>undefined</i>, the SplitBar moves smoothly.
- * @type Number
- * @property tickSize
- */
- /**
- * The minimum size of the resizing element. (Defaults to 0)
- * @type Number
- */
- this.minSize = 0;
- /**
- * The maximum size of the resizing element. (Defaults to 2000)
- * @type Number
- */
- this.maxSize = 2000;
- /**
- * Whether to animate the transition to the new size
- * @type Boolean
- */
- this.animate = false;
- /**
- * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
- * @type Boolean
- */
- this.useShim = false;
- /** @private */
- this.shim = null;
- if(!existingProxy){
- /** @private */
- this.proxy = Ext.SplitBar.createProxy(this.orientation);
- }else{
- this.proxy = Ext.get(existingProxy).dom;
- }
- /** @private */
- this.dd = new Ext.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
- /** @private */
- this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
- /** @private */
- this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
- /** @private */
- this.dragSpecs = {};
- /**
- * @private The adapter to use to positon and resize elements
- */
- this.adapter = new Ext.SplitBar.BasicLayoutAdapter();
- this.adapter.init(this);
- if(this.orientation == Ext.SplitBar.HORIZONTAL){
- /** @private */
- this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Ext.SplitBar.LEFT : Ext.SplitBar.RIGHT);
- this.el.addClass("x-splitbar-h");
- }else{
- /** @private */
- this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Ext.SplitBar.TOP : Ext.SplitBar.BOTTOM);
- this.el.addClass("x-splitbar-v");
- }
- this.addEvents(
- /**
- * @event resize
- * Fires when the splitter is moved (alias for {@link #moved})
- * @param {Ext.SplitBar} this
- * @param {Number} newSize the new width or height
- */
- "resize",
- /**
- * @event moved
- * Fires when the splitter is moved
- * @param {Ext.SplitBar} this
- * @param {Number} newSize the new width or height
- */
- "moved",
- /**
- * @event beforeresize
- * Fires before the splitter is dragged
- * @param {Ext.SplitBar} this
- */
- "beforeresize",
- "beforeapply"
- );
- Ext.SplitBar.superclass.constructor.call(this);
- };
- Ext.extend(Ext.SplitBar, Ext.util.Observable, {
- onStartProxyDrag : function(x, y){
- this.fireEvent("beforeresize", this);
- this.overlay = Ext.DomHelper.append(document.body, {cls: "x-drag-overlay", html: " "}, true);
- this.overlay.unselectable();
- this.overlay.setSize(Ext.lib.Dom.getViewWidth(true), Ext.lib.Dom.getViewHeight(true));
- this.overlay.show();
- Ext.get(this.proxy).setDisplayed("block");
- var size = this.adapter.getElementSize(this);
- this.activeMinSize = this.getMinimumSize();
- this.activeMaxSize = this.getMaximumSize();
- var c1 = size - this.activeMinSize;
- var c2 = Math.max(this.activeMaxSize - size, 0);
- if(this.orientation == Ext.SplitBar.HORIZONTAL){
- this.dd.resetConstraints();
- this.dd.setXConstraint(
- this.placement == Ext.SplitBar.LEFT ? c1 : c2,
- this.placement == Ext.SplitBar.LEFT ? c2 : c1,
- this.tickSize
- );
- this.dd.setYConstraint(0, 0);
- }else{
- this.dd.resetConstraints();
- this.dd.setXConstraint(0, 0);
- this.dd.setYConstraint(
- this.placement == Ext.SplitBar.TOP ? c1 : c2,
- this.placement == Ext.SplitBar.TOP ? c2 : c1,
- this.tickSize
- );
- }
- this.dragSpecs.startSize = size;
- this.dragSpecs.startPoint = [x, y];
- Ext.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
- },
- /**
- * @private Called after the drag operation by the DDProxy
- */
- onEndProxyDrag : function(e){
- Ext.get(this.proxy).setDisplayed(false);
- var endPoint = Ext.lib.Event.getXY(e);
- if(this.overlay){
- Ext.destroy(this.overlay);
- delete this.overlay;
- }
- var newSize;
- if(this.orientation == Ext.SplitBar.HORIZONTAL){
- newSize = this.dragSpecs.startSize +
- (this.placement == Ext.SplitBar.LEFT ?
- endPoint[0] - this.dragSpecs.startPoint[0] :
- this.dragSpecs.startPoint[0] - endPoint[0]
- );
- }else{
- newSize = this.dragSpecs.startSize +
- (this.placement == Ext.SplitBar.TOP ?
- endPoint[1] - this.dragSpecs.startPoint[1] :
- this.dragSpecs.startPoint[1] - endPoint[1]
- );
- }
- newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
- if(newSize != this.dragSpecs.startSize){
- if(this.fireEvent('beforeapply', this, newSize) !== false){
- this.adapter.setElementSize(this, newSize);
- this.fireEvent("moved", this, newSize);
- this.fireEvent("resize", this, newSize);
- }
- }
- },
- /**
- * Get the adapter this SplitBar uses
- * @return The adapter object
- */
- getAdapter : function(){
- return this.adapter;
- },
- /**
- * Set the adapter this SplitBar uses
- * @param {Object} adapter A SplitBar adapter object
- */
- setAdapter : function(adapter){
- this.adapter = adapter;
- this.adapter.init(this);
- },
- /**
- * Gets the minimum size for the resizing element
- * @return {Number} The minimum size
- */
- getMinimumSize : function(){
- return this.minSize;
- },
- /**
- * Sets the minimum size for the resizing element
- * @param {Number} minSize The minimum size
- */
- setMinimumSize : function(minSize){
- this.minSize = minSize;
- },
- /**
- * Gets the maximum size for the resizing element
- * @return {Number} The maximum size
- */
- getMaximumSize : function(){
- return this.maxSize;
- },
- /**
- * Sets the maximum size for the resizing element
- * @param {Number} maxSize The maximum size
- */
- setMaximumSize : function(maxSize){
- this.maxSize = maxSize;
- },
- /**
- * Sets the initialize size for the resizing element
- * @param {Number} size The initial size
- */
- setCurrentSize : function(size){
- var oldAnimate = this.animate;
- this.animate = false;
- this.adapter.setElementSize(this, size);
- this.animate = oldAnimate;
- },
- /**
- * Destroy this splitbar.
- * @param {Boolean} removeEl True to remove the element
- */
- destroy : function(removeEl){
- Ext.destroy(this.shim, Ext.get(this.proxy));
- this.dd.unreg();
- if(removeEl){
- this.el.remove();
- }
- this.purgeListeners();
- }
- });
- /**
- * @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.
- */
- Ext.SplitBar.createProxy = function(dir){
- var proxy = new Ext.Element(document.createElement("div"));
- proxy.unselectable();
- var cls = 'x-splitbar-proxy';
- proxy.addClass(cls + ' ' + (dir == Ext.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
- document.body.appendChild(proxy.dom);
- return proxy.dom;
- };
- /**
- * @class Ext.SplitBar.BasicLayoutAdapter
- * Default Adapter. It assumes the splitter and resizing element are not positioned
- * elements and only gets/sets the width of the element. Generally used for table based layouts.
- */
- Ext.SplitBar.BasicLayoutAdapter = function(){
- };
- Ext.SplitBar.BasicLayoutAdapter.prototype = {
- // do nothing for now
- init : function(s){
- },
- /**
- * Called before drag operations to get the current size of the resizing element.
- * @param {Ext.SplitBar} s The SplitBar using this adapter
- */
- getElementSize : function(s){
- if(s.orientation == Ext.SplitBar.HORIZONTAL){
- return s.resizingEl.getWidth();
- }else{
- return s.resizingEl.getHeight();
- }
- },
- /**
- * Called after drag operations to set the size of the resizing element.
- * @param {Ext.SplitBar} s The SplitBar using this adapter
- * @param {Number} newSize The new size to set
- * @param {Function} onComplete A function to be invoked when resizing is complete
- */
- setElementSize : function(s, newSize, onComplete){
- if(s.orientation == Ext.SplitBar.HORIZONTAL){
- if(!s.animate){
- s.resizingEl.setWidth(newSize);
- if(onComplete){
- onComplete(s, newSize);
- }
- }else{
- s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
- }
- }else{
- if(!s.animate){
- s.resizingEl.setHeight(newSize);
- if(onComplete){
- onComplete(s, newSize);
- }
- }else{
- s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
- }
- }
- }
- };
- /**
- *@class Ext.SplitBar.AbsoluteLayoutAdapter
- * @extends Ext.SplitBar.BasicLayoutAdapter
- * Adapter that moves the splitter element to align with the resized sizing element.
- * Used with an absolute positioned SplitBar.
- * @param {Mixed} container The container that wraps around the absolute positioned content. If it's
- * document.body, make sure you assign an id to the body element.
- */
- Ext.SplitBar.AbsoluteLayoutAdapter = function(container){
- this.basic = new Ext.SplitBar.BasicLayoutAdapter();
- this.container = Ext.get(container);
- };
- Ext.SplitBar.AbsoluteLayoutAdapter.prototype = {
- init : function(s){
- this.basic.init(s);
- },
- getElementSize : function(s){
- return this.basic.getElementSize(s);
- },
- setElementSize : function(s, newSize, onComplete){
- this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
- },
- moveSplitter : function(s){
- var yes = Ext.SplitBar;
- switch(s.placement){
- case yes.LEFT:
- s.el.setX(s.resizingEl.getRight());
- break;
- case yes.RIGHT:
- s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
- break;
- case yes.TOP:
- s.el.setY(s.resizingEl.getBottom());
- break;
- case yes.BOTTOM:
- s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
- break;
- }
- }
- };
- /**
- * Orientation constant - Create a vertical SplitBar
- * @static
- * @type Number
- */
- Ext.SplitBar.VERTICAL = 1;
- /**
- * Orientation constant - Create a horizontal SplitBar
- * @static
- * @type Number
- */
- Ext.SplitBar.HORIZONTAL = 2;
- /**
- * Placement constant - The resizing element is to the left of the splitter element
- * @static
- * @type Number
- */
- Ext.SplitBar.LEFT = 1;
- /**
- * Placement constant - The resizing element is to the right of the splitter element
- * @static
- * @type Number
- */
- Ext.SplitBar.RIGHT = 2;
- /**
- * Placement constant - The resizing element is positioned above the splitter element
- * @static
- * @type Number
- */
- Ext.SplitBar.TOP = 3;
- /**
- * Placement constant - The resizing element is positioned under splitter element
- * @static
- * @type Number
- */
- Ext.SplitBar.BOTTOM = 4;
- /** * @class Ext.Container * @extends Ext.BoxComponent * <p>Base class for any {@link Ext.BoxComponent} that may contain other Components. Containers handle the * basic behavior of containing items, namely adding, inserting and removing items.</p> * * <p>The most commonly used Container classes are {@link Ext.Panel}, {@link Ext.Window} and {@link Ext.TabPanel}. * If you do not need the capabilities offered by the aforementioned classes you can create a lightweight * Container to be encapsulated by an HTML element to your specifications by using the * <tt><b>{@link Ext.Component#autoEl autoEl}</b></tt> config option. This is a useful technique when creating * embedded {@link Ext.layout.ColumnLayout column} layouts inside {@link Ext.form.FormPanel FormPanels} * for example.</p> * * <p>The code below illustrates both how to explicitly create a Container, and how to implicitly * create one using the <b><tt>'container'</tt></b> xtype:<pre><code> // explicitly create a Container var embeddedColumns = new Ext.Container({ autoEl: 'div', // This is the default layout: 'column', defaults: { // implicitly create Container by specifying xtype xtype: 'container', autoEl: 'div', // This is the default. layout: 'form', columnWidth: 0.5, style: { padding: '10px' } }, // The two items below will be Ext.Containers, each encapsulated by a <DIV> element. items: [{ items: { xtype: 'datefield', name: 'startDate', fieldLabel: 'Start date' } }, { items: { xtype: 'datefield', name: 'endDate', fieldLabel: 'End date' } }] });</code></pre></p> * * <p><u><b>Layout</b></u></p> * <p>Container classes delegate the rendering of child Components to a layout * manager class which must be configured into the Container using the * <code><b>{@link #layout}</b></code> configuration property.</p> * <p>When either specifying child <code>{@link #items}</code> of a Container, * or dynamically {@link #add adding} Components to a Container, remember to * consider how you wish the Container to arrange those child elements, and * whether those child elements need to be sized using one of Ext's built-in * <b><code>{@link #layout}</code></b> schemes. By default, Containers use the * {@link Ext.layout.ContainerLayout ContainerLayout} scheme which only * renders child components, appending them one after the other inside the * Container, and <b>does not apply any sizing</b> at all.</p> * <p>A common mistake is when a developer neglects to specify a * <b><code>{@link #layout}</code></b> (e.g. widgets like GridPanels or * TreePanels are added to Containers for which no <tt><b>{@link #layout}</b></tt> * has been specified). If a Container is left to use the default * {@link Ext.layout.ContainerLayout ContainerLayout} scheme, none of its * child components will be resized, or changed in any way when the Container * is resized.</p> * <p>Certain layout managers allow dynamic addition of child components. * Those that do include {@link Ext.layout.CardLayout}, * {@link Ext.layout.AnchorLayout}, {@link Ext.layout.FormLayout}, and * {@link Ext.layout.TableLayout}. For example:<pre><code> // Create the GridPanel. var myNewGrid = new Ext.grid.GridPanel({ store: myStore, columns: myColumnModel, title: 'Results', // the title becomes the title of the tab }); myTabPanel.add(myNewGrid); // {@link Ext.TabPanel} implicitly uses {@link Ext.layout.CardLayout CardLayout} myTabPanel.{@link Ext.TabPanel#setActiveTab setActiveTab}(myNewGrid); * </code></pre></p> * <p>The example above adds a newly created GridPanel to a TabPanel. Note that * a TabPanel uses {@link Ext.layout.CardLayout} as its layout manager which * means all its child items are sized to {@link Ext.layout.FitLayout fit} * exactly into its client area. * <p><b><u>Overnesting is a common problem</u></b>. * An example of overnesting occurs when a GridPanel is added to a TabPanel * by wrapping the GridPanel <i>inside</i> a wrapping Panel (that has no * <tt><b>{@link #layout}</b></tt> specified) and then add that wrapping Panel * to the TabPanel. The point to realize is that a GridPanel <b>is</b> a * Component which can be added directly to a Container. If the wrapping Panel * has no <tt><b>{@link #layout}</b></tt> configuration, then the overnested * GridPanel will not be sized as expected.<p> </code></pre> * * <p><u><b>Adding via remote configuration</b></u></p> * * <p>A server side script can be used to add Components which are generated dynamically on the server. * An example of adding a GridPanel to a TabPanel where the GridPanel is generated by the server * based on certain parameters: * </p><pre><code> // execute an Ajax request to invoke server side script: Ext.Ajax.request({ url: 'gen-invoice-grid.php', // send additional parameters to instruct server script params: { startDate: Ext.getCmp('start-date').getValue(), endDate: Ext.getCmp('end-date').getValue() }, // process the response object to add it to the TabPanel: success: function(xhr) { var newComponent = eval(xhr.responseText); // see discussion below myTabPanel.add(newComponent); // add the component to the TabPanel myTabPanel.setActiveTab(newComponent); }, failure: function() { Ext.Msg.alert("Grid create failed", "Server communication failure"); } }); </code></pre> * <p>The server script needs to return an executable Javascript statement which, when processed * using <tt>eval()</tt>, will return either a config object with an {@link Ext.Component#xtype xtype}, * or an instantiated Component. The server might return this for example:</p><pre><code> (function() { function formatDate(value){ return value ? value.dateFormat('M d, Y') : ''; }; var store = new Ext.data.Store({ url: 'get-invoice-data.php', baseParams: { startDate: '01/01/2008', endDate: '01/31/2008' }, reader: new Ext.data.JsonReader({ record: 'transaction', idProperty: 'id', totalRecords: 'total' }, [ 'customer', 'invNo', {name: 'date', type: 'date', dateFormat: 'm/d/Y'}, {name: 'value', type: 'float'} ]) }); var grid = new Ext.grid.GridPanel({ title: 'Invoice Report', bbar: new Ext.PagingToolbar(store), store: store, columns: [ {header: "Customer", width: 250, dataIndex: 'customer', sortable: true}, {header: "Invoice Number", width: 120, dataIndex: 'invNo', sortable: true}, {header: "Invoice Date", width: 100, dataIndex: 'date', renderer: formatDate, sortable: true}, {header: "Value", width: 120, dataIndex: 'value', renderer: 'usMoney', sortable: true} ], }); store.load(); return grid; // return instantiated component })(); </code></pre> * <p>When the above code fragment is passed through the <tt>eval</tt> function in the success handler * of the Ajax request, the code is executed by the Javascript processor, and the anonymous function * runs, and returns the instantiated grid component.</p> * <p>Note: since the code above is <i>generated</i> by a server script, the <tt>baseParams</tt> for * the Store, the metadata to allow generation of the Record layout, and the ColumnModel * can all be generated into the code since these are all known on the server.</p> * * @xtype container */ Ext.Container = Ext.extend(Ext.BoxComponent, { /** * @cfg {Boolean} monitorResize * True to automatically monitor window resize events to handle anything that is sensitive to the current size * of the viewport. This value is typically managed by the chosen <code>{@link #layout}</code> and should not need * to be set manually. */ /** * @cfg {String/Object} layout * When creating complex UIs, it is important to remember that sizing and * positioning of child items is the responsibility of the Container's * layout manager. If you expect child items to be sized in response to * user interactions, <b>you must specify a layout manager</b> which * creates and manages the type of layout you have in mind. For example:<pre><code> new Ext.Window({ width:300, height: 300, layout: 'fit', // explicitly set layout manager: override the default (layout:'auto') items: [{ title: 'Panel inside a Window' }] }).show(); * </code></pre> * <p>Omitting the {@link #layout} config means that the * {@link Ext.layout.ContainerLayout default layout manager} will be used which does * nothing but render child components sequentially into the Container (no sizing or * positioning will be performed in this situation).</p> * <p>The layout manager class for this container may be specified as either as an * Object or as a String:</p> * <div><ul class="mdetail-params"> * * <li><u>Specify as an Object</u></li> * <div><ul class="mdetail-params"> * <li>Example usage:</li> <pre><code> layout: { type: 'vbox', padding: '5', align: 'left' } </code></pre> * * <li><tt><b>type</b></tt></li> * <br/><p>The layout type to be used for this container. If not specified, * a default {@link Ext.layout.ContainerLayout} will be created and used.</p> * <br/><p>Valid layout <tt>type</tt> values are:</p> * <div class="sub-desc"><ul class="mdetail-params"> * <li><tt><b>{@link Ext.layout.AbsoluteLayout absolute}</b></tt></li> * <li><tt><b>{@link Ext.layout.AccordionLayout accordion}</b></tt></li> * <li><tt><b>{@link Ext.layout.AnchorLayout anchor}</b></tt></li> * <li><tt><b>{@link Ext.layout.ContainerLayout auto}</b></tt> <b>Default</b></li> * <li><tt><b>{@link Ext.layout.BorderLayout border}</b></tt></li> * <li><tt><b>{@link Ext.layout.CardLayout card}</b></tt></li> * <li><tt><b>{@link Ext.layout.ColumnLayout column}</b></tt></li> * <li><tt><b>{@link Ext.layout.FitLayout fit}</b></tt></li> * <li><tt><b>{@link Ext.layout.FormLayout form}</b></tt></li> * <li><tt><b>{@link Ext.layout.HBoxLayout hbox}</b></tt></li> * <li><tt><b>{@link Ext.layout.MenuLayout menu}</b></tt></li> * <li><tt><b>{@link Ext.layout.TableLayout table}</b></tt></li> * <li><tt><b>{@link Ext.layout.ToolbarLayout toolbar}</b></tt></li> * <li><tt><b>{@link Ext.layout.VBoxLayout vbox}</b></tt></li> * </ul></div> * * <li>Layout specific configuration properties</li> * <br/><p>Additional layout specific configuration properties may also be * specified. For complete details regarding the valid config options for * each layout type, see the layout class corresponding to the <tt>type</tt> * specified.</p> * * </ul></div> * * <li><u>Specify as a String</u></li> * <div><ul class="mdetail-params"> * <li>Example usage:</li> <pre><code> layout: 'vbox', layoutConfig: { padding: '5', align: 'left' } </code></pre> * <li><tt><b>layout</b></tt></li> * <br/><p>The layout <tt>type</tt> to be used for this container (see list * of valid layout type values above).</p><br/> * <li><tt><b>{@link #layoutConfig}</b></tt></li> * <br/><p>Additional layout specific configuration properties. For complete * details regarding the valid config options for each layout type, see the * layout class corresponding to the <tt>layout</tt> specified.</p> * </ul></div></ul></div> */ /** * @cfg {Object} layoutConfig * This is a config object containing properties specific to the chosen * <b><code>{@link #layout}</code></b> if <b><code>{@link #layout}</code></b> * has been specified as a <i>string</i>.</p> */ /** * @cfg {Boolean/Number} bufferResize * When set to true (100 milliseconds) or a number of milliseconds, the layout assigned for this container will buffer * the frequency it calculates and does a re-layout of components. This is useful for heavy containers or containers * with a large quantity of sub-components for which frequent layout calls would be expensive. */ bufferResize: 100, /** * @cfg {String/Number} activeItem * A string component id or the numeric index of the component that should be initially activated within the * container's layout on render. For example, activeItem: 'item-1' or activeItem: 0 (index 0 = the first * item in the container's collection). activeItem only applies to layout styles that can display * items one at a time (like {@link Ext.layout.AccordionLayout}, {@link Ext.layout.CardLayout} and * {@link Ext.layout.FitLayout}). Related to {@link Ext.layout.ContainerLayout#activeItem}. */ /** * @cfg {Object/Array} items * <pre><b>** IMPORTANT</b>: be sure to specify a <b><code>{@link #layout}</code> ! **</b></pre> * <p>A single item, or an array of child Components to be added to this container, * for example:</p> * <pre><code> // specifying a single item items: {...}, layout: 'fit', // specify a layout! // specifying multiple items items: [{...}, {...}], layout: 'anchor', // specify a layout! * </code></pre> * <p>Each item may be:</p> * <div><ul class="mdetail-params"> * <li>any type of object based on {@link Ext.Component}</li> * <li>a fully instanciated object or</li> * <li>an object literal that:</li> * <div><ul class="mdetail-params"> * <li>has a specified <code>{@link Ext.Component#xtype xtype}</code></li> * <li>the {@link Ext.Component#xtype} specified is associated with the Component * desired and should be chosen from one of the available xtypes as listed * in {@link Ext.Component}.</li> * <li>If an <code>{@link Ext.Component#xtype xtype}</code> is not explicitly * specified, the {@link #defaultType} for that Container is used.</li> * <li>will be "lazily instanciated", avoiding the overhead of constructing a fully * instanciated Component object</li> * </ul></div></ul></div> * <p><b>Notes</b>:</p> * <div><ul class="mdetail-params"> * <li>Ext uses lazy rendering. Child Components will only be rendered * should it become necessary. Items are automatically laid out when they are first * shown (no sizing is done while hidden), or in response to a {@link #doLayout} call.</li> * <li>Do not specify <code>{@link Ext.Panel#contentEl contentEl}</code>/ * <code>{@link Ext.Panel#html html}</code> with <code>items</code>.</li> * </ul></div> */ /** * @cfg {Object} defaults * <p>A config object that will be applied to all components added to this container either via the {@link #items} * config or via the {@link #add} or {@link #insert} methods. The <tt>defaults</tt> config can contain any * number of name/value property pairs to be added to each item, and should be valid for the types of items * being added to the container. For example, to automatically apply padding to the body of each of a set of * contained {@link Ext.Panel} items, you could pass: <tt>defaults: {bodyStyle:'padding:15px'}</tt>.</p><br/> * <p><b>Note</b>: <tt>defaults</tt> will not be applied to config objects if the option is already specified. * For example:</p><pre><code> defaults: { // defaults are applied to items, not the container autoScroll:true }, items: [ { xtype: 'panel', // defaults <b>do not</b> have precedence over id: 'panel1', // options in config objects, so the defaults autoScroll: false // will not be applied here, panel1 will be autoScroll:false }, new Ext.Panel({ // defaults <b>do</b> have precedence over options id: 'panel2', // options in components, so the defaults autoScroll: false // will be applied here, panel2 will be autoScroll:true. }) ] * </code></pre> */ /** @cfg {Boolean} autoDestroy * If true the container will automatically destroy any contained component that is removed from it, else * destruction must be handled manually (defaults to true). */ autoDestroy : true, /** @cfg {Boolean} forceLayout * If true the container will force a layout initially even if hidden or collapsed. This option * is useful for forcing forms to render in collapsed or hidden containers. (defaults to false). */ forceLayout: false, /** @cfg {Boolean} hideBorders * True to hide the borders of each contained component, false to defer to the component's existing * border settings (defaults to false). */ /** @cfg {String} defaultType * <p>The default {@link Ext.Component xtype} of child Components to create in this Container when * a child item is specified as a raw configuration object, rather than as an instantiated Component.</p> * <p>Defaults to <tt>'panel'</tt>, except {@link Ext.menu.Menu} which defaults to <tt>'menuitem'</tt>, * and {@link Ext.Toolbar} and {@link Ext.ButtonGroup} which default to <tt>'button'</tt>.</p> */ defaultType : 'panel', // private initComponent : function(){ Ext.Container.superclass.initComponent.call(this); this.addEvents( /** * @event afterlayout * Fires when the components in this container are arranged by the associated layout manager. * @param {Ext.Container} this * @param {ContainerLayout} layout The ContainerLayout implementation for this container */ 'afterlayout', /** * @event beforeadd * Fires before any {@link Ext.Component} is added or inserted into the container. * A handler can return false to cancel the add. * @param {Ext.Container} this * @param {Ext.Component} component The component being added * @param {Number} index The index at which the component will be added to the container's items collection */ 'beforeadd', /** * @event beforeremove * Fires before any {@link Ext.Component} is removed from the container. A handler can return * false to cancel the remove. * @param {Ext.Container} this * @param {Ext.Component} component The component being removed */ 'beforeremove', /** * @event add * @bubbles * Fires after any {@link Ext.Component} is added or inserted into the container. * @param {Ext.Container} this * @param {Ext.Component} component The component that was added * @param {Number} index The index at which the component was added to the container's items collection */ 'add', /** * @event remove * @bubbles * Fires after any {@link Ext.Component} is removed from the container. * @param {Ext.Container} this * @param {Ext.Component} component The component that was removed */ 'remove' ); this.enableBubble('add', 'remove'); /** * The collection of components in this container as a {@link Ext.util.MixedCollection} * @type MixedCollection * @property items */ var items = this.items; if(items){ delete this.items; if(Ext.isArray(items) && items.length > 0){ this.add.apply(this, items); }else{ this.add(items); } } }, // private initItems : function(){ if(!this.items){ this.items = new Ext.util.MixedCollection(false, this.getComponentId); this.getLayout(); // initialize the layout } }, // private setLayout : function(layout){ if(this.layout && this.layout != layout){ this.layout.setContainer(null); } this.initItems(); this.layout = layout; layout.setContainer(this); }, // private render : function(){ Ext.Container.superclass.render.apply(this, arguments); if(this.layout){ if(Ext.isObject(this.layout) && !this.layout.layout){ this.layoutConfig = this.layout; this.layout = this.layoutConfig.type; } if(typeof this.layout == 'string'){ this.layout = new Ext.Container.LAYOUTS[this.layout.toLowerCase()](this.layoutConfig); } this.setLayout(this.layout); if(this.activeItem !== undefined){ var item = this.activeItem; delete this.activeItem; this.layout.setActiveItem(item); } } if(!this.ownerCt){ // force a layout if no ownerCt is set this.doLayout(false, true); } if(this.monitorResize === true){ Ext.EventManager.onWindowResize(this.doLayout, this, [false]); } }, /** * <p>Returns the Element to be used to contain the child Components of this Container.</p> * <p>An implementation is provided which returns the Container's {@link #getEl Element}, but * if there is a more complex structure to a Container, this may be overridden to return * the element into which the {@link #layout layout} renders child Components.</p> * @return {Ext.Element} The Element to render child Components into. */ getLayoutTarget : function(){ return this.el; }, // private - used as the key lookup function for the items collection getComponentId : function(comp){ return comp.getItemId(); }, /** * <p>Adds {@link Ext.Component Component}(s) to this Container.</p> * <br><p><b>Description</b></u> : * <div><ul class="mdetail-params"> * <li>Fires the {@link #beforeadd} event before adding</li> * <li>The Container's {@link #defaults default config values} will be applied * accordingly (see <code>{@link #defaults}</code> for details).</li> * <li>Fires the {@link #add} event after the component has been added.</li> * </ul></div> * <br><p><b>Notes</b></u> : * <div><ul class="mdetail-params"> * <li>If the Container is <i>already rendered</i> when <tt>add</tt> * is called, you may need to call {@link #doLayout} to refresh the view which causes * any unrendered child Components to be rendered. This is required so that you can * <tt>add</tt> multiple child components if needed while only refreshing the layout * once. For example:<pre><code> var tb = new {@link Ext.Toolbar}(); tb.render(document.body); // toolbar is rendered tb.add({text:'Button 1'}); // add multiple items ({@link #defaultType} for {@link Ext.Toolbar Toolbar} is 'button') tb.add({text:'Button 2'}); tb.{@link #doLayout}(); // refresh the layout * </code></pre></li> * <li><i>Warning:</i> Containers directly managed by the BorderLayout layout manager * may not be removed or added. See the Notes for {@link Ext.layout.BorderLayout BorderLayout} * for more details.</li> * </ul></div> * @param {Object/Array} component * <p>Either a single component or an Array of components to add. See * <code>{@link #items}</code> for additional information.</p> * @param {Object} (Optional) component_2 * @param {Object} (Optional) component_n * @return {Ext.Component} component The Component (or config object) that was added. */ add : function(comp){ this.initItems(); var args = arguments.length > 1; if(args || Ext.isArray(comp)){ Ext.each(args ? arguments : comp, function(c){ this.add(c); }, this); return; } var c = this.lookupComponent(this.applyDefaults(comp)); var pos = this.items.length; if(this.fireEvent('beforeadd', this, c, pos) !== false && this.onBeforeAdd(c) !== false){ this.items.add(c); c.ownerCt = this; this.fireEvent('add', this, c, pos); } return c; }, /** * Inserts a Component into this Container at a specified index. Fires the * {@link #beforeadd} event before inserting, then fires the {@link #add} event after the * Component has been inserted. * @param {Number} index The index at which the Component will be inserted * into the Container's items collection * @param {Ext.Component} component The child Component to insert.<br><br> * Ext uses lazy rendering, and will only render the inserted Component should * it become necessary.<br><br> * A Component config object may be passed in order to avoid the overhead of * constructing a real Component object if lazy rendering might mean that the * inserted Component will not be rendered immediately. To take advantage of * this 'lazy instantiation', set the {@link Ext.Component#xtype} config * property to the registered type of the Component wanted.<br><br> * For a list of all available xtypes, see {@link Ext.Component}. * @return {Ext.Component} component The Component (or config object) that was * inserted with the Container's default config values applied. */ insert : function(index, comp){ this.initItems(); var a = arguments, len = a.length; if(len > 2){ for(var i = len-1; i >= 1; --i) { this.insert(index, a[i]); } return; } var c = this.lookupComponent(this.applyDefaults(comp)); if(c.ownerCt == this && this.items.indexOf(c) < index){ --index; } if(this.fireEvent('beforeadd', this, c, index) !== false && this.onBeforeAdd(c) !== false){ this.items.insert(index, c); c.ownerCt = this; this.fireEvent('add', this, c, index); } return c; }, // private applyDefaults : function(c){ if(this.defaults){ if(typeof c == 'string'){ c = Ext.ComponentMgr.get(c); Ext.apply(c, this.defaults); }else if(!c.events){ Ext.applyIf(c, this.defaults); }else{ Ext.apply(c, this.defaults); } } return c; }, // private onBeforeAdd : function(item){ if(item.ownerCt){ item.ownerCt.remove(item, false); } if(this.hideBorders === true){ item.border = (item.border === true); } }, /** * Removes a component from this container. Fires the {@link #beforeremove} event before removing, then fires * the {@link #remove} event after the component has been removed. * @param {Component/String} component The component reference or id to remove. * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function. * Defaults to the value of this Container's {@link #autoDestroy} config. * @return {Ext.Component} component The Component that was removed. */ remove : function(comp, autoDestroy){ this.initItems(); var c = this.getComponent(comp); if(c && this.fireEvent('beforeremove', this, c) !== false){ this.items.remove(c); delete c.ownerCt; if(autoDestroy === true || (autoDestroy !== false && this.autoDestroy)){ c.destroy(); } if(this.layout && this.layout.activeItem == c){ delete this.layout.activeItem; } this.fireEvent('remove', this, c); } return c; }, /** * Removes all components from this container. * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function. * Defaults to the value of this Container's {@link #autoDestroy} config. * @return {Array} Array of the destroyed components */ removeAll: function(autoDestroy){ this.initItems(); var item, rem = [], items = []; this.items.each(function(i){ rem.push(i); }); for (var i = 0, len = rem.length; i < len; ++i){ item = rem[i]; this.remove(item, autoDestroy); if(item.ownerCt !== this){ items.push(item); } } return items; }, /** * Examines this container's <code>{@link #items}</code> <b>property</b> * and gets a direct child component of this container. * @param {String/Number} comp This parameter may be any of the following: * <div><ul class="mdetail-params"> * <li>a <b><tt>String</tt></b> : representing the <code>{@link Ext.Component#itemId itemId}</code> * or <code>{@link Ext.Component#id id}</code> of the child component </li> * <li>a <b><tt>Number</tt></b> : representing the position of the child component * within the <code>{@link #items}</code> <b>property</b></li> * </ul></div> * <p>For additional information see {@link Ext.util.MixedCollection#get}. * @return Ext.Component The component (if found). */ getComponent : function(comp){ if(Ext.isObject(comp)){ return comp; } return this.items.get(comp); }, // private lookupComponent : function(comp){ if(typeof comp == 'string'){ return Ext.ComponentMgr.get(comp); }else if(!comp.events){ return this.createComponent(comp); } return comp; }, // private createComponent : function(config){ return Ext.create(config, this.defaultType); }, /** * Force this container's layout to be recalculated. A call to this function is required after adding a new component * to an already rendered container, or possibly after changing sizing/position properties of child components. * @param {Boolean} shallow (optional) True to only calc the layout of this component, and let child components auto * calc layouts as required (defaults to false, which calls doLayout recursively for each subcontainer) * @param {Boolean} force (optional) True to force a layout to occur, even if the item is hidden. * @return {Ext.Container} this */ doLayout: function(shallow, force){ var rendered = this.rendered, forceLayout = this.forceLayout; if(!this.isVisible() || this.collapsed){ this.deferLayout = this.deferLayout || !shallow; if(!(force || forceLayout)){ return; } shallow = shallow && !this.deferLayout; } else { delete this.deferLayout; } if(rendered && this.layout){ this.layout.layout(); } if(shallow !== true && this.items){ var cs = this.items.items; for(var i = 0, len = cs.length; i < len; i++){ var c = cs[i]; if(c.doLayout){ c.forceLayout = forceLayout; c.doLayout(); } } } if(rendered){ this.onLayout(shallow, force); } delete this.forceLayout; }, //private onLayout : Ext.emptyFn, onShow : function(){ Ext.Container.superclass.onShow.call(this); if(this.deferLayout !== undefined){ this.doLayout(true); } }, /** * Returns the layout currently in use by the container. If the container does not currently have a layout * set, a default {@link Ext.layout.ContainerLayout} will be created and set as the container's layout. * @return {ContainerLayout} layout The container's layout */ getLayout : function(){ if(!this.layout){ var layout = new Ext.layout.ContainerLayout(this.layoutConfig); this.setLayout(layout); } return this.layout; }, // private beforeDestroy : function(){ if(this.items){ Ext.destroy.apply(Ext, this.items.items); } if(this.monitorResize){ Ext.EventManager.removeResizeListener(this.doLayout, this); } Ext.destroy(this.layout); Ext.Container.superclass.beforeDestroy.call(this); }, /** * Bubbles up the component/container heirarchy, calling the specified function with each component. The scope (<i>this</i>) of * function call will be the scope provided or the current component. The arguments to the function * will be the args provided or the current component. If the function returns false at any point, * the bubble is stopped. * @param {Function} fn The function to call * @param {Object} scope (optional) The scope of the function (defaults to current node) * @param {Array} args (optional) The args to call the function with (default to passing the current component) * @return {Ext.Container} this */ bubble : function(fn, scope, args){ var p = this; while(p){ if(fn.apply(scope || p, args || [p]) === false){ break; } p = p.ownerCt; } return this; }, /** * Cascades down the component/container heirarchy from this component (called first), calling the specified function with * each component. The scope (<i>this</i>) of * function call will be the scope provided or the current component. The arguments to the function * will be the args provided or the current component. If the function returns false at any point, * the cascade is stopped on that branch. * @param {Function} fn The function to call * @param {Object} scope (optional) The scope of the function (defaults to current component) * @param {Array} args (optional) The args to call the function with (defaults to passing the current component) * @return {Ext.Container} this */ cascade : function(fn, scope, args){ if(fn.apply(scope || this, args || [this]) !== false){ if(this.items){ var cs = this.items.items; for(var i = 0, len = cs.length; i < len; i++){ if(cs[i].cascade){ cs[i].cascade(fn, scope, args); }else{ fn.apply(scope || cs[i], args || [cs[i]]); } } } } return this; }, /** * Find a component under this container at any level by id * @param {String} id * @return Ext.Component */ findById : function(id){ var m, ct = this; this.cascade(function(c){ if(ct != c && c.id === id){ m = c; return false; } }); return m || null; }, /** * Find a component under this container at any level by xtype or class * @param {String/Class} xtype The xtype string for a component, or the class of the component directly * @param {Boolean} shallow (optional) False to check whether this Component is descended from the xtype (this is * the default), or true to check whether this Component is directly of the specified xtype. * @return {Array} Array of Ext.Components */ findByType : function(xtype, shallow){ return this.findBy(function(c){ return c.isXType(xtype, shallow); }); }, /** * Find a component under this container at any level by property * @param {String} prop * @param {String} value * @return {Array} Array of Ext.Components */ find : function(prop, value){ return this.findBy(function(c){ return c[prop] === value; }); }, /** * Find a component under this container at any level by a custom function. If the passed function returns * true, the component will be included in the results. The passed function is called with the arguments (component, this container). * @param {Function} fn The function to call * @param {Object} scope (optional) * @return {Array} Array of Ext.Components */ findBy : function(fn, scope){ var m = [], ct = this; this.cascade(function(c){ if(ct != c && fn.call(scope || c, c, ct) === true){ m.push(c); } }); return m; }, /** * Get a component contained by this container (alias for items.get(key)) * @param {String/Number} key The index or id of the component * @return {Ext.Component} Ext.Component */ get : function(key){ return this.items.get(key); } }); Ext.Container.LAYOUTS = {}; Ext.reg('container', Ext.Container); /** * @class Ext.layout.ContainerLayout * <p>The ContainerLayout class is the default layout manager delegated by {@link Ext.Container} to * render any child Components when no <tt>{@link Ext.Container#layout layout}</tt> is configured into * a {@link Ext.Container Container}. ContainerLayout provides the basic foundation for all other layout * classes in Ext. It simply renders all child Components into the Container, performing no sizing or * positioning services. To utilize a layout that provides sizing and positioning of child Components, * specify an appropriate <tt>{@link Ext.Container#layout layout}</tt>.</p> * <p>This class is intended to be extended or created via the <tt><b>{@link Ext.Container#layout layout}</b></tt> * configuration property. See <tt><b>{@link Ext.Container#layout}</b></tt> for additional details.</p> */ Ext.layout.ContainerLayout = function(config){ Ext.apply(this, config); }; Ext.layout.ContainerLayout.prototype = { /** * @cfg {String} extraCls * <p>An optional extra CSS class that will be added to the container. This can be useful for adding * customized styles to the container or any of its children using standard CSS rules. See * {@link Ext.Component}.{@link Ext.Component#ctCls ctCls} also.</p> * <p><b>Note</b>: <tt>extraCls</tt> defaults to <tt>''</tt> except for the following classes * which assign a value by default: * <div class="mdetail-params"><ul> * <li>{@link Ext.layout.AbsoluteLayout Absolute Layout} : <tt>'x-abs-layout-item'</tt></li> * <li>{@link Ext.layout.Box Box Layout} : <tt>'x-box-item'</tt></li> * <li>{@link Ext.layout.ColumnLayout Column Layout} : <tt>'x-column'</tt></li> * </ul></div> * To configure the above Classes with an extra CSS class append to the default. For example, * for ColumnLayout:<pre><code> * extraCls: 'x-column custom-class' * </code></pre> * </p> */ /** * @cfg {Boolean} renderHidden * True to hide each contained item on render (defaults to false). */ /** * A reference to the {@link Ext.Component} that is active. For example, <pre><code> * if(myPanel.layout.activeItem.id == 'item-1') { ... } * </code></pre> * <tt>activeItem</tt> only applies to layout styles that can display items one at a time * (like {@link Ext.layout.AccordionLayout}, {@link Ext.layout.CardLayout} * and {@link Ext.layout.FitLayout}). Read-only. Related to {@link Ext.Container#activeItem}. * @type {Ext.Component} * @property activeItem */ // private monitorResize:false, // private activeItem : null, // private layout : function(){ var target = this.container.getLayoutTarget(); this.onLayout(this.container, target); this.container.fireEvent('afterlayout', this.container, this); }, // private onLayout : function(ct, target){ this.renderAll(ct, target); }, // private isValidParent : function(c, target){ return target && c.getDomPositionEl().dom.parentNode == (target.dom || target); }, // private renderAll : function(ct, target){ var items = ct.items.items; for(var i = 0, len = items.length; i < len; i++) { var c = items[i]; if(c && (!c.rendered || !this.isValidParent(c, target))){ this.renderItem(c, i, target); } } }, // private renderItem : function(c, position, target){ if(c && !c.rendered){ c.render(target, position); this.configureItem(c, position); }else if(c && !this.isValidParent(c, target)){ if(typeof position == 'number'){ position = target.dom.childNodes[position]; } target.dom.insertBefore(c.getDomPositionEl().dom, position || null); c.container = target; this.configureItem(c, position); } }, // private configureItem: function(c, position){ if(this.extraCls){ var t = c.getPositionEl ? c.getPositionEl() : c; t.addClass(this.extraCls); } if (this.renderHidden && c != this.activeItem) { c.hide(); } if(c.doLayout){ c.doLayout(false, this.forceLayout); } }, // private onResize: function(){ if(this.container.collapsed){ return; } var b = this.container.bufferResize; if(b){ if(!this.resizeTask){ this.resizeTask = new Ext.util.DelayedTask(this.runLayout, this); this.resizeBuffer = typeof b == 'number' ? b : 100; } this.resizeTask.delay(this.resizeBuffer); }else{ this.runLayout(); } }, // private runLayout: function(){ this.layout(); this.container.onLayout(); }, // private setContainer : function(ct){ if(this.monitorResize && ct != this.container){ if(this.container){ this.container.un('resize', this.onResize, this); this.container.un('bodyresize', this.onResize, this); } if(ct){ ct.on({ scope: this, resize: this.onResize, bodyresize: this.onResize }); } } this.container = ct; }, // private parseMargins : function(v){ if(typeof v == 'number'){ v = v.toString(); } var ms = v.split(' '); var len = ms.length; if(len == 1){ ms[1] = ms[0]; ms[2] = ms[0]; ms[3] = ms[0]; } if(len == 2){ ms[2] = ms[0]; ms[3] = ms[1]; } if(len == 3){ ms[3] = ms[1]; } return { top:parseInt(ms[0], 10) || 0, right:parseInt(ms[1], 10) || 0, bottom:parseInt(ms[2], 10) || 0, left:parseInt(ms[3], 10) || 0 }; }, /** * The {@link Template Ext.Template} used by Field rendering layout classes (such as * {@link Ext.layout.FormLayout}) to create the DOM structure of a fully wrapped, * labeled and styled form Field. A default Template is supplied, but this may be * overriden to create custom field structures. The template processes values returned from * {@link Ext.layout.FormLayout#getTemplateArgs}. * @property fieldTpl * @type Ext.Template */ fieldTpl: (function() { var t = new Ext.Template( '<div class="x-form-item {itemCls}" tabIndex="-1">', '<label for="{id}" style="{labelStyle}" class="x-form-item-label">{label}{labelSeparator}</label>', '<div class="x-form-element" id="x-form-el-{id}" style="{elementStyle}">', '</div><div class="{clearCls}"></div>', '</div>' ); t.disableFormats = true; return t.compile(); })(), /* * Destroys this layout. This is a template method that is empty by default, but should be implemented * by subclasses that require explicit destruction to purge event handlers or remove DOM nodes. * @protected */ destroy : Ext.emptyFn }; Ext.Container.LAYOUTS['auto'] = Ext.layout.ContainerLayout;/**
- * @class Ext.layout.FitLayout
- * @extends Ext.layout.ContainerLayout
- * <p>This is a base class for layouts that contain <b>a single item</b> that automatically expands to fill the layout's
- * container. This class is intended to be extended or created via the <tt>layout:'fit'</tt> {@link Ext.Container#layout}
- * config, and should generally not need to be created directly via the new keyword.</p>
- * <p>FitLayout does not have any direct config options (other than inherited ones). To fit a panel to a container
- * using FitLayout, simply set layout:'fit' on the container and add a single panel to it. If the container has
- * multiple panels, only the first one will be displayed. Example usage:</p>
- * <pre><code>
- var p = new Ext.Panel({
- title: 'Fit Layout',
- layout:'fit',
- items: {
- title: 'Inner Panel',
- html: '<p>This is the inner panel content</p>',
- border: false
- }
- });
- </code></pre>
- */
- Ext.layout.FitLayout = Ext.extend(Ext.layout.ContainerLayout, {
- // private
- monitorResize:true,
- // private
- onLayout : function(ct, target){
- Ext.layout.FitLayout.superclass.onLayout.call(this, ct, target);
- if(!this.container.collapsed){
- var sz = (Ext.isIE6 && Ext.isStrict && target.dom == document.body) ? target.getViewSize() : target.getStyleSize();
- this.setItemSize(this.activeItem || ct.items.itemAt(0), sz);
- }
- },
- // private
- setItemSize : function(item, size){
- if(item && size.height > 0){ // display none?
- item.setSize(size);
- }
- }
- });
- Ext.Container.LAYOUTS['fit'] = Ext.layout.FitLayout;/**
- * @class Ext.layout.CardLayout
- * @extends Ext.layout.FitLayout
- * <p>This layout manages multiple child Components, each fitted to the Container, where only a single child Component can be
- * visible at any given time. This layout style is most commonly used for wizards, tab implementations, etc.
- * This class is intended to be extended or created via the layout:'card' {@link Ext.Container#layout} config,
- * and should generally not need to be created directly via the new keyword.</p>
- * <p>The CardLayout's focal method is {@link #setActiveItem}. Since only one panel is displayed at a time,
- * the only way to move from one Component to the next is by calling setActiveItem, passing the id or index of
- * the next panel to display. The layout itself does not provide a user interface for handling this navigation,
- * so that functionality must be provided by the developer.</p>
- * <p>In the following example, a simplistic wizard setup is demonstrated. A button bar is added
- * to the footer of the containing panel to provide navigation buttons. The buttons will be handled by a
- * common navigation routine -- for this example, the implementation of that routine has been ommitted since
- * it can be any type of custom logic. Note that other uses of a CardLayout (like a tab control) would require a
- * completely different implementation. For serious implementations, a better approach would be to extend
- * CardLayout to provide the custom functionality needed. Example usage:</p>
- * <pre><code>
- var navHandler = function(direction){
- // This routine could contain business logic required to manage the navigation steps.
- // It would call setActiveItem as needed, manage navigation button state, handle any
- // branching logic that might be required, handle alternate actions like cancellation
- // or finalization, etc. A complete wizard implementation could get pretty
- // sophisticated depending on the complexity required, and should probably be
- // done as a subclass of CardLayout in a real-world implementation.
- };
- var card = new Ext.Panel({
- title: 'Example Wizard',
- layout:'card',
- activeItem: 0, // make sure the active item is set on the container config!
- bodyStyle: 'padding:15px',
- defaults: {
- // applied to each contained panel
- border:false
- },
- // just an example of one possible navigation scheme, using buttons
- bbar: [
- {
- id: 'move-prev',
- text: 'Back',
- handler: navHandler.createDelegate(this, [-1]),
- disabled: true
- },
- '->', // greedy spacer so that the buttons are aligned to each side
- {
- id: 'move-next',
- text: 'Next',
- handler: navHandler.createDelegate(this, [1])
- }
- ],
- // the panels (or "cards") within the layout
- items: [{
- id: 'card-0',
- html: '<h1>Welcome to the Wizard!</h1><p>Step 1 of 3</p>'
- },{
- id: 'card-1',
- html: '<p>Step 2 of 3</p>'
- },{
- id: 'card-2',
- html: '<h1>Congratulations!</h1><p>Step 3 of 3 - Complete</p>'
- }]
- });
- </code></pre>
- */
- Ext.layout.CardLayout = Ext.extend(Ext.layout.FitLayout, {
- /**
- * @cfg {Boolean} deferredRender
- * True to render each contained item at the time it becomes active, false to render all contained items
- * as soon as the layout is rendered (defaults to false). If there is a significant amount of content or
- * a lot of heavy controls being rendered into panels that are not displayed by default, setting this to
- * true might improve performance.
- */
- deferredRender : false,
- /**
- * @cfg {Boolean} layoutOnCardChange
- * True to force a layout of the active item when the active card is changed. Defaults to false.
- */
- layoutOnCardChange : false,
- /**
- * @cfg {Boolean} renderHidden @hide
- */
- // private
- renderHidden : true,
- constructor: function(config){
- Ext.layout.CardLayout.superclass.constructor.call(this, config);
- this.forceLayout = (this.deferredRender === false);
- },
- /**
- * Sets the active (visible) item in the layout.
- * @param {String/Number} item The string component id or numeric index of the item to activate
- */
- setActiveItem : function(item){
- item = this.container.getComponent(item);
- if(this.activeItem != item){
- if(this.activeItem){
- this.activeItem.hide();
- }
- this.activeItem = item;
- item.show();
- this.container.doLayout();
- if(this.layoutOnCardChange && item.doLayout){
- item.doLayout();
- }
- }
- },
- // private
- renderAll : function(ct, target){
- if(this.deferredRender){
- this.renderItem(this.activeItem, undefined, target);
- }else{
- Ext.layout.CardLayout.superclass.renderAll.call(this, ct, target);
- }
- }
- });
- Ext.Container.LAYOUTS['card'] = Ext.layout.CardLayout;/**
- * @class Ext.layout.AnchorLayout
- * @extends Ext.layout.ContainerLayout
- * <p>This is a layout that enables anchoring of contained elements relative to the container's dimensions.
- * If the container is resized, all anchored items are automatically rerendered according to their
- * <b><tt>{@link #anchor}</tt></b> rules.</p>
- * <p>This class is intended to be extended or created via the layout:'anchor' {@link Ext.Container#layout}
- * config, and should generally not need to be created directly via the new keyword.</p>
- * <p>AnchorLayout does not have any direct config options (other than inherited ones). By default,
- * AnchorLayout will calculate anchor measurements based on the size of the container itself. However, the
- * container using the AnchorLayout can supply an anchoring-specific config property of <b>anchorSize</b>.
- * If anchorSize is specifed, the layout will use it as a virtual container for the purposes of calculating
- * anchor measurements based on it instead, allowing the container to be sized independently of the anchoring
- * logic if necessary. For example:</p>
- * <pre><code>
- var viewport = new Ext.Viewport({
- layout:'anchor',
- anchorSize: {width:800, height:600},
- items:[{
- title:'Item 1',
- html:'Content 1',
- width:800,
- anchor:'right 20%'
- },{
- title:'Item 2',
- html:'Content 2',
- width:300,
- anchor:'50% 30%'
- },{
- title:'Item 3',
- html:'Content 3',
- width:600,
- anchor:'-100 50%'
- }]
- });
- * </code></pre>
- */
- Ext.layout.AnchorLayout = Ext.extend(Ext.layout.ContainerLayout, {
- /**
- * @cfg {String} anchor
- * <p>This configuation option is to be applied to <b>child <tt>items</tt></b> of a container managed by
- * this layout (ie. configured with <tt>layout:'anchor'</tt>).</p><br/>
- *
- * <p>This value is what tells the layout how an item should be anchored to the container. <tt>items</tt>
- * added to an AnchorLayout accept an anchoring-specific config property of <b>anchor</b> which is a string
- * containing two values: the horizontal anchor value and the vertical anchor value (for example, '100% 50%').
- * The following types of anchor values are supported:<div class="mdetail-params"><ul>
- *
- * <li><b>Percentage</b> : Any value between 1 and 100, expressed as a percentage.<div class="sub-desc">
- * The first anchor is the percentage width that the item should take up within the container, and the
- * second is the percentage height. For example:<pre><code>
- // two values specified
- anchor: '100% 50%' // render item complete width of the container and
- // 1/2 height of the container
- // one value specified
- anchor: '100%' // the width value; the height will default to auto
- * </code></pre></div></li>
- *
- * <li><b>Offsets</b> : Any positive or negative integer value.<div class="sub-desc">
- * This is a raw adjustment where the first anchor is the offset from the right edge of the container,
- * and the second is the offset from the bottom edge. For example:<pre><code>
- // two values specified
- anchor: '-50 -100' // render item the complete width of the container
- // minus 50 pixels and
- // the complete height minus 100 pixels.
- // one value specified
- anchor: '-50' // anchor value is assumed to be the right offset value
- // bottom offset will default to 0
- * </code></pre></div></li>
- *
- * <li><b>Sides</b> : Valid values are <tt>'right'</tt> (or <tt>'r'</tt>) and <tt>'bottom'</tt>
- * (or <tt>'b'</tt>).<div class="sub-desc">
- * Either the container must have a fixed size or an anchorSize config value defined at render time in
- * order for these to have any effect.</div></li>
- *
- * <li><b>Mixed</b> : <div class="sub-desc">
- * Anchor values can also be mixed as needed. For example, to render the width offset from the container
- * right edge by 50 pixels and 75% of the container's height use:
- * <pre><code>
- anchor: '-50 75%'
- * </code></pre></div></li>
- *
- *
- * </ul></div>
- */
- // private
- monitorResize:true,
- // private
- getAnchorViewSize : function(ct, target){
- return target.dom == document.body ?
- target.getViewSize() : target.getStyleSize();
- },
- // private
- onLayout : function(ct, target){
- Ext.layout.AnchorLayout.superclass.onLayout.call(this, ct, target);
- var size = this.getAnchorViewSize(ct, target);
- var w = size.width, h = size.height;
- if(w < 20 && h < 20){
- return;
- }
- // find the container anchoring size
- var aw, ah;
- if(ct.anchorSize){
- if(typeof ct.anchorSize == 'number'){
- aw = ct.anchorSize;
- }else{
- aw = ct.anchorSize.width;
- ah = ct.anchorSize.height;
- }
- }else{
- aw = ct.initialConfig.width;
- ah = ct.initialConfig.height;
- }
- var cs = ct.items.items, len = cs.length, i, c, a, cw, ch;
- for(i = 0; i < len; i++){
- c = cs[i];
- if(c.anchor){
- a = c.anchorSpec;
- if(!a){ // cache all anchor values
- var vs = c.anchor.split(' ');
- c.anchorSpec = a = {
- right: this.parseAnchor(vs[0], c.initialConfig.width, aw),
- bottom: this.parseAnchor(vs[1], c.initialConfig.height, ah)
- };
- }
- cw = a.right ? this.adjustWidthAnchor(a.right(w), c) : undefined;
- ch = a.bottom ? this.adjustHeightAnchor(a.bottom(h), c) : undefined;
- if(cw || ch){
- c.setSize(cw || undefined, ch || undefined);
- }
- }
- }
- },
- // private
- parseAnchor : function(a, start, cstart){
- if(a && a != 'none'){
- var last;
- if(/^(r|right|b|bottom)$/i.test(a)){ // standard anchor
- var diff = cstart - start;
- return function(v){
- if(v !== last){
- last = v;
- return v - diff;
- }
- }
- }else if(a.indexOf('%') != -1){
- var ratio = parseFloat(a.replace('%', ''))*.01; // percentage
- return function(v){
- if(v !== last){
- last = v;
- return Math.floor(v*ratio);
- }
- }
- }else{
- a = parseInt(a, 10);
- if(!isNaN(a)){ // simple offset adjustment
- return function(v){
- if(v !== last){
- last = v;
- return v + a;
- }
- }
- }
- }
- }
- return false;
- },
- // private
- adjustWidthAnchor : function(value, comp){
- return value;
- },
- // private
- adjustHeightAnchor : function(value, comp){
- return value;
- }
- /**
- * @property activeItem
- * @hide
- */
- });
- Ext.Container.LAYOUTS['anchor'] = Ext.layout.AnchorLayout;/**
- * @class Ext.layout.ColumnLayout
- * @extends Ext.layout.ContainerLayout
- * <p>This is the layout style of choice for creating structural layouts in a multi-column format where the width of
- * each column can be specified as a percentage or fixed width, but the height is allowed to vary based on the content.
- * This class is intended to be extended or created via the layout:'column' {@link Ext.Container#layout} config,
- * and should generally not need to be created directly via the new keyword.</p>
- * <p>ColumnLayout does not have any direct config options (other than inherited ones), but it does support a
- * specific config property of <b><tt>columnWidth</tt></b> that can be included in the config of any panel added to it. The
- * layout will use the columnWidth (if present) or width of each panel during layout to determine how to size each panel.
- * If width or columnWidth is not specified for a given panel, its width will default to the panel's width (or auto).</p>
- * <p>The width property is always evaluated as pixels, and must be a number greater than or equal to 1.
- * The columnWidth property is always evaluated as a percentage, and must be a decimal value greater than 0 and
- * less than 1 (e.g., .25).</p>
- * <p>The basic rules for specifying column widths are pretty simple. The logic makes two passes through the
- * set of contained panels. During the first layout pass, all panels that either have a fixed width or none
- * specified (auto) are skipped, but their widths are subtracted from the overall container width. During the second
- * pass, all panels with columnWidths are assigned pixel widths in proportion to their percentages based on
- * the total <b>remaining</b> container width. In other words, percentage width panels are designed to fill the space
- * left over by all the fixed-width and/or auto-width panels. Because of this, while you can specify any number of columns
- * with different percentages, the columnWidths must always add up to 1 (or 100%) when added together, otherwise your
- * layout may not render as expected. Example usage:</p>
- * <pre><code>
- // All columns are percentages -- they must add up to 1
- var p = new Ext.Panel({
- title: 'Column Layout - Percentage Only',
- layout:'column',
- items: [{
- title: 'Column 1',
- columnWidth: .25
- },{
- title: 'Column 2',
- columnWidth: .6
- },{
- title: 'Column 3',
- columnWidth: .15
- }]
- });
- // Mix of width and columnWidth -- all columnWidth values must add up
- // to 1. The first column will take up exactly 120px, and the last two
- // columns will fill the remaining container width.
- var p = new Ext.Panel({
- title: 'Column Layout - Mixed',
- layout:'column',