X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/7a654f8d43fdb43d78b63d90528bed6e86b608cc..3789b528d8dd8aad4558e38e22d775bcab1cbd36:/pkgs/classes.js diff --git a/pkgs/classes.js b/pkgs/classes.js index 3e8f2d94..c08d63df 100644 --- a/pkgs/classes.js +++ b/pkgs/classes.js @@ -11,7 +11,8 @@ licensing@sencha.com * with configured listeners defined.
* For example: *

-Employee = Ext.extend(Ext.util.Observable, {
+Ext.define('Employee', {
+    extend: 'Ext.util.Observable',
     constructor: function(config){
         this.name = config.name;
         this.addEvents({
@@ -212,7 +213,6 @@ new Ext.panel.Panel({
             options,
             config,
             managedListeners,
-            managedListener,
             length,
             i;
 
@@ -229,14 +229,9 @@ new Ext.panel.Panel({
         }
 
         managedListeners = me.managedListeners ? me.managedListeners.slice() : [];
-        length = managedListeners.length;
 
-        for (i = 0; i < length; i++) {
-            managedListener = managedListeners[i];
-            if (managedListener.item === item && managedListener.ename === ename && (!fn || managedListener.fn === fn) && (!scope || managedListener.scope === scope)) {
-                Ext.Array.remove(me.managedListeners, managedListener);
-                item.un(managedListener.ename, managedListener.fn, managedListener.scope);
-            }
+        for (i = 0, length = managedListeners.length; i < length; i++) {
+            me.removeManagedListenerItem(false, managedListeners[i], item, ename, fn, scope);
         }
     },
 
@@ -385,7 +380,7 @@ myGridPanel.on({
         } else {
             ename = ename.toLowerCase();
             event = me.events[ename];
-            if (event.isEvent) {
+            if (event && event.isEvent) {
                 event.removeListener(fn, scope);
             }
         }
@@ -413,7 +408,9 @@ myGridPanel.on({
 
     //
     purgeListeners : function() {
-        console.warn('Observable: purgeListeners has been deprecated. Please use clearListeners.');
+        if (Ext.global.console) {
+            Ext.global.console.warn('Observable: purgeListeners has been deprecated. Please use clearListeners.');
+        }
         return this.clearListeners.apply(this, arguments);
     },
     //
@@ -424,20 +421,36 @@ myGridPanel.on({
     clearManagedListeners : function() {
         var managedListeners = this.managedListeners || [],
             i = 0,
-            len = managedListeners.length,
-            managedListener;
+            len = managedListeners.length;
 
         for (; i < len; i++) {
-            managedListener = managedListeners[i];
-            managedListener.item.un(managedListener.ename, managedListener.fn, managedListener.scope);
+            this.removeManagedListenerItem(true, managedListeners[i]);
         }
 
         this.managedListeners = [];
     },
+    
+    /**
+     * Remove a single managed listener item
+     * @private
+     * @param {Boolean} isClear True if this is being called during a clear
+     * @param {Object} managedListener The managed listener item
+     * See removeManagedListener for other args
+     */
+    removeManagedListenerItem: function(isClear, managedListener, item, ename, fn, scope){
+        if (isClear || (managedListener.item === item && managedListener.ename === ename && (!fn || managedListener.fn === fn) && (!scope || managedListener.scope === scope))) {
+            managedListener.item.un(managedListener.ename, managedListener.fn, managedListener.scope);
+            if (!isClear) {
+                Ext.Array.remove(this.managedListeners, managedListener);
+            }    
+        }
+    },
 
     //
     purgeManagedListeners : function() {
-        console.warn('Observable: purgeManagedListeners has been deprecated. Please use clearManagedListeners.');
+        if (Ext.global.console) {
+            Ext.global.console.warn('Observable: purgeManagedListeners has been deprecated. Please use clearManagedListeners.');
+        }
         return this.clearManagedListeners.apply(this, arguments);
     },
     //
@@ -1068,48 +1081,53 @@ myWindow.header.el.on('click', function() {
     },
 
     /**
+     * @deprecated 4.0 Replaced by {@link #stopAnimation}
      * Stops any running effects and clears this object's internal effects queue if it contains
      * any additional effects that haven't started yet.
      * @return {Ext.core.Element} The Element
+     * @method
      */
     stopFx: Ext.Function.alias(Ext.util.Animate, 'stopAnimation'),
 
     /**
-     * @deprecated 4.0 Replaced by {@link #stopAnimation}
      * Stops any running effects and clears this object's internal effects queue if it contains
      * any additional effects that haven't started yet.
      * @return {Ext.core.Element} The Element
      */
     stopAnimation: function() {
         Ext.fx.Manager.stopAnimation(this.id);
+        return this;
     },
 
     /**
      * Ensures that all effects queued after syncFx is called on this object are
      * run concurrently.  This is the opposite of {@link #sequenceFx}.
-     * @return {Ext.core.Element} The Element
+     * @return {Object} this
      */
     syncFx: function() {
         Ext.fx.Manager.setFxDefaults(this.id, {
             concurrent: true
         });
+        return this;
     },
 
     /**
      * Ensures that all effects queued after sequenceFx is called on this object are
      * run in sequence.  This is the opposite of {@link #syncFx}.
-     * @return {Ext.core.Element} The Element
+     * @return {Object} this
      */
     sequenceFx: function() {
         Ext.fx.Manager.setFxDefaults(this.id, {
             concurrent: false
         });
+        return this;
     },
 
     /**
      * @deprecated 4.0 Replaced by {@link #getActiveAnimation}
      * Returns thq current animation if this object has any effects actively running or queued, else returns false.
      * @return {Mixed} anim if element has active effects, else false
+     * @method
      */
     hasActiveFx: Ext.Function.alias(Ext.util.Animate, 'getActiveAnimation'),
 
@@ -2286,7 +2304,6 @@ Ext.define('Ext.ComponentQuery', {
          * 

This parameter may also be an array of Components to filter according to the selector.

* @returns {Array} The matched Components. * @member Ext.ComponentQuery - * @method query */ query: function(selector, root) { var selectors = selector.split(','), @@ -2328,7 +2345,6 @@ Ext.define('Ext.ComponentQuery', { * @param selector The selector string to test against. * @return {Boolean} True if the Component matches the selector. * @member Ext.ComponentQuery - * @method query */ is: function(component, selector) { if (!selector) { @@ -3341,13 +3357,13 @@ Ext.define('Ext.layout.component.Component', { ownerElChild = owner.el.child, layoutCollection; - /** - * Do not layout calculatedSized components for fixedLayouts unless the ownerCt == layoutOwner - * fixedLayouts means layouts which are never auto/auto in the sizing that comes from their ownerCt. - * Currently 3 layouts MAY be auto/auto (Auto, Border, and Box) - * The reason for not allowing component layouts is to stop component layouts from things such as Updater and - * form Validation. - */ + /* + * Do not layout calculatedSized components for fixedLayouts unless the ownerCt == layoutOwner + * fixedLayouts means layouts which are never auto/auto in the sizing that comes from their ownerCt. + * Currently 3 layouts MAY be auto/auto (Auto, Border, and Box) + * The reason for not allowing component layouts is to stop component layouts from things such as Updater and + * form Validation. + */ if (!isSetSize && !(Ext.isNumber(width) && Ext.isNumber(height)) && ownerCt && ownerCt.layout && ownerCt.layout.fixedLayout && ownerCt != layoutOwner) { me.doContainerLayout(); return false; @@ -5673,18 +5689,6 @@ store.sort('myField', 'DESC'); getSorters: function() { return this.sorters.items; - }, - - /** - * Returns an object describing the current sort state of this Store. - * @return {Object} The sort state of the Store. An object with two properties: - * See {@link #sortInfo} for additional details. - */ - getSortState : function() { - return this.sortInfo; } }); /** @@ -6936,7 +6940,7 @@ and a property `descEl` referencing the `div` Element which contains the descrip */ /** - * @cfg {String} styleHtmlContent + * @cfg {Boolean} styleHtmlContent * True to automatically style the html inside the content target of this component (body for panels). * Defaults to false. */ @@ -7208,6 +7212,9 @@ and a property `descEl` referencing the `div` Element which contains the descrip if (me.renderTo) { me.render(me.renderTo); + // EXTJSIV-1935 - should be a way to do afterShow or something, but that + // won't work. Likewise, rendering hidden and then showing (w/autoShow) has + // implications to afterRender so we cannot do that. } if (me.autoShow) { @@ -7314,7 +7321,6 @@ and a property `descEl` referencing the `div` Element which contains the descrip return plugin; }, - // @private initPlugin : function(plugin) { plugin.init(this); @@ -8664,7 +8670,7 @@ alert(t.getXTypes()); // alerts 'component/field/textfield' }, /** - * @deprecated 4.0 Replaced by {link:#addCls} + * @deprecated 4.0 Replaced by {@link #addCls} * Adds a CSS class to the top level element representing this component. * @param {String} cls The CSS class name to add * @return {Ext.Component} Returns the Component to allow method chaining. @@ -8754,8 +8760,26 @@ alert(t.getXTypes()); // alerts 'component/field/textfield' return me.mixins.observable.addListener.apply(me, arguments); }, - - // @TODO: implement removelistener to support the dom event stuff + + // inherit docs + removeManagedListenerItem: function(isClear, managedListener, item, ename, fn, scope){ + var me = this, + element = managedListener.options ? managedListener.options.element : null; + + if (element) { + element = me[element]; + if (element && element.un) { + if (isClear || (managedListener.item === item && managedListener.ename === ename && (!fn || managedListener.fn === fn) && (!scope || managedListener.scope === scope))) { + element.un(managedListener.ename, managedListener.fn, managedListener.scope); + if (!isClear) { + Ext.Array.remove(me.managedListeners, managedListener); + } + } + } + } else { + return me.mixins.observable.removeManagedListenerItem.apply(me, arguments); + } + }, /** * Provides the link for Observable's fireEvent method to bubble up the ownership hierarchy. @@ -9255,12 +9279,14 @@ Ext.define('Ext.AbstractPlugin', { /** * The init method is invoked after initComponent has been run for the * component which we are injecting the plugin into. + * @method */ init: Ext.emptyFn, /** * The destroy method is invoked by the owning Component at the time the Component is being destroyed. * Use this method to clean up an resources. + * @method */ destroy: Ext.emptyFn, @@ -9328,14 +9354,12 @@ Ext.define('Ext.data.Connection', { /** * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true) - * @type Boolean */ disableCaching: true, /** * @cfg {String} disableCachingParam (Optional) Change the parameter which is sent went disabling caching * through a cache buster. Defaults to '_dc' - * @type String */ disableCachingParam: '_dc', @@ -9345,7 +9369,7 @@ Ext.define('Ext.data.Connection', { timeout : 30000, /** - * @param {Object} extraParams (Optional) Any parameters to be appended to the request. + * @cfg {Object} extraParams (Optional) Any parameters to be appended to the request. */ useDefaultHeader : true, @@ -9926,7 +9950,7 @@ failure: function(response, opts) { id; if (request && me.isLoading(request)) { - /** + /* * Clear out the onreadystatechange here, this allows us * greater control, the browser may/may not fire the function * depending on a series of conditions. @@ -10123,7 +10147,7 @@ is used to communicate with your server side code. It can be used as follows: } }); -Default options for all requests can be set be changing a property on the Ext.Ajax class: +Default options for all requests can be set by changing a property on the Ext.Ajax class: Ext.Ajax.timeout = 60000; // 60 seconds @@ -10622,7 +10646,6 @@ Ext.define('Ext.ModelManager', { /** * @class Ext.app.Controller - * @constructor * * Controllers are the glue that binds an application together. All they really do is listen for events (usually from * views) and take some action. Here's how we might create a Controller to manage Users: @@ -10675,28 +10698,28 @@ Ext.define('Ext.ModelManager', { * One of the most useful parts of Controllers is the new ref system. These use the new {@link Ext.ComponentQuery} to * make it really easy to get references to Views on your page. Let's look at an example of this now: * - * Ext.define('MyApp.controller.Users', { - extend: 'Ext.app.Controller', - - refs: [ - { - ref: 'list', - selector: 'grid' - } - ], - - init: function() { - this.control({ - 'button': { - click: this.refreshGrid - } - }); - }, - - refreshGrid: function() { - this.getList().store.load(); - } - }); + * Ext.define('MyApp.controller.Users', { + * extend: 'Ext.app.Controller', + * + * refs: [ + * { + * ref: 'list', + * selector: 'grid' + * } + * ], + * + * init: function() { + * this.control({ + * 'button': { + * click: this.refreshGrid + * } + * }); + * }, + * + * refreshGrid: function() { + * this.getList().store.load(); + * } + * }); * * This example assumes the existence of a {@link Ext.grid.Panel Grid} on the page, which contains a single button to * refresh the Grid when clicked. In our refs array, we set up a reference to the grid. There are two parts to this - @@ -10726,20 +10749,20 @@ Ext.define('Ext.ModelManager', { * Refs aren't the only thing that generate convenient getter methods. Controllers often have to deal with Models and * Stores so the framework offers a couple of easy ways to get access to those too. Let's look at another example: * - * Ext.define('MyApp.controller.Users', { - extend: 'Ext.app.Controller', - - models: ['User'], - stores: ['AllUsers', 'AdminUsers'], - - init: function() { - var User = this.getUserModel(), - allUsers = this.getAllUsersStore(); - - var ed = new User({name: 'Ed'}); - allUsers.add(ed); - } - }); + * Ext.define('MyApp.controller.Users', { + * extend: 'Ext.app.Controller', + * + * models: ['User'], + * stores: ['AllUsers', 'AdminUsers'], + * + * init: function() { + * var User = this.getUserModel(), + * allUsers = this.getAllUsersStore(); + * + * var ed = new User({name: 'Ed'}); + * allUsers.add(ed); + * } + * }); * * By specifying Models and Stores that the Controller cares about, it again dynamically loads them from the appropriate * locations (app/model/User.js, app/store/AllUsers.js and app/store/AdminUsers.js in this case) and creates getter @@ -10752,12 +10775,12 @@ Ext.define('Ext.ModelManager', { * For more information about writing Ext JS 4 applications, please see the * application architecture guide. Also see the {@link Ext.app.Application} documentation. * - * @markdown * @docauthor Ed Spencer + * @constructor */ Ext.define('Ext.app.Controller', { /** - * @cfg {Object} id The id of this controller. You can use this id when dispatching. + * @cfg {String} id The id of this controller. You can use this id when dispatching. */ mixins: { @@ -11049,8 +11072,8 @@ var errors = myModel.validate(); errors.isValid(); //false errors.length; //2 -errors.getByField('name'); // [{field: 'name', error: 'must be present'}] -errors.getByField('title'); // [{field: 'title', error: 'is too short'}] +errors.getByField('name'); // [{field: 'name', message: 'must be present'}] +errors.getByField('title'); // [{field: 'title', message: 'is too short'}]
*/ Ext.define('Ext.data.Errors', { @@ -11754,23 +11777,32 @@ Ext.define('Ext.util.Floating', { */ doConstrain: function(constrainTo) { var me = this, - constrainEl, - vector, + vector = me.getConstrainVector(constrainTo), xy; + if (vector) { + xy = me.getPosition(); + xy[0] += vector[0]; + xy[1] += vector[1]; + me.setPosition(xy); + } + }, + + + /** + * Gets the x/y offsets to constrain this float + * @private + * @param {Mixed} constrainTo Optional. The Element or {@link Ext.util.Region Region} into which this Component is to be constrained. + * @return {Array} The x/y constraints + */ + getConstrainVector: function(constrainTo){ + var me = this, + el; + if (me.constrain || me.constrainHeader) { - if (me.constrainHeader) { - constrainEl = me.header.el; - } else { - constrainEl = me.el; - } - vector = constrainEl.getConstrainVector(constrainTo || (me.floatParent && me.floatParent.getTargetEl()) || me.container); - if (vector) { - xy = me.getPosition(); - xy[0] += vector[0]; - xy[1] += vector[1]; - me.setPosition(xy); - } + el = me.constrainHeader ? me.header.el : me.el; + constrainTo = constrainTo || (me.floatParent && me.floatParent.getTargetEl()) || me.container; + return el.getConstrainVector(constrainTo); } }, @@ -12433,6 +12465,8 @@ Ext.define('Ext.layout.container.boxOverflow.None', { handleOverflow: Ext.emptyFn, clearOverflow: Ext.emptyFn, + + onRemove: Ext.emptyFn, /** * @private @@ -12442,7 +12476,9 @@ Ext.define('Ext.layout.container.boxOverflow.None', { */ getItem: function(item) { return this.layout.owner.getComponent(item); - } + }, + + onRemove: Ext.emptyFn }); /** * @class Ext.util.KeyMap @@ -16677,8 +16713,7 @@ Ext.define('Ext.data.reader.Reader', { id = me.getId(node); - record = new Model(values, id); - record.raw = node; + record = new Model(values, id, node); records.push(record); if (me.implicitIncludes) { @@ -17212,7 +17247,12 @@ Ext.define('Ext.data.reader.Json', { /** * @class Ext.data.writer.Json * @extends Ext.data.writer.Writer - * @ignore + +This class is used to write {@link Ext.data.Model} data to the server in a JSON format. +The {@link #allowSingle} configuration can be set to false to force the records to always be +encoded in an array, even if there is only a single record being sent. + + * @markdown */ Ext.define('Ext.data.writer.Json', { extend: 'Ext.data.writer.Writer', @@ -17496,6 +17536,7 @@ Ext.define('Ext.data.proxy.Proxy', { * @param {Ext.data.Operation} operation The Operation to perform * @param {Function} callback Callback function to be called when the Operation has completed (whether successful or not) * @param {Object} scope Scope to execute the callback function in + * @method */ create: Ext.emptyFn, @@ -17504,6 +17545,7 @@ Ext.define('Ext.data.proxy.Proxy', { * @param {Ext.data.Operation} operation The Operation to perform * @param {Function} callback Callback function to be called when the Operation has completed (whether successful or not) * @param {Object} scope Scope to execute the callback function in + * @method */ read: Ext.emptyFn, @@ -17512,6 +17554,7 @@ Ext.define('Ext.data.proxy.Proxy', { * @param {Ext.data.Operation} operation The Operation to perform * @param {Function} callback Callback function to be called when the Operation has completed (whether successful or not) * @param {Object} scope Scope to execute the callback function in + * @method */ update: Ext.emptyFn, @@ -17520,6 +17563,7 @@ Ext.define('Ext.data.proxy.Proxy', { * @param {Ext.data.Operation} operation The Operation to perform * @param {Function} callback Callback function to be called when the Operation has completed (whether successful or not) * @param {Object} scope Scope to execute the callback function in + * @method */ destroy: Ext.emptyFn, @@ -18033,6 +18077,7 @@ api: { * Optional callback function which can be used to clean up after a request has been completed. * @param {Ext.data.Request} request The Request object * @param {Boolean} success True if the request was successful + * @method */ afterRequest: Ext.emptyFn, @@ -18724,7 +18769,7 @@ Ext.define('Ext.data.Model', { // Fire the onModelDefined template method on ModelManager Ext.ModelManager.onModelDefined(cls); }); - } + }; }, inheritableStatics: { @@ -18891,7 +18936,8 @@ Ext.define('Ext.data.Model', { * @type {Array} */ - constructor: function(data, id) { + // raw not documented intentionally, meant to be used internally. + constructor: function(data, id, raw) { data = data || {}; var me = this, @@ -18910,6 +18956,13 @@ Ext.define('Ext.data.Model', { * @private */ me.internalId = (id || id === 0) ? id : Ext.data.Model.id(me); + + /** + * The raw data used to create this model if created via a reader. + * @property raw + * @type Object + */ + me.raw = raw; Ext.applyIf(me, { data: {} @@ -19867,7 +19920,9 @@ new Ext.Component({ me.el.setVisibilityMode(Ext.core.Element[me.hideMode.toUpperCase()]); } - me.setAutoScroll(me.autoScroll); + if (Ext.isDefined(me.autoScroll)) { + me.setAutoScroll(me.autoScroll); + } me.callParent(); if (!(me.x && me.y) && (me.pageX || me.pageY)) { @@ -20374,6 +20429,7 @@ new Ext.Component({ me.container.remove(); } } + delete me.focusTask; me.callParent(); }, @@ -20397,7 +20453,10 @@ new Ext.Component({ focusEl; if (delay) { - me.focusTask.delay(Ext.isNumber(delay) ? delay: 10, null, me, [selectText, false]); + if (!me.focusTask) { + me.focusTask = Ext.create('Ext.util.DelayedTask', me.focus); + } + me.focusTask.delay(Ext.isNumber(delay) ? delay : 10, null, me, [selectText, false]); return me; } @@ -20562,11 +20621,6 @@ alert(t.getXType()); // alerts 'textfield' return this.proxy; } -}, function() { - - // A single focus delayer for all Components. - this.prototype.focusTask = Ext.create('Ext.util.DelayedTask', this.prototype.focus); - }); /** @@ -21811,24 +21865,26 @@ Ext.define('Ext.container.Container', { /** * @class Ext.toolbar.Fill * @extends Ext.Component + * * A non-rendering placeholder item which instructs the Toolbar's Layout to begin using * the right-justified button container. * * {@img Ext.toolbar.Fill/Ext.toolbar.Fill.png Toolbar Fill} - * Example usage: -

-    Ext.create('Ext.panel.Panel', {
-        title: 'Toolbar Fill Example',
-        width: 300,
-        height: 200,
-        tbar : [
-            'Item 1',
-            {xtype: 'tbfill'}, // or '->'
-            'Item 2'
-        ],
-        renderTo: Ext.getBody()
-    });
-
+ * + * ## Example + * + * Ext.create('Ext.panel.Panel', { + * title: 'Toolbar Fill Example', + * width: 300, + * height: 200, + * tbar : [ + * 'Item 1', + * {xtype: 'tbfill'}, // or '->' + * 'Item 2' + * ], + * renderTo: Ext.getBody() + * }); + * * @constructor * Creates a new Fill * @xtype tbfill @@ -21866,21 +21922,23 @@ Ext.define('Ext.toolbar.Item', { * @extends Ext.toolbar.Item * A simple class that adds a vertical separator bar between toolbar items * (css class:'x-toolbar-separator'). + * * {@img Ext.toolbar.Separator/Ext.toolbar.Separator.png Toolbar Separator} - * Example usage: - *

-    Ext.create('Ext.panel.Panel', {
-        title: 'Toolbar Seperator Example',
-        width: 300,
-        height: 200,
-        tbar : [
-            'Item 1',
-            {xtype: 'tbseparator'}, // or '-'
-            'Item 2'
-        ],
-        renderTo: Ext.getBody()
-    }); 
-
+ * + * ## Example + * + * Ext.create('Ext.panel.Panel', { + * title: 'Toolbar Seperator Example', + * width: 300, + * height: 200, + * tbar : [ + * 'Item 1', + * {xtype: 'tbseparator'}, // or '-' + * 'Item 2' + * ], + * renderTo: Ext.getBody() + * }); + * * @constructor * Creates a new Separator * @xtype tbseparator @@ -22427,6 +22485,17 @@ Ext.define('Ext.button.Button', { * The CSS class to add to a button when it's menu is active. (Defaults to 'x-btn-menu-active') */ menuActiveCls: 'menu-active', + + /** + * @cfg {Object} baseParams + * An object literal of parameters to pass to the url when the {@link #href} property is specified. + */ + + /** + * @cfg {Object} params + * An object literal of parameters to pass to the url when the {@link #href} property is specified. + * Any params override {@link #baseParams}. New params can be set using the {@link #setParams} method. + */ ariaRole: 'button', @@ -22817,17 +22886,21 @@ Ext.define('Ext.button.Button', { * @returns The href string with parameters appended. */ getHref: function() { - var me = this; - return me.href ? Ext.urlAppend(me.href, me.params + Ext.Object.toQueryString(Ext.apply(Ext.apply({}, me.baseParams)))) : false; + var me = this, + params = Ext.apply({}, me.baseParams); + + // write baseParams first, then write any params + params = Ext.apply(params, me.params); + return me.href ? Ext.urlAppend(me.href, Ext.Object.toQueryString(params)) : false; }, /** *

Only valid if the Button was originally configured with a {@link #url}

*

Sets the href of the link dynamically according to the params passed, and any {@link #baseParams} configured.

- * @param {Object} Parameters to use in the href URL. + * @param {Object} params Parameters to use in the href URL. */ - setParams: function(p) { - this.params = p; + setParams: function(params) { + this.params = params; this.btnEl.dom.href = this.getHref(); }, @@ -23468,6 +23541,10 @@ Ext.define('Ext.layout.container.boxOverflow.Menu', { */ me.menuItems = []; }, + + onRemove: function(comp){ + Ext.Array.remove(this.menuItems, comp); + }, handleOverflow: function(calculations, targetSize) { var me = this, @@ -23528,7 +23605,7 @@ Ext.define('Ext.layout.container.boxOverflow.Menu', { * @private */ hideTrigger: function() { - if (this.menuTrigger != undefined) { + if (this.menuTrigger !== undefined) { this.menuTrigger.hide(); } }, @@ -25911,6 +25988,13 @@ Ext.define('Ext.layout.container.Box', { } }; }, + + onRemove: function(comp){ + this.callParent(arguments); + if (this.overflowHandler) { + this.overflowHandler.onRemove(comp); + } + }, /** * @private @@ -25925,7 +26009,7 @@ Ext.define('Ext.layout.container.Box', { } var handlerType = 'None'; - if (handler && handler.type != undefined) { + if (handler && handler.type !== undefined) { handlerType = handler.type; } @@ -27327,7 +27411,7 @@ __Some items have shortcut strings for creation:__ {@img Ext.toolbar.Toolbar/Ext.toolbar.Toolbar1.png Toolbar component} Example usage: - Ext.create('Ext.toolbar.Toolbar", { + Ext.create('Ext.toolbar.Toolbar', { renderTo: document.body, width : 500, items: [ @@ -27992,7 +28076,7 @@ var panel = new Ext.panel.Panel({ item.onAdded(me, i); me.onDockedAdd(item); } - if (me.rendered) { + if (me.rendered && !me.suspendLayout) { me.doComponentLayout(); } return items; @@ -29543,10 +29627,16 @@ Ext.define('Ext.draw.Draw', { } }, + // To be deprecated, converts itself (an arrayPath) to a proper SVG path string path2string: function () { return this.join(",").replace(Ext.draw.Draw.pathToStringRE, "$1"); }, + // Convert the passed arrayPath to a proper SVG path string (d attribute) + pathToString: function(arrayPath) { + return arrayPath.join(",").replace(Ext.draw.Draw.pathToStringRE, "$1"); + }, + parsePathString: function (pathString) { if (!pathString) { return null; @@ -29601,10 +29691,7 @@ Ext.define('Ext.draw.Draw', { pathClone: function(pathArray) { var res = [], - j, - jj, - i, - ii; + j, jj, i, ii; if (!this.is(pathArray, "array") || !this.is(pathArray && pathArray[0], "array")) { // rough assumption pathArray = this.parsePathString(pathArray); } @@ -29627,80 +29714,93 @@ Ext.define('Ext.draw.Draw', { y = 0, mx = 0, my = 0, - start = 0, - i, - ii, - r, - pa, - j, - jj, - k, - kk; - if (pathArray[0][0] == "M") { + i = 0, + ln = pathArray.length, + r, pathSegment, j, ln2; + // MoveTo initial x/y position + if (ln && pathArray[0][0] == "M") { x = +pathArray[0][1]; y = +pathArray[0][2]; mx = x; my = y; - start++; + i++; res[0] = ["M", x, y]; } - for (i = start, ii = pathArray.length; i < ii; i++) { + for (; i < ln; i++) { r = res[i] = []; - pa = pathArray[i]; - if (pa[0] != pa[0].toUpperCase()) { - r[0] = pa[0].toUpperCase(); + pathSegment = pathArray[i]; + if (pathSegment[0] != pathSegment[0].toUpperCase()) { + r[0] = pathSegment[0].toUpperCase(); switch (r[0]) { + // Elliptical Arc case "A": - r[1] = pa[1]; - r[2] = pa[2]; - r[3] = pa[3]; - r[4] = pa[4]; - r[5] = pa[5]; - r[6] = +(pa[6] + x); - r[7] = +(pa[7] + y); + r[1] = pathSegment[1]; + r[2] = pathSegment[2]; + r[3] = pathSegment[3]; + r[4] = pathSegment[4]; + r[5] = pathSegment[5]; + r[6] = +(pathSegment[6] + x); + r[7] = +(pathSegment[7] + y); break; + // Vertical LineTo case "V": - r[1] = +pa[1] + y; + r[1] = +pathSegment[1] + y; break; + // Horizontal LineTo case "H": - r[1] = +pa[1] + x; + r[1] = +pathSegment[1] + x; break; case "M": - mx = +pa[1] + x; - my = +pa[2] + y; + // MoveTo + mx = +pathSegment[1] + x; + my = +pathSegment[2] + y; default: - for (j = 1, jj = pa.length; j < jj; j++) { - r[j] = +pa[j] + ((j % 2) ? x : y); + j = 1; + ln2 = pathSegment.length; + for (; j < ln2; j++) { + r[j] = +pathSegment[j] + ((j % 2) ? x : y); } } - } else { - for (k = 0, kk = pa.length; k < kk; k++) { - res[i][k] = pa[k]; + } + else { + j = 0; + ln2 = pathSegment.length; + for (; j < ln2; j++) { + res[i][j] = pathSegment[j]; } } switch (r[0]) { + // ClosePath case "Z": x = mx; y = my; break; + // Horizontal LineTo case "H": x = r[1]; break; + // Vertical LineTo case "V": y = r[1]; break; + // MoveTo case "M": - mx = res[i][res[i].length - 2]; - my = res[i][res[i].length - 1]; + pathSegment = res[i]; + ln2 = pathSegment.length; + mx = pathSegment[ln2 - 2]; + my = pathSegment[ln2 - 1]; default: - x = res[i][res[i].length - 2]; - y = res[i][res[i].length - 1]; + pathSegment = res[i]; + ln2 = pathSegment.length; + x = pathSegment[ln2 - 2]; + y = pathSegment[ln2 - 1]; } } res.toString = this.path2string; return res; }, + // TO BE DEPRECATED pathToRelative: function (pathArray) { if (!this.is(pathArray, "array") || !this.is(pathArray && pathArray[0], "array")) { pathArray = this.parsePathString(pathArray); @@ -29776,7 +29876,7 @@ Ext.define('Ext.draw.Draw', { return res; }, - //Returns a path converted to a set of curveto commands + // Returns a path converted to a set of curveto commands path2curve: function (path) { var me = this, points = me.pathToAbsolute(path), @@ -30023,27 +30123,8 @@ Ext.define('Ext.draw.Draw', { return newres; } }, - - rotatePoint: function (x, y, alpha, cx, cy) { - if (!alpha) { - return { - x: x, - y: y - }; - } - cx = cx || 0; - cy = cy || 0; - x = x - cx; - y = y - cy; - alpha = alpha * this.radian; - var cos = Math.cos(alpha), - sin = Math.sin(alpha); - return { - x: x * cos - y * sin + cx, - y: x * sin + y * cos + cy - }; - }, + // TO BE DEPRECATED rotateAndTranslatePath: function (sprite) { var alpha = sprite.rotation.degrees, cx = sprite.rotation.x, @@ -30080,7 +30161,28 @@ Ext.define('Ext.draw.Draw', { } return res; }, - + + // TO BE DEPRECATED + rotatePoint: function (x, y, alpha, cx, cy) { + if (!alpha) { + return { + x: x, + y: y + }; + } + cx = cx || 0; + cy = cy || 0; + x = x - cx; + y = y - cy; + alpha = alpha * this.radian; + var cos = Math.cos(alpha), + sin = Math.sin(alpha); + return { + x: x * cos - y * sin + cx, + y: x * sin + y * cos + cy + }; + }, + pathDimensions: function (path) { if (!path || !(path + "")) { return {x: 0, y: 0, width: 0, height: 0}; @@ -30090,13 +30192,10 @@ Ext.define('Ext.draw.Draw', { y = 0, X = [], Y = [], - p, - i, - ii, - xmin, - ymin, - dim; - for (i = 0, ii = path.length; i < ii; i++) { + i = 0, + ln = path.length, + p, xmin, ymin, dim; + for (; i < ln; i++) { p = path[i]; if (p[0] == "M") { x = p[1]; @@ -30122,42 +30221,50 @@ Ext.define('Ext.draw.Draw', { height: Math.max.apply(0, Y) - ymin }; }, - + + intersectInside: function(path, cp1, cp2) { + return (cp2[0] - cp1[0]) * (path[1] - cp1[1]) > (cp2[1] - cp1[1]) * (path[0] - cp1[0]); + }, + + intersectIntersection: function(s, e, cp1, cp2) { + var p = [], + dcx = cp1[0] - cp2[0], + dcy = cp1[1] - cp2[1], + dpx = s[0] - e[0], + dpy = s[1] - e[1], + n1 = cp1[0] * cp2[1] - cp1[1] * cp2[0], + n2 = s[0] * e[1] - s[1] * e[0], + n3 = 1 / (dcx * dpy - dcy * dpx); + + p[0] = (n1 * dpx - n2 * dcx) * n3; + p[1] = (n1 * dpy - n2 * dcy) * n3; + return p; + }, + intersect: function(subjectPolygon, clipPolygon) { - var cp1, cp2, s, e, point; - var inside = function(p) { - return (cp2[0]-cp1[0]) * (p[1]-cp1[1]) > (cp2[1]-cp1[1]) * (p[0]-cp1[0]); - }; - var intersection = function() { - var p = []; - var dcx = cp1[0]-cp2[0], - dcy = cp1[1]-cp2[1], - dpx = s[0]-e[0], - dpy = s[1]-e[1], - n1 = cp1[0]*cp2[1] - cp1[1]*cp2[0], - n2 = s[0]*e[1] - s[1]*e[0], - n3 = 1 / (dcx*dpy - dcy*dpx); - - p[0] = (n1*dpx - n2*dcx) * n3; - p[1] = (n1*dpy - n2*dcy) * n3; - return p; - }; - var outputList = subjectPolygon; - cp1 = clipPolygon[clipPolygon.length -1]; - for (var i = 0, l = clipPolygon.length; i < l; ++i) { + var me = this, + i = 0, + ln = clipPolygon.length, + cp1 = clipPolygon[ln - 1], + outputList = subjectPolygon, + cp2, s, e, point, ln2, inputList, j; + for (; i < ln; ++i) { cp2 = clipPolygon[i]; - var inputList = outputList; + inputList = outputList; outputList = []; - s = inputList[inputList.length -1]; - for (var j = 0, ln = inputList.length; j < ln; j++) { + s = inputList[inputList.length - 1]; + j = 0; + ln2 = inputList.length; + for (; j < ln2; j++) { e = inputList[j]; - if (inside(e)) { - if (!inside(s)) { - outputList.push(intersection()); + if (me.intersectInside(e, cp1, cp2)) { + if (!me.intersectInside(s, cp1, cp2)) { + outputList.push(me.intersectIntersection(s, e, cp1, cp2)); } outputList.push(e); - } else if (inside(s)) { - outputList.push(intersection()); + } + else if (me.intersectInside(s, cp1, cp2)) { + outputList.push(me.intersectIntersection(s, e, cp1, cp2)); } s = e; } @@ -30165,7 +30272,7 @@ Ext.define('Ext.draw.Draw', { } return outputList; }, - + curveDim: function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) { var a = (c2x - 2 * c1x + p1x) - (p2x - 2 * c2x + c1x), b = 2 * (c1x - p1x) - 2 * (c2x - c1x), @@ -31402,8 +31509,8 @@ Ext.define('Ext.dd.DragDrop', { /** * The padding configured for this drag and drop object for calculating * the drop zone intersection with this object. - * @property padding - * @type int[] An array containing the 4 padding values: [top, right, bottom, left] + * An array containing the 4 padding values: [top, right, bottom, left] + * @property {[int]} padding */ padding: null, @@ -31483,8 +31590,7 @@ Ext.define('Ext.dd.DragDrop', { * Array of pixel locations the element will snap to if we specified a * horizontal graduation/interval. This array is generated automatically * when you define a tick interval. - * @property xTicks - * @type int[] + * @property {[int]} xTicks */ xTicks: null, @@ -31492,8 +31598,7 @@ Ext.define('Ext.dd.DragDrop', { * Array of pixel locations the element will snap to if we specified a * vertical graduation/interval. This array is generated automatically * when you define a tick interval. - * @property yTicks - * @type int[] + * @property {[int]} yTicks */ yTicks: null, @@ -33210,6 +33315,7 @@ Ext.define('Ext.dd.DragSource', { * drag event has begun. The drag cannot be canceled from this function. * @param {Number} x The x position of the click on the dragged object * @param {Number} y The y position of the click on the dragged object + * @method */ onStartDrag: Ext.emptyFn, @@ -33535,7 +33641,13 @@ Ext.define('Ext.panel.Panel', { * clicking the expand button to see it again (defaults to true). */ floatable: true, - + + /** + * @cfg {Mixed} overlapHeader + * True to overlap the header in a panel over the framing of the panel itself. This is needed when frame:true (and is done automatically for you). Otherwise it is undefined. + * If you manually add rounded corners to a panel header which does not have frame:true, this will need to be set to true. + */ + /** * @cfg {Boolean} collapsible *

True to make the panel collapsible and have an expand/collapse toggle Tool added into @@ -34364,12 +34476,14 @@ each of the buttons in the fbar. cls: me.baseCls + '-collapsed-placeholder ' + ' ' + Ext.baseCSSPrefix + 'docked ' + me.baseCls + '-' + me.ui + '-collapsed', renderTo: me.el }; - reExpander[(reExpander.orientation == 'horizontal') ? 'tools' : 'items'] = [{ - xtype: 'tool', - type: 'expand-' + me.expandDirection, - handler: me.toggleCollapse, - scope: me - }]; + if (!me.hideCollapseTool) { + reExpander[(reExpander.orientation == 'horizontal') ? 'tools' : 'items'] = [{ + xtype: 'tool', + type: 'expand-' + me.expandDirection, + handler: me.toggleCollapse, + scope: me + }]; + } // Capture the size of the re-expander. // For vertical headers in IE6 and IE7, this will be sized by a CSS rule in _panel.scss @@ -34409,6 +34523,10 @@ each of the buttons in the fbar. if (animate) { me.animate(anim); } else { + // EXTJSIV-1937 (would like to use setCalculateSize) + // save width/height here, expand puts them back + me.uncollapsedSize = { width: me.width, height: me.height }; + me.setSize(anim.to.width, anim.to.height); if (Ext.isDefined(anim.to.left) || Ext.isDefined(anim.to.top)) { me.setPosition(anim.to.left, anim.to.top); @@ -34469,6 +34587,19 @@ each of the buttons in the fbar. if (!this.collapsed || this.fireEvent('beforeexpand', this, animate) === false) { return false; } + + // EXTJSIV-1937 (would like to use setCalculateSize) + if (this.uncollapsedSize) { + Ext.Object.each(this.uncollapsedSize, function (name, value) { + if (Ext.isDefined(value)) { + this[name] = value; + } else { + delete this[name]; + } + }, this); + delete this.uncollapsedSize; + } + var me = this, i = 0, l = me.hiddenDocked.length, @@ -35927,84 +36058,95 @@ Ext.define('Ext.tip.QuickTip', { /** * @class Ext.tip.QuickTipManager - *

Provides attractive and customizable tooltips for any element. The QuickTips + * + * Provides attractive and customizable tooltips for any element. The QuickTips * singleton is used to configure and manage tooltips globally for multiple elements * in a generic manner. To create individual tooltips with maximum customizability, - * you should consider either {@link Ext.tip.Tip} or {@link Ext.tip.ToolTip}.

- *

Quicktips can be configured via tag attributes directly in markup, or by - * registering quick tips programmatically via the {@link #register} method.

- *

The singleton's instance of {@link Ext.tip.QuickTip} is available via + * you should consider either {@link Ext.tip.Tip} or {@link Ext.tip.ToolTip}. + * + * Quicktips can be configured via tag attributes directly in markup, or by + * registering quick tips programmatically via the {@link #register} method. + * + * The singleton's instance of {@link Ext.tip.QuickTip} is available via * {@link #getQuickTip}, and supports all the methods, and all the all the * configuration properties of Ext.tip.QuickTip. These settings will apply to all - * tooltips shown by the singleton.

- *

Below is the summary of the configuration properties which can be used. - * For detailed descriptions see the config options for the {@link Ext.tip.QuickTip QuickTip} class

- *

QuickTips singleton configs (all are optional)

- *
- *

Target element configs (optional unless otherwise noted)

- *
- *

Here is an example showing how some of these config options could be used:

+ * tooltips shown by the singleton. + * + * Below is the summary of the configuration properties which can be used. + * For detailed descriptions see the config options for the {@link Ext.tip.QuickTip QuickTip} class + * + * ## QuickTips singleton configs (all are optional) + * + * - `dismissDelay` + * - `hideDelay` + * - `maxWidth` + * - `minWidth` + * - `showDelay` + * - `trackMouse` + * + * ## Target element configs (optional unless otherwise noted) + * + * - `autoHide` + * - `cls` + * - `dismissDelay` (overrides singleton value) + * - `target` (required) + * - `text` (required) + * - `title` + * - `width` + * + * Here is an example showing how some of these config options could be used: * * {@img Ext.tip.QuickTipManager/Ext.tip.QuickTipManager.png Ext.tip.QuickTipManager component} * * ## Code - * // Init the singleton. Any tag-based quick tips will start working. - * Ext.tip.QuickTipManager.init(); - * - * // Apply a set of config properties to the singleton - * Ext.apply(Ext.tip.QuickTipManager.getQuickTip(), { - * maxWidth: 200, - * minWidth: 100, - * showDelay: 50 // Show 50ms after entering target - * }); - * - * // Create a small panel to add a quick tip to - * Ext.create('Ext.container.Container', { - * id: 'quickTipContainer', - * width: 200, - * height: 150, - * style: { - * backgroundColor:'#000000' - * }, - * renderTo: Ext.getBody() - * }); * - * - * // Manually register a quick tip for a specific element - * Ext.tip.QuickTipManager.register({ - * target: 'quickTipContainer', - * title: 'My Tooltip', - * text: 'This tooltip was added in code', - * width: 100, - * dismissDelay: 10000 // Hide after 10 seconds hover - * }); - - *

To register a quick tip in markup, you simply add one or more of the valid QuickTip attributes prefixed with - * the ext: namespace. The HTML element itself is automatically set as the quick tip target. Here is the summary - * of supported attributes (optional unless otherwise noted):

- * - *

Here is an example of configuring an HTML element to display a tooltip from markup:

- *

-// Add a quick tip to an HTML button
-<input type="button" value="OK" ext:qtitle="OK Button" ext:qwidth="100"
-     data-qtip="This is a quick tip from markup!"></input>
-
+ * // Init the singleton. Any tag-based quick tips will start working. + * Ext.tip.QuickTipManager.init(); + * + * // Apply a set of config properties to the singleton + * Ext.apply(Ext.tip.QuickTipManager.getQuickTip(), { + * maxWidth: 200, + * minWidth: 100, + * showDelay: 50 // Show 50ms after entering target + * }); + * + * // Create a small panel to add a quick tip to + * Ext.create('Ext.container.Container', { + * id: 'quickTipContainer', + * width: 200, + * height: 150, + * style: { + * backgroundColor:'#000000' + * }, + * renderTo: Ext.getBody() + * }); + * + * + * // Manually register a quick tip for a specific element + * Ext.tip.QuickTipManager.register({ + * target: 'quickTipContainer', + * title: 'My Tooltip', + * text: 'This tooltip was added in code', + * width: 100, + * dismissDelay: 10000 // Hide after 10 seconds hover + * }); + * + * To register a quick tip in markup, you simply add one or more of the valid QuickTip attributes prefixed with + * the **data-** namespace. The HTML element itself is automatically set as the quick tip target. Here is the summary + * of supported attributes (optional unless otherwise noted): + * + * - `hide`: Specifying "user" is equivalent to setting autoHide = false. Any other value will be the same as autoHide = true. + * - `qclass`: A CSS class to be applied to the quick tip (equivalent to the 'cls' target element config). + * - `qtip (required)`: The quick tip text (equivalent to the 'text' target element config). + * - `qtitle`: The quick tip title (equivalent to the 'title' target element config). + * - `qwidth`: The quick tip width (equivalent to the 'width' target element config). + * + * Here is an example of configuring an HTML element to display a tooltip from markup: + * + * // Add a quick tip to an HTML button + * + * * @singleton */ Ext.define('Ext.tip.QuickTipManager', function() { @@ -36015,11 +36157,17 @@ Ext.define('Ext.tip.QuickTipManager', function() { requires: ['Ext.tip.QuickTip'], singleton: true, alternateClassName: 'Ext.QuickTips', + /** * Initialize the global QuickTips instance and prepare any quick tips. - * @param {Boolean} autoRender True to render the QuickTips container immediately to preload images. (Defaults to true) + * @param {Boolean} autoRender True to render the QuickTips container immediately to + * preload images. (Defaults to true) + * @param {Object} config An optional config object for the created QuickTip. By + * default, the {@link Ext.tip.QuickTip QuickTip} class is instantiated, but this can + * be changed by supplying an xtype property or a className property in this object. + * All other properties on this object are configuration for the created component. */ - init : function(autoRender){ + init : function (autoRender, config) { if (!tip) { if (!Ext.isReady) { Ext.onReady(function(){ @@ -36027,10 +36175,33 @@ Ext.define('Ext.tip.QuickTipManager', function() { }); return; } - tip = Ext.create('Ext.tip.QuickTip', { - disabled: disabled, - renderTo: autoRender !== false ? document.body : undefined - }); + + var tipConfig = Ext.apply({ disabled: disabled }, config), + className = tipConfig.className, + xtype = tipConfig.xtype; + + if (className) { + delete tipConfig.className; + } else if (xtype) { + className = 'widget.' + xtype; + delete tipConfig.xtype; + } + + if (autoRender !== false) { + tipConfig.renderTo = document.body; + + // + if (tipConfig.renderTo.tagName != 'BODY') { // e.g., == 'FRAMESET' + Ext.Error.raise({ + sourceClass: 'Ext.tip.QuickTipManager', + sourceMethod: 'init', + msg: 'Cannot init QuickTipManager: no document body' + }); + } + // + } + + tip = Ext.create(className || 'Ext.tip.QuickTip', tipConfig); } }, @@ -36125,21 +36296,21 @@ Ext.define('Ext.tip.QuickTipManager', function() { }()); /** * @class Ext.app.Application - * @constructor + * @extend Ext.app.Controller * * Represents an Ext JS 4 application, which is typically a single page app using a {@link Ext.container.Viewport Viewport}. * A typical Ext.app.Application might look like this: * - * Ext.application({ - name: 'MyApp', - launch: function() { - Ext.create('Ext.container.Viewport', { - items: { - html: 'My App' - } - }); - } - }); + * Ext.application({ + * name: 'MyApp', + * launch: function() { + * Ext.create('Ext.container.Viewport', { + * items: { + * html: 'My App' + * } + * }); + * } + * }); * * This does several things. First it creates a global variable called 'MyApp' - all of your Application's classes (such * as its Models, Views and Controllers) will reside under this single namespace, which drastically lowers the chances @@ -36156,15 +36327,15 @@ Ext.define('Ext.tip.QuickTipManager', function() { * might have Models and Controllers for Posts and Comments, and Views for listing, adding and editing Posts and Comments. * Here's how we'd tell our Application about all these things: * - * Ext.application({ - name: 'Blog', - models: ['Post', 'Comment'], - controllers: ['Posts', 'Comments'], - - launch: function() { - ... - } - }); + * Ext.application({ + * name: 'Blog', + * models: ['Post', 'Comment'], + * controllers: ['Posts', 'Comments'], + * + * launch: function() { + * ... + * } + * }); * * Note that we didn't actually list the Views directly in the Application itself. This is because Views are managed by * Controllers, so it makes sense to keep those dependencies there. The Application will load each of the specified @@ -36173,12 +36344,12 @@ Ext.define('Ext.tip.QuickTipManager', function() { * app/controller/Comments.js. In turn, each Controller simply needs to list the Views it uses and they will be * automatically loaded. Here's how our Posts controller like be defined: * - * Ext.define('MyApp.controller.Posts', { - extend: 'Ext.app.Controller', - views: ['posts.List', 'posts.Edit'], - - //the rest of the Controller here - }); + * Ext.define('MyApp.controller.Posts', { + * extend: 'Ext.app.Controller', + * views: ['posts.List', 'posts.Edit'], + * + * //the rest of the Controller here + * }); * * Because we told our Application about our Models and Controllers, and our Controllers about their Views, Ext JS will * automatically load all of our app files for us. This means we don't have to manually add script tags into our html @@ -36188,8 +36359,8 @@ Ext.define('Ext.tip.QuickTipManager', function() { * For more information about writing Ext JS 4 applications, please see the * application architecture guide. * - * @markdown * @docauthor Ed Spencer + * @constructor */ Ext.define('Ext.app.Application', { extend: 'Ext.app.Controller', @@ -36204,7 +36375,7 @@ Ext.define('Ext.app.Application', { ], /** - * @cfg {Object} name The name of your application. This will also be the namespace for your views, controllers + * @cfg {String} name The name of your application. This will also be the namespace for your views, controllers * models and stores. Don't use spaces or special characters in the name. */ @@ -36231,9 +36402,10 @@ Ext.define('Ext.app.Application', { appFolder: 'app', /** - * @cfg {Boolean} autoCreateViewport Automatically loads and instantiates AppName.view.Viewport before firing the launch function. + * @cfg {Boolean} autoCreateViewport True to automatically load and instantiate AppName.view.Viewport + * before firing the launch function (defaults to false). */ - autoCreateViewport: true, + autoCreateViewport: false, constructor: function(config) { config = config || {}; @@ -36253,8 +36425,8 @@ Ext.define('Ext.app.Application', { this.eventbus = Ext.create('Ext.app.EventBus'); - var controllers = this.controllers, - ln = controllers.length, + var controllers = Ext.Array.from(this.controllers), + ln = controllers && controllers.length, i, controller; this.controllers = Ext.create('Ext.util.MixedCollection'); @@ -36682,13 +36854,13 @@ Ext.define('Ext.draw.CompositeSprite', { * Hides all sprites. If the first parameter of the method is true * then a redraw will be forced for each sprite. */ - hide: function(attrs) { + hide: function(redraw) { var i = 0, items = this.items, len = this.length; for (; i < len; i++) { - items[i].hide(); + items[i].hide(redraw); } return this; }, @@ -36697,13 +36869,13 @@ Ext.define('Ext.draw.CompositeSprite', { * Shows all sprites. If the first parameter of the method is true * then a redraw will be forced for each sprite. */ - show: function(attrs) { + show: function(redraw) { var i = 0, items = this.items, len = this.length; for (; i < len; i++) { - items[i].show(); + items[i].show(redraw); } return this; }, @@ -37491,11 +37663,81 @@ Ext.define('Ext.chart.Shape', { * * For example: * - drawComponent.surface.on({ - 'mousemove': function() { - console.log('moving the mouse over the surface'); - } - }); + * drawComponent.surface.on({ + * 'mousemove': function() { + * console.log('moving the mouse over the surface'); + * } + * }); + * + * ## Example + * + * drawComponent.surface.add([ + * { + * type: 'circle', + * radius: 10, + * fill: '#f00', + * x: 10, + * y: 10, + * group: 'circles' + * }, + * { + * type: 'circle', + * radius: 10, + * fill: '#0f0', + * x: 50, + * y: 50, + * group: 'circles' + * }, + * { + * type: 'circle', + * radius: 10, + * fill: '#00f', + * x: 100, + * y: 100, + * group: 'circles' + * }, + * { + * type: 'rect', + * radius: 10, + * x: 10, + * y: 10, + * group: 'rectangles' + * }, + * { + * type: 'rect', + * radius: 10, + * x: 50, + * y: 50, + * group: 'rectangles' + * }, + * { + * type: 'rect', + * radius: 10, + * x: 100, + * y: 100, + * group: 'rectangles' + * } + * ]); + * + * // Get references to my groups + * my circles = surface.getGroup('circles'); + * my rectangles = surface.getGroup('rectangles'); + * + * // Animate the circles down + * circles.animate({ + * duration: 1000, + * translate: { + * y: 200 + * } + * }); + * + * // Animate the rectangles across + * rectangles.animate({ + * duration: 1000, + * translate: { + * x: 200 + * } + * }); */ Ext.define('Ext.draw.Surface', { @@ -37650,6 +37892,7 @@ Ext.define('Ext.draw.Surface', { * * @param {Object} sprite The sprite to add the class to. * @param {String/Array} className The CSS class to add, or an array of classes + * @method */ addCls: Ext.emptyFn, @@ -37662,6 +37905,7 @@ Ext.define('Ext.draw.Surface', { * * @param {Object} sprite The sprite to remove the class from. * @param {String/Array} className The CSS class to remove, or an array of classes + * @method */ removeCls: Ext.emptyFn, @@ -37676,6 +37920,7 @@ Ext.define('Ext.draw.Surface', { * * @param {Object} sprite The sprite to add, or an array of classes to * @param {Object} styles An Object with CSS styles. + * @method */ setStyle: Ext.emptyFn, @@ -37699,17 +37944,16 @@ Ext.define('Ext.draw.Surface', { // @private initBackground: function(config) { - var gradientId, - gradient, - backgroundSprite, - width = this.width, - height = this.height; + var me = this, + width = me.width, + height = me.height, + gradientId, gradient, backgroundSprite; if (config) { if (config.gradient) { gradient = config.gradient; gradientId = gradient.id; - this.addGradient(gradient); - this.background = this.add({ + me.addGradient(gradient); + me.background = me.add({ type: 'rect', x: 0, y: 0, @@ -37718,7 +37962,7 @@ Ext.define('Ext.draw.Surface', { fill: 'url(#' + gradientId + ')' }); } else if (config.fill) { - this.background = this.add({ + me.background = me.add({ type: 'rect', x: 0, y: 0, @@ -37727,7 +37971,7 @@ Ext.define('Ext.draw.Surface', { fill: config.fill }); } else if (config.image) { - this.background = this.add({ + me.background = me.add({ type: 'image', x: 0, y: 0, @@ -37847,6 +38091,8 @@ Ext.define('Ext.draw.Surface', { } } }); + * + * @method */ addGradient: Ext.emptyFn, @@ -38097,7 +38343,9 @@ Ext.define('Ext.draw.Surface', { // @private getPathellipse: function (el) { var a = el.attr; - return this.ellipsePath(a.x, a.y, a.radiusX, a.radiusY); + return this.ellipsePath(a.x, a.y, + a.radiusX || (a.width / 2) || 0, + a.radiusY || (a.height / 2) || 0); }, // @private @@ -38181,6 +38429,7 @@ Ext.define('Ext.draw.Surface', { * * @param {Object} sprite The Sprite to change the text. * @param {String} text The new text to be set. + * @method */ setText: Ext.emptyFn, @@ -38409,6 +38658,7 @@ Ext.define('Ext.draw.Component', { }, true); if (me.rendered) { me.setSize(width, height); + me.surface.setSize(width, height); } else { me.surface.setSize(width, height); @@ -40106,7 +40356,7 @@ Ext.define('Ext.chart.Label', { store = me.chart.store, len = store.getCount(), ratio = items.length / len, - i, count, j, + i, count, index, j, k, gradientsCount = (gradients || 0) && gradients.length, colorStopTotal, colorStopIndex, colorStop, item, label, storeItem, @@ -40119,10 +40369,16 @@ Ext.define('Ext.chart.Label', { } for (i = 0, count = 0; i < len; i++) { + index = 0; for (j = 0; j < ratio; j++) { item = items[count]; label = group.getAt(count); storeItem = store.getAt(i); + + //check the excludes + while(this.__excludes && this.__excludes[index]) { + index++; + } if (!item && label) { label.hide(true); @@ -40130,9 +40386,9 @@ Ext.define('Ext.chart.Label', { if (item && field[j]) { if (!label) { - label = me.onCreateLabel(storeItem, item, i, display, j, count); + label = me.onCreateLabel(storeItem, item, i, display, j, index); } - me.onPlaceLabel(label, storeItem, item, i, display, animate, j, count); + me.onPlaceLabel(label, storeItem, item, i, display, animate, j, index); //set contrast if (config.contrast && item.sprite) { @@ -40168,6 +40424,7 @@ Ext.define('Ext.chart.Label', { } } count++; + index++; } } me.hideLabels(count); @@ -40423,35 +40680,33 @@ Ext.define('Ext.chart.axis.Abstract', { * to create a Chart please check the Chart class documentation. Here's an example for the axes part: * An example of axis for a series (in this case for an area chart that has multiple layers of yFields) could be: * -

-    axes: [{
-        type: 'Numeric',
-        grid: true,
-        position: 'left',
-        fields: ['data1', 'data2', 'data3'],
-        title: 'Number of Hits',
-        grid: {
-            odd: {
-                opacity: 1,
-                fill: '#ddd',
-                stroke: '#bbb',
-                'stroke-width': 1
-            }
-        },
-        minimum: 0
-    }, {
-        type: 'Category',
-        position: 'bottom',
-        fields: ['name'],
-        title: 'Month of the Year',
-        grid: true,
-        label: {
-            rotate: {
-                degrees: 315
-            }
-        }
-    }]
-   
+ * axes: [{ + * type: 'Numeric', + * grid: true, + * position: 'left', + * fields: ['data1', 'data2', 'data3'], + * title: 'Number of Hits', + * grid: { + * odd: { + * opacity: 1, + * fill: '#ddd', + * stroke: '#bbb', + * 'stroke-width': 1 + * } + * }, + * minimum: 0 + * }, { + * type: 'Category', + * position: 'bottom', + * fields: ['name'], + * title: 'Month of the Year', + * grid: true, + * label: { + * rotate: { + * degrees: 315 + * } + * } + * }] * * In this case we use a `Numeric` axis for displaying the values of the Area series and a `Category` axis for displaying the names of * the store elements. The numeric axis is placed on the left of the screen, while the category axis is placed at the bottom of the chart. @@ -40479,7 +40734,10 @@ Ext.define('Ext.chart.axis.Axis', { * @cfg {Number} minorTickSteps * The number of small ticks between two major ticks. Default is zero. */ - + + //@private force min/max values from store + forceMinMax: false, + /** * @cfg {Number} dashSize * The size of the dash marker. Default's 3. @@ -40577,6 +40835,14 @@ Ext.define('Ext.chart.axis.Axis', { out = Ext.draw.Draw.snapEnds(min, max, me.majorTickSteps !== false ? (me.majorTickSteps +1) : me.steps); outfrom = out.from; outto = out.to; + if (me.forceMinMax) { + if (!isNaN(max)) { + out.to = max; + } + if (!isNaN(min)) { + out.from = min; + } + } if (!isNaN(me.maximum)) { //TODO(nico) users are responsible for their own minimum/maximum values set. //Clipping should be added to remove lines in the chart which are below the axis. @@ -41185,67 +41451,67 @@ Ext.define('Ext.chart.axis.Axis', { * axis are more suitable. * * As with other axis you can set the position of the axis and its title. For example: + * * {@img Ext.chart.axis.Category/Ext.chart.axis.Category.png Ext.chart.axis.Category chart axis} -

-   var store = Ext.create('Ext.data.JsonStore', {
-        fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
-        data: [
-            {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
-            {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
-            {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
-            {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
-            {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}                                                
-        ]
-    });
-    
-    Ext.create('Ext.chart.Chart', {
-        renderTo: Ext.getBody(),
-        width: 500,
-        height: 300,
-        store: store,
-        axes: [{
-            type: 'Numeric',
-            grid: true,
-            position: 'left',
-            fields: ['data1', 'data2', 'data3', 'data4', 'data5'],
-            title: 'Sample Values',
-            grid: {
-                odd: {
-                    opacity: 1,
-                    fill: '#ddd',
-                    stroke: '#bbb',
-                    'stroke-width': 1
-                }
-            },
-            minimum: 0,
-            adjustMinimumByMajorUnit: 0
-        }, {
-            type: 'Category',
-            position: 'bottom',
-            fields: ['name'],
-            title: 'Sample Metrics',
-            grid: true,
-            label: {
-                rotate: {
-                    degrees: 315
-                }
-            }
-        }],
-        series: [{
-            type: 'area',
-            highlight: false,
-            axis: 'left',
-            xField: 'name',
-            yField: ['data1', 'data2', 'data3', 'data4', 'data5'],
-            style: {
-                opacity: 0.93
-            }
-        }]
-    });
-    
- - In this example with set the category axis to the bottom of the surface, bound the axis to - the name property and set as title Month of the Year. + * + * var store = Ext.create('Ext.data.JsonStore', { + * fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'], + * data: [ + * {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13}, + * {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3}, + * {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7}, + * {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23}, + * {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33} + * ] + * }); + * + * Ext.create('Ext.chart.Chart', { + * renderTo: Ext.getBody(), + * width: 500, + * height: 300, + * store: store, + * axes: [{ + * type: 'Numeric', + * grid: true, + * position: 'left', + * fields: ['data1', 'data2', 'data3', 'data4', 'data5'], + * title: 'Sample Values', + * grid: { + * odd: { + * opacity: 1, + * fill: '#ddd', + * stroke: '#bbb', + * 'stroke-width': 1 + * } + * }, + * minimum: 0, + * adjustMinimumByMajorUnit: 0 + * }, { + * type: 'Category', + * position: 'bottom', + * fields: ['name'], + * title: 'Sample Metrics', + * grid: true, + * label: { + * rotate: { + * degrees: 315 + * } + * } + * }], + * series: [{ + * type: 'area', + * highlight: false, + * axis: 'left', + * xField: 'name', + * yField: ['data1', 'data2', 'data3', 'data4', 'data5'], + * style: { + * opacity: 0.93 + * } + * }] + * }); + * + * In this example with set the category axis to the bottom of the surface, bound the axis to + * the name property and set as title Month of the Year. */ Ext.define('Ext.chart.axis.Category', { @@ -41320,15 +41586,14 @@ Ext.define('Ext.chart.axis.Category', { * * A possible configuration for this axis would look like: * - axes: [{ - type: 'gauge', - position: 'gauge', - minimum: 0, - maximum: 100, - steps: 10, - margin: 7 - }], - * + * axes: [{ + * type: 'gauge', + * position: 'gauge', + * minimum: 0, + * maximum: 100, + * steps: 10, + * margin: 7 + * }], */ Ext.define('Ext.chart.axis.Gauge', { @@ -41512,67 +41777,66 @@ Ext.define('Ext.chart.axis.Gauge', { * opposed to the category axis. You can set mininum and maximum values to the * axis so that the values are bound to that. If no values are set, then the * scale will auto-adjust to the values. + * * {@img Ext.chart.axis.Numeric/Ext.chart.axis.Numeric.png Ext.chart.axis.Numeric chart axis} + * * For example: - -

-   var store = Ext.create('Ext.data.JsonStore', {
-        fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
-        data: [
-            {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
-            {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
-            {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
-            {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
-            {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}                                                
-        ]
-    });
-    
-    Ext.create('Ext.chart.Chart', {
-        renderTo: Ext.getBody(),
-        width: 500,
-        height: 300,
-        store: store,
-        axes: [{
-            type: 'Numeric',
-            grid: true,
-            position: 'left',
-            fields: ['data1', 'data2', 'data3', 'data4', 'data5'],
-            title: 'Sample Values',
-            grid: {
-                odd: {
-                    opacity: 1,
-                    fill: '#ddd',
-                    stroke: '#bbb',
-                    'stroke-width': 1
-                }
-            },
-            minimum: 0,
-            adjustMinimumByMajorUnit: 0
-        }, {
-            type: 'Category',
-            position: 'bottom',
-            fields: ['name'],
-            title: 'Sample Metrics',
-            grid: true,
-            label: {
-                rotate: {
-                    degrees: 315
-                }
-            }
-        }],
-        series: [{
-            type: 'area',
-            highlight: false,
-            axis: 'left',
-            xField: 'name',
-            yField: ['data1', 'data2', 'data3', 'data4', 'data5'],
-            style: {
-                opacity: 0.93
-            }
-        }]
-    });
-    
- + * + * var store = Ext.create('Ext.data.JsonStore', { + * fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'], + * data: [ + * {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13}, + * {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3}, + * {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7}, + * {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23}, + * {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33} + * ] + * }); + * + * Ext.create('Ext.chart.Chart', { + * renderTo: Ext.getBody(), + * width: 500, + * height: 300, + * store: store, + * axes: [{ + * type: 'Numeric', + * grid: true, + * position: 'left', + * fields: ['data1', 'data2', 'data3', 'data4', 'data5'], + * title: 'Sample Values', + * grid: { + * odd: { + * opacity: 1, + * fill: '#ddd', + * stroke: '#bbb', + * 'stroke-width': 1 + * } + * }, + * minimum: 0, + * adjustMinimumByMajorUnit: 0 + * }, { + * type: 'Category', + * position: 'bottom', + * fields: ['name'], + * title: 'Sample Metrics', + * grid: true, + * label: { + * rotate: { + * degrees: 315 + * } + * } + * }], + * series: [{ + * type: 'area', + * highlight: false, + * axis: 'left', + * xField: 'name', + * yField: ['data1', 'data2', 'data3', 'data4', 'data5'], + * style: { + * opacity: 0.93 + * } + * }] + * }); * * In this example we create an axis of Numeric type. We set a minimum value so that * even if all series have values greater than zero, the grid starts at zero. We bind @@ -41582,7 +41846,6 @@ Ext.define('Ext.chart.axis.Gauge', { * We use a grid configuration to set odd background rows to a certain style and even rows * to be transparent/ignored. * - * * @constructor */ Ext.define('Ext.chart.axis.Numeric', { @@ -42030,7 +42293,8 @@ Ext.define('Ext.data.AbstractStore', { //documented above constructor: function(config) { - var me = this; + var me = this, + filters; me.addEvents( /** @@ -42105,6 +42369,7 @@ Ext.define('Ext.data.AbstractStore', { ); Ext.apply(me, config); + // don't use *config* anymore from here on... use *me* instead... /** * Temporary cache in which removed model instances are kept until successfully synchronised with a Proxy, @@ -42116,7 +42381,7 @@ Ext.define('Ext.data.AbstractStore', { me.removed = []; me.mixins.observable.constructor.apply(me, arguments); - me.model = Ext.ModelManager.getModel(config.model || me.model); + me.model = Ext.ModelManager.getModel(me.model); /** * @property modelDefaults @@ -42144,7 +42409,7 @@ Ext.define('Ext.data.AbstractStore', { } //ensures that the Proxy is instantiated correctly - me.setProxy(config.proxy || me.proxy || me.model.getProxy()); + me.setProxy(me.proxy || me.model.getProxy()); if (me.id && !me.storeId) { me.storeId = me.id; @@ -42162,8 +42427,9 @@ Ext.define('Ext.data.AbstractStore', { * @property filters * @type Ext.util.MixedCollection */ + filters = me.decodeFilters(me.filters); me.filters = Ext.create('Ext.util.MixedCollection'); - me.filters.addAll(me.decodeFilters(config.filters)); + me.filters.addAll(filters); }, /** @@ -42366,7 +42632,10 @@ Ext.define('Ext.data.AbstractStore', { return item.dirty === true && item.phantom !== true && item.isValid(); }, - //returns any records that have been removed from the store but not yet destroyed on the proxy + /** + * Returns any records that have been removed from the store but not yet destroyed on the proxy. + * @return {Array} The removed Model instances + */ getRemovedRecords: function() { return this.removed; }, @@ -42596,6 +42865,7 @@ Ext.define('Ext.data.AbstractStore', { * Removes all records from the store. This method does a "fast remove", * individual remove events are not called. The {@link #clear} event is * fired upon completion. + * @method */ removeAll: Ext.emptyFn, // individual substores should implement a "fast" remove @@ -42902,10 +43172,9 @@ Ext.define('Ext.data.Store', { groupDir: "ASC", /** + * @cfg {Number} pageSize * The number of records considered to form a 'page'. This is used to power the built-in * paging using the nextPage and previousPage functions. Defaults to 25. - * @property pageSize - * @type Number */ pageSize: 25, @@ -42958,7 +43227,8 @@ Ext.define('Ext.data.Store', { config = config || {}; var me = this, - groupers = config.groupers, + groupers = config.groupers || me.groupers, + groupField = config.groupField || me.groupField, proxy, data; @@ -43014,10 +43284,10 @@ Ext.define('Ext.data.Store', { delete config.data; } - if (!groupers && config.groupField) { + if (!groupers && groupField) { groupers = [{ - property : config.groupField, - direction: config.groupDir + property : groupField, + direction: config.groupDir || me.groupDir }]; } delete config.groupers; @@ -43031,6 +43301,7 @@ Ext.define('Ext.data.Store', { me.groupers.addAll(me.decodeGroupers(groupers)); this.callParent([config]); + // don't use *config* anymore from here on... use *me* instead... if (me.groupers.items.length) { me.sort(me.groupers.items, 'prepend', false); @@ -43644,7 +43915,7 @@ store.load(function(records, operation, success) { original, index; - /** + /* * Loop over each record returned from the server. Assume they are * returned in order of how they were sent. If we find a matching * record, replace it with the newly created one. @@ -44313,7 +44584,6 @@ store.load(function(records, operation, success) { sorters = me.getSorters(); start = me.guaranteedStart; end = me.guaranteedEnd; - range; if (sorters.length) { prefetchData.sort(sorters); @@ -44867,28 +45137,26 @@ Ext.define('Ext.data.JsonStore', { * * For example: * -

-    axes: [{
-        type: 'Time',
-        position: 'bottom',
-        fields: 'date',
-        title: 'Day',
-        dateFormat: 'M d',
-        groupBy: 'year,month,day',
-        aggregateOp: 'sum',
-
-        constrain: true,
-        fromDate: new Date('1/1/11'),
-        toDate: new Date('1/7/11')
-    }]
-  
+ * axes: [{ + * type: 'Time', + * position: 'bottom', + * fields: 'date', + * title: 'Day', + * dateFormat: 'M d', + * groupBy: 'year,month,day', + * aggregateOp: 'sum', + * + * constrain: true, + * fromDate: new Date('1/1/11'), + * toDate: new Date('1/7/11') + * }] * - * In this example we're creating a time axis that has as title Day. - * The field the axis is bound to is date. - * The date format to use to display the text for the axis labels is M d + * In this example we're creating a time axis that has as title *Day*. + * The field the axis is bound to is `date`. + * The date format to use to display the text for the axis labels is `M d` * which is a three letter month abbreviation followed by the day number. - * The time axis will show values for dates betwee fromDate and toDate. - * Since constrain is set to true all other values for other dates not between + * The time axis will show values for dates between `fromDate` and `toDate`. + * Since `constrain` is set to true all other values for other dates not between * the fromDate and toDate will not be displayed. * * @constructor @@ -46969,7 +47237,7 @@ Ext.define('Ext.chart.series.Bar', { }, // @private callback used when placing a label. - onPlaceLabel: function(label, storeItem, item, i, display, animate, index) { + onPlaceLabel: function(label, storeItem, item, i, display, animate, j, index) { // Determine the label's final position. Starts with the configured preferred value but // may get flipped from inside to outside or vice-versa depending on space. var me = this, @@ -47171,95 +47439,92 @@ Ext.define('Ext.chart.series.Bar', { * @class Ext.chart.series.Column * @extends Ext.chart.series.Bar * -

- Creates a Column Chart. Much of the methods are inherited from Bar. A Column Chart is a useful visualization technique to display quantitative information for different - categories that can show some progression (or regression) in the data set. - As with all other series, the Column Series must be appended in the *series* Chart array configuration. See the Chart - documentation for more information. A typical configuration object for the column series could be: -

-{@img Ext.chart.series.Column/Ext.chart.series.Column.png Ext.chart.series.Column chart series -

-    var store = Ext.create('Ext.data.JsonStore', {
-        fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
-        data: [
-            {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
-            {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
-            {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
-            {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
-            {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}                                                
-        ]
-    });
-    
-    Ext.create('Ext.chart.Chart', {
-        renderTo: Ext.getBody(),
-        width: 500,
-        height: 300,
-        animate: true,
-        store: store,
-        axes: [{
-            type: 'Numeric',
-            position: 'bottom',
-            fields: ['data1'],
-            label: {
-                renderer: Ext.util.Format.numberRenderer('0,0')
-            },
-            title: 'Sample Values',
-            grid: true,
-            minimum: 0
-        }, {
-            type: 'Category',
-            position: 'left',
-            fields: ['name'],
-            title: 'Sample Metrics'
-        }],
-            axes: [{
-                type: 'Numeric',
-                position: 'left',
-                fields: ['data1'],
-                label: {
-                    renderer: Ext.util.Format.numberRenderer('0,0')
-                },
-                title: 'Sample Values',
-                grid: true,
-                minimum: 0
-            }, {
-                type: 'Category',
-                position: 'bottom',
-                fields: ['name'],
-                title: 'Sample Metrics'
-            }],
-            series: [{
-                type: 'column',
-                axis: 'left',
-                highlight: true,
-                tips: {
-                  trackMouse: true,
-                  width: 140,
-                  height: 28,
-                  renderer: function(storeItem, item) {
-                    this.setTitle(storeItem.get('name') + ': ' + storeItem.get('data1') + ' $');
-                  }
-                },
-                label: {
-                  display: 'insideEnd',
-                  'text-anchor': 'middle',
-                    field: 'data1',
-                    renderer: Ext.util.Format.numberRenderer('0'),
-                    orientation: 'vertical',
-                    color: '#333'
-                },
-                xField: 'name',
-                yField: 'data1'
-            }]
-    });
-   
- -

- In this configuration we set `column` as the series type, bind the values of the bars to the bottom axis, set `highlight` to true so that bars are smoothly highlighted - when hovered and bind the `xField` or category field to the data store `name` property and the `yField` as the data1 property of a store element. -

+ * Creates a Column Chart. Much of the methods are inherited from Bar. A Column Chart is a useful visualization technique to display quantitative information for different + * categories that can show some progression (or regression) in the data set. + * As with all other series, the Column Series must be appended in the *series* Chart array configuration. See the Chart + * documentation for more information. A typical configuration object for the column series could be: + * + * {@img Ext.chart.series.Column/Ext.chart.series.Column.png Ext.chart.series.Column chart series} + * + * ## Example + * + * var store = Ext.create('Ext.data.JsonStore', { + * fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'], + * data: [ + * {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13}, + * {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3}, + * {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7}, + * {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23}, + * {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33} + * ] + * }); + * + * Ext.create('Ext.chart.Chart', { + * renderTo: Ext.getBody(), + * width: 500, + * height: 300, + * animate: true, + * store: store, + * axes: [{ + * type: 'Numeric', + * position: 'bottom', + * fields: ['data1'], + * label: { + * renderer: Ext.util.Format.numberRenderer('0,0') + * }, + * title: 'Sample Values', + * grid: true, + * minimum: 0 + * }, { + * type: 'Category', + * position: 'left', + * fields: ['name'], + * title: 'Sample Metrics' + * }], + * axes: [{ + * type: 'Numeric', + * position: 'left', + * fields: ['data1'], + * label: { + * renderer: Ext.util.Format.numberRenderer('0,0') + * }, + * title: 'Sample Values', + * grid: true, + * minimum: 0 + * }, { + * type: 'Category', + * position: 'bottom', + * fields: ['name'], + * title: 'Sample Metrics' + * }], + * series: [{ + * type: 'column', + * axis: 'left', + * highlight: true, + * tips: { + * trackMouse: true, + * width: 140, + * height: 28, + * renderer: function(storeItem, item) { + * this.setTitle(storeItem.get('name') + ': ' + storeItem.get('data1') + ' $'); + * } + * }, + * label: { + * display: 'insideEnd', + * 'text-anchor': 'middle', + * field: 'data1', + * renderer: Ext.util.Format.numberRenderer('0'), + * orientation: 'vertical', + * color: '#333' + * }, + * xField: 'name', + * yField: 'data1' + * }] + * }); + * + * In this configuration we set `column` as the series type, bind the values of the bars to the bottom axis, set `highlight` to true so that bars are smoothly highlighted + * when hovered and bind the `xField` or category field to the data store `name` property and the `yField` as the data1 property of a store element. */ - Ext.define('Ext.chart.series.Column', { /* Begin Definitions */ @@ -47746,90 +48011,92 @@ Ext.define('Ext.chart.series.Gauge', { * @class Ext.chart.series.Line * @extends Ext.chart.series.Cartesian * -

- Creates a Line Chart. A Line Chart is a useful visualization technique to display quantitative information for different - categories or other real values (as opposed to the bar chart), that can show some progression (or regression) in the dataset. - As with all other series, the Line Series must be appended in the *series* Chart array configuration. See the Chart - documentation for more information. A typical configuration object for the line series could be: -

-{@img Ext.chart.series.Line/Ext.chart.series.Line.png Ext.chart.series.Line chart series} -

-    var store = Ext.create('Ext.data.JsonStore', {
-        fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
-        data: [
-            {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
-            {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
-            {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
-            {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
-            {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}                                                
-        ]
-    });
-    
-    Ext.create('Ext.chart.Chart', {
-        renderTo: Ext.getBody(),
-        width: 500,
-        height: 300,
-        animate: true,
-        store: store,
-        axes: [{
-            type: 'Numeric',
-            position: 'bottom',
-            fields: ['data1'],
-            label: {
-                renderer: Ext.util.Format.numberRenderer('0,0')
-            },
-            title: 'Sample Values',
-            grid: true,
-            minimum: 0
-        }, {
-            type: 'Category',
-            position: 'left',
-            fields: ['name'],
-            title: 'Sample Metrics'
-        }],
-        series: [{
-            type: 'line',
-            highlight: {
-                size: 7,
-                radius: 7
-            },
-            axis: 'left',
-            xField: 'name',
-            yField: 'data1',
-            markerCfg: {
-                type: 'cross',
-                size: 4,
-                radius: 4,
-                'stroke-width': 0
-            }
-        }, {
-            type: 'line',
-            highlight: {
-                size: 7,
-                radius: 7
-            },
-            axis: 'left',
-            fill: true,
-            xField: 'name',
-            yField: 'data3',
-            markerCfg: {
-                type: 'circle',
-                size: 4,
-                radius: 4,
-                'stroke-width': 0
-            }
-        }]
-    });
-   
- -

- In this configuration we're adding two series (or lines), one bound to the `data1` property of the store and the other to `data3`. The type for both configurations is - `line`. The `xField` for both series is the same, the name propert of the store. Both line series share the same axis, the left axis. You can set particular marker - configuration by adding properties onto the markerConfig object. Both series have an object as highlight so that markers animate smoothly to the properties in highlight - when hovered. The second series has `fill=true` which means that the line will also have an area below it of the same color. -

+ * Creates a Line Chart. A Line Chart is a useful visualization technique to display quantitative information for different + * categories or other real values (as opposed to the bar chart), that can show some progression (or regression) in the dataset. + * As with all other series, the Line Series must be appended in the *series* Chart array configuration. See the Chart + * documentation for more information. A typical configuration object for the line series could be: + * + * {@img Ext.chart.series.Line/Ext.chart.series.Line.png Ext.chart.series.Line chart series} + * + * var store = Ext.create('Ext.data.JsonStore', { + * fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'], + * data: [ + * {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13}, + * {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3}, + * {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7}, + * {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23}, + * {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33} + * ] + * }); + * + * Ext.create('Ext.chart.Chart', { + * renderTo: Ext.getBody(), + * width: 500, + * height: 300, + * animate: true, + * store: store, + * axes: [{ + * type: 'Numeric', + * position: 'bottom', + * fields: ['data1'], + * label: { + * renderer: Ext.util.Format.numberRenderer('0,0') + * }, + * title: 'Sample Values', + * grid: true, + * minimum: 0 + * }, { + * type: 'Category', + * position: 'left', + * fields: ['name'], + * title: 'Sample Metrics' + * }], + * series: [{ + * type: 'line', + * highlight: { + * size: 7, + * radius: 7 + * }, + * axis: 'left', + * xField: 'name', + * yField: 'data1', + * markerCfg: { + * type: 'cross', + * size: 4, + * radius: 4, + * 'stroke-width': 0 + * } + * }, { + * type: 'line', + * highlight: { + * size: 7, + * radius: 7 + * }, + * axis: 'left', + * fill: true, + * xField: 'name', + * yField: 'data3', + * markerCfg: { + * type: 'circle', + * size: 4, + * radius: 4, + * 'stroke-width': 0 + * } + * }] + * }); + * + * In this configuration we're adding two series (or lines), one bound to the `data1` + * property of the store and the other to `data3`. The type for both configurations is + * `line`. The `xField` for both series is the same, the name propert of the store. + * Both line series share the same axis, the left axis. You can set particular marker + * configuration by adding properties onto the markerConfig object. Both series have + * an object as highlight so that markers animate smoothly to the properties in highlight + * when hovered. The second series has `fill=true` which means that the line will also + * have an area below it of the same color. + * + * **Note:** In the series definition remember to explicitly set the axis to bind the + * values of the line series to. This can be done by using the `axis` configuration property. */ - Ext.define('Ext.chart.series.Line', { /* Begin Definitions */ @@ -47845,6 +48112,13 @@ Ext.define('Ext.chart.series.Line', { type: 'line', alias: 'series.line', + + /** + * @cfg {String} axis + * The position of the axis to bind the values to. Possible values are 'left', 'bottom', 'top' and 'right'. + * You must explicitly set this value to bind the values of the line series to the ones in the axis, otherwise a + * relative scale will be used. + */ /** * @cfg {Number} selectionTolerance @@ -47999,16 +48273,24 @@ Ext.define('Ext.chart.series.Line', { shadowBarAttr, xValues = [], yValues = [], + numericAxis = true, + axisCount = 0, onbreak = false, markerStyle = me.markerStyle, seriesStyle = me.seriesStyle, seriesLabelStyle = me.seriesLabelStyle, colorArrayStyle = me.colorArrayStyle, colorArrayLength = colorArrayStyle && colorArrayStyle.length || 0, + posHash = { + 'left': 'right', + 'right': 'left', + 'top': 'bottom', + 'bottom': 'top' + }, seriesIdx = me.seriesIdx, shadows, shadow, shindex, fromPath, fill, fillPath, rendererAttributes, x, y, prevX, prevY, firstY, markerCount, i, j, ln, axis, ends, marker, markerAux, item, xValue, yValue, coords, xScale, yScale, minX, maxX, minY, maxY, line, animation, endMarkerStyle, - endLineStyle, type, props, firstMarker; + endLineStyle, type, props, firstMarker, count; //if store is empty then there's nothing to draw. if (!store || !store.getCount()) { @@ -48052,42 +48334,80 @@ Ext.define('Ext.chart.series.Line', { me.clipRect = [bbox.x, bbox.y, bbox.width, bbox.height]; - for (i = 0, ln = axes.length; i < ln; i++) { - axis = chart.axes.get(axes[i]); - if (axis) { - ends = axis.calcEnds(); - if (axis.position == 'top' || axis.position == 'bottom') { - minX = ends.from; - maxX = ends.to; + chart.axes.each(function(axis) { + //only apply position calculations to axes that affect this series + //this means the axis in the position referred by this series and also + //the axis in the other coordinate for this series. For example: (left, top|bottom), + //or (top, left|right), etc. + if (axis.position == me.axis || axis.position != posHash[me.axis]) { + axisCount++; + if (axis.type != 'Numeric') { + numericAxis = false; + return; } - else { - minY = ends.from; - maxY = ends.to; + numericAxis = (numericAxis && axis.type == 'Numeric'); + if (axis) { + ends = axis.calcEnds(); + if (axis.position == 'top' || axis.position == 'bottom') { + minX = ends.from; + maxX = ends.to; + } + else { + minY = ends.from; + maxY = ends.to; + } } } + }); + + //If there's only one axis specified for a series, then we set the default type of the other + //axis to a category axis. So in this case numericAxis, which would be true if both axes affecting + //the series are numeric should be false. + if (numericAxis && axisCount == 1) { + numericAxis = false; } + // If a field was specified without a corresponding axis, create one to get bounds //only do this for the axis where real values are bound (that's why we check for //me.axis) - if (me.xField && !Ext.isNumber(minX) - && (me.axis == 'bottom' || me.axis == 'top')) { - axis = Ext.create('Ext.chart.axis.Axis', { - chart: chart, - fields: [].concat(me.xField) - }).calcEnds(); - minX = axis.from; - maxX = axis.to; + if (me.xField && !Ext.isNumber(minX)) { + if (me.axis == 'bottom' || me.axis == 'top') { + axis = Ext.create('Ext.chart.axis.Axis', { + chart: chart, + fields: [].concat(me.xField) + }).calcEnds(); + minX = axis.from; + maxX = axis.to; + } else if (numericAxis) { + axis = Ext.create('Ext.chart.axis.Axis', { + chart: chart, + fields: [].concat(me.xField), + forceMinMax: true + }).calcEnds(); + minX = axis.from; + maxX = axis.to; + } } - if (me.yField && !Ext.isNumber(minY) - && (me.axis == 'right' || me.axis == 'left')) { - axis = Ext.create('Ext.chart.axis.Axis', { - chart: chart, - fields: [].concat(me.yField) - }).calcEnds(); - minY = axis.from; - maxY = axis.to; + + if (me.yField && !Ext.isNumber(minY)) { + if (me.axis == 'right' || me.axis == 'left') { + axis = Ext.create('Ext.chart.axis.Axis', { + chart: chart, + fields: [].concat(me.yField) + }).calcEnds(); + minY = axis.from; + maxY = axis.to; + } else if (numericAxis) { + axis = Ext.create('Ext.chart.axis.Axis', { + chart: chart, + fields: [].concat(me.yField), + forceMinMax: true + }).calcEnds(); + minY = axis.from; + maxY = axis.to; + } } - + if (isNaN(minX)) { minX = 0; xScale = bbox.width / (store.getCount() - 1); @@ -48103,7 +48423,7 @@ Ext.define('Ext.chart.series.Line', { else { yScale = bbox.height / (maxY - minY); } - + store.each(function(record, i) { xValue = record.get(me.xField); yValue = record.get(me.yField); @@ -48119,12 +48439,12 @@ Ext.define('Ext.chart.series.Line', { // Ensure a value if (typeof xValue == 'string' || typeof xValue == 'object' //set as uniform distribution if the axis is a category axis. - || (me.axis != 'top' && me.axis != 'bottom')) { + || (me.axis != 'top' && me.axis != 'bottom' && !numericAxis)) { xValue = i; } if (typeof yValue == 'string' || typeof yValue == 'object' //set as uniform distribution if the axis is a category axis. - || (me.axis != 'left' && me.axis != 'right')) { + || (me.axis != 'left' && me.axis != 'right' && !numericAxis)) { yValue = i; } xValues.push(xValue); @@ -48140,6 +48460,7 @@ Ext.define('Ext.chart.series.Line', { me.items = []; + count = 0; ln = xValues.length; for (i = 0; i < ln; i++) { xValue = xValues[i]; @@ -48190,7 +48511,7 @@ Ext.define('Ext.chart.series.Line', { } } if (showMarkers) { - marker = markerGroup.getAt(i); + marker = markerGroup.getAt(count++); if (!marker) { marker = Ext.chart.Shape[type](surface, Ext.apply({ group: [group, markerGroup], @@ -48345,29 +48666,22 @@ Ext.define('Ext.chart.series.Line', { } //animate markers if (showMarkers) { + count = 0; for(i = 0; i < ln; i++) { - item = markerGroup.getAt(i); - if (item) { - if (me.items[i]) { + if (me.items[i]) { + item = markerGroup.getAt(count++); + if (item) { rendererAttributes = me.renderer(item, store.getAt(i), item._to, i, store); me.onAnimate(item, { to: Ext.apply(rendererAttributes, endMarkerStyle || {}) }); - } else { - item.setAttributes(Ext.apply({ - hidden: true - }, item._to), true); } - } + } } - for(; i < markerCount; i++) { - item = markerGroup.getAt(i); + for(; count < markerCount; count++) { + item = markerGroup.getAt(count); item.hide(true); } -// for(i = 0; i < (chart.markerIndex || 0)-1; i++) { -// item = markerGroup.getAt(i); -// item.hide(true); -// } } } else { rendererAttributes = me.renderer(me.line, false, { path: path, hidden: false }, i, store); @@ -48392,19 +48706,18 @@ Ext.define('Ext.chart.series.Line', { }, true); } if (showMarkers) { + count = 0; for(i = 0; i < ln; i++) { - item = markerGroup.getAt(i); - if (item) { - if (me.items[i]) { + if (me.items[i]) { + item = markerGroup.getAt(count++); + if (item) { rendererAttributes = me.renderer(item, store.getAt(i), item._to, i, store); item.setAttributes(Ext.apply(endMarkerStyle || {}, rendererAttributes || {}), true); - } else { - item.hide(true); } - } + } } - for(; i < markerCount; i++) { - item = markerGroup.getAt(i); + for(; count < markerCount; count++) { + item = markerGroup.getAt(count); item.hide(true); } } @@ -48745,58 +49058,56 @@ Ext.define('Ext.chart.series.Line', { * As with all other series, the Pie Series must be appended in the *series* Chart array configuration. See the Chart * documentation for more information. A typical configuration object for the pie series could be: * -{@img Ext.chart.series.Pie/Ext.chart.series.Pie.png Ext.chart.series.Pie chart series} -

-    var store = Ext.create('Ext.data.JsonStore', {
-        fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
-        data: [
-            {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
-            {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
-            {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
-            {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
-            {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}                                                
-        ]
-    });
-    
-    Ext.create('Ext.chart.Chart', {
-        renderTo: Ext.getBody(),
-        width: 500,
-        height: 300,
-        animate: true,
-        store: store,
-        theme: 'Base:gradients',
-        series: [{
-            type: 'pie',
-            field: 'data1',
-            showInLegend: true,
-            tips: {
-              trackMouse: true,
-              width: 140,
-              height: 28,
-              renderer: function(storeItem, item) {
-                //calculate and display percentage on hover
-                var total = 0;
-                store.each(function(rec) {
-                    total += rec.get('data1');
-                });
-                this.setTitle(storeItem.get('name') + ': ' + Math.round(storeItem.get('data1') / total * 100) + '%');
-              }
-            },
-            highlight: {
-              segment: {
-                margin: 20
-              }
-            },
-            label: {
-                field: 'name',
-                display: 'rotate',
-                contrast: true,
-                font: '18px Arial'
-            }
-        }]    
-    });
-   
- + * {@img Ext.chart.series.Pie/Ext.chart.series.Pie.png Ext.chart.series.Pie chart series} + * + * var store = Ext.create('Ext.data.JsonStore', { + * fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'], + * data: [ + * {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13}, + * {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3}, + * {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7}, + * {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23}, + * {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33} + * ] + * }); + * + * Ext.create('Ext.chart.Chart', { + * renderTo: Ext.getBody(), + * width: 500, + * height: 300, + * animate: true, + * store: store, + * theme: 'Base:gradients', + * series: [{ + * type: 'pie', + * field: 'data1', + * showInLegend: true, + * tips: { + * trackMouse: true, + * width: 140, + * height: 28, + * renderer: function(storeItem, item) { + * //calculate and display percentage on hover + * var total = 0; + * store.each(function(rec) { + * total += rec.get('data1'); + * }); + * this.setTitle(storeItem.get('name') + ': ' + Math.round(storeItem.get('data1') / total * 100) + '%'); + * } + * }, + * highlight: { + * segment: { + * margin: 20 + * } + * }, + * label: { + * field: 'name', + * display: 'rotate', + * contrast: true, + * font: '18px Arial' + * } + * }] + * }); * * In this configuration we set `pie` as the type for the series, set an object with specific style properties for highlighting options * (triggered when hovering elements). We also set true to `showInLegend` so all the pie slices can be represented by a legend item. @@ -48806,7 +49117,6 @@ Ext.define('Ext.chart.series.Line', { * and size through the `font` parameter. * * @xtype pie - * */ Ext.define('Ext.chart.series.Pie', { @@ -49198,25 +49508,22 @@ Ext.define('Ext.chart.series.Pie', { shadowAttr = shadowAttributes[shindex]; shadow = shadowGroups[shindex].getAt(i); if (!shadow) { - shadow = chart.surface.add(Ext.apply({}, - { + shadow = chart.surface.add(Ext.apply({}, { type: 'path', group: shadowGroups[shindex], strokeLinejoin: "round" - }, - rendererAttributes, shadowAttr)); + }, rendererAttributes, shadowAttr)); } if (animate) { - rendererAttributes = me.renderer(shadow, store.getAt(i), Ext.apply({}, - rendererAttributes, shadowAttr), i, store); + shadowAttr = me.renderer(shadow, store.getAt(i), Ext.apply({}, rendererAttributes, shadowAttr), i, store); me.onAnimate(shadow, { - to: rendererAttributes + to: shadowAttr }); } else { - rendererAttributes = me.renderer(shadow, store.getAt(i), Ext.apply(shadowAttr, { + shadowAttr = me.renderer(shadow, store.getAt(i), Ext.apply(shadowAttr, { hidden: false }), i, store); - shadow.setAttributes(rendererAttributes, true); + shadow.setAttributes(shadowAttr, true); } shadows.push(shadow); } @@ -49770,85 +50077,83 @@ Ext.define('Ext.chart.series.Pie', { * As with all other series, the Radar series must be appended in the *series* Chart array configuration. See the Chart * documentation for more information. A typical configuration object for the radar series could be: * - {@img Ext.chart.series.Radar/Ext.chart.series.Radar.png Ext.chart.series.Radar chart series} -

-    var store = Ext.create('Ext.data.JsonStore', {
-        fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
-        data: [
-            {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
-            {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
-            {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
-            {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
-            {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}                                                
-        ]
-    });
-    
-    Ext.create('Ext.chart.Chart', {
-        renderTo: Ext.getBody(),
-        width: 500,
-        height: 300,
-        animate: true,
-        theme:'Category2',
-        store: store,
-        axes: [{
-            type: 'Radial',
-            position: 'radial',
-            label: {
-                display: true
-            }
-        }],
-        series: [{
-            type: 'radar',
-            xField: 'name',
-            yField: 'data3',
-            showInLegend: true,
-            showMarkers: true,
-            markerConfig: {
-                radius: 5,
-                size: 5           
-            },
-            style: {
-                'stroke-width': 2,
-                fill: 'none'
-            }
-        },{
-            type: 'radar',
-            xField: 'name',
-            yField: 'data2',
-            showMarkers: true,
-            showInLegend: true,
-            markerConfig: {
-                radius: 5,
-                size: 5
-            },
-            style: {
-                'stroke-width': 2,
-                fill: 'none'
-            }
-        },{
-            type: 'radar',
-            xField: 'name',
-            yField: 'data5',
-            showMarkers: true,
-            showInLegend: true,
-            markerConfig: {
-                radius: 5,
-                size: 5
-            },
-            style: {
-                'stroke-width': 2,
-                fill: 'none'
-            }
-        }]    
-    });
-   
+ * {@img Ext.chart.series.Radar/Ext.chart.series.Radar.png Ext.chart.series.Radar chart series} + * + * var store = Ext.create('Ext.data.JsonStore', { + * fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'], + * data: [ + * {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13}, + * {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3}, + * {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7}, + * {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23}, + * {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33} + * ] + * }); + * + * Ext.create('Ext.chart.Chart', { + * renderTo: Ext.getBody(), + * width: 500, + * height: 300, + * animate: true, + * theme:'Category2', + * store: store, + * axes: [{ + * type: 'Radial', + * position: 'radial', + * label: { + * display: true + * } + * }], + * series: [{ + * type: 'radar', + * xField: 'name', + * yField: 'data3', + * showInLegend: true, + * showMarkers: true, + * markerConfig: { + * radius: 5, + * size: 5 + * }, + * style: { + * 'stroke-width': 2, + * fill: 'none' + * } + * },{ + * type: 'radar', + * xField: 'name', + * yField: 'data2', + * showMarkers: true, + * showInLegend: true, + * markerConfig: { + * radius: 5, + * size: 5 + * }, + * style: { + * 'stroke-width': 2, + * fill: 'none' + * } + * },{ + * type: 'radar', + * xField: 'name', + * yField: 'data5', + * showMarkers: true, + * showInLegend: true, + * markerConfig: { + * radius: 5, + * size: 5 + * }, + * style: { + * 'stroke-width': 2, + * fill: 'none' + * } + * }] + * }); * * In this configuration we add three series to the chart. Each of these series is bound to the same categories field, `name` but bound to different properties for each category, * `data1`, `data2` and `data3` respectively. All series display markers by having `showMarkers` enabled. The configuration for the markers of each series can be set by adding properties onto * the markerConfig object. Finally we override some theme styling properties by adding properties to the `style` object. * * @xtype radar - * */ Ext.define('Ext.chart.series.Radar', { @@ -50191,61 +50496,59 @@ Ext.define('Ext.chart.series.Radar', { * As with all other series, the Scatter Series must be appended in the *series* Chart array configuration. See the Chart * documentation for more information on creating charts. A typical configuration object for the scatter could be: * -{@img Ext.chart.series.Scatter/Ext.chart.series.Scatter.png Ext.chart.series.Scatter chart series} -

-    var store = Ext.create('Ext.data.JsonStore', {
-        fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
-        data: [
-            {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
-            {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
-            {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
-            {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
-            {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}                                                
-        ]
-    });
-    
-    Ext.create('Ext.chart.Chart', {
-        renderTo: Ext.getBody(),
-        width: 500,
-        height: 300,
-        animate: true,
-        theme:'Category2',
-        store: store,
-        axes: [{
-            type: 'Numeric',
-            position: 'bottom',
-            fields: ['data1', 'data2', 'data3'],
-            title: 'Sample Values',
-            grid: true,
-            minimum: 0
-        }, {
-            type: 'Category',
-            position: 'left',
-            fields: ['name'],
-            title: 'Sample Metrics'
-        }],
-        series: [{
-            type: 'scatter',
-            markerConfig: {
-                radius: 5,
-                size: 5
-            },
-            axis: 'left',
-            xField: 'name',
-            yField: 'data2'
-        }, {
-            type: 'scatter',
-            markerConfig: {
-                radius: 5,
-                size: 5
-            },
-            axis: 'left',
-            xField: 'name',
-            yField: 'data3'
-        }]   
-    });
-   
- + * {@img Ext.chart.series.Scatter/Ext.chart.series.Scatter.png Ext.chart.series.Scatter chart series} + * + * var store = Ext.create('Ext.data.JsonStore', { + * fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'], + * data: [ + * {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13}, + * {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3}, + * {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7}, + * {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23}, + * {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33} + * ] + * }); + * + * Ext.create('Ext.chart.Chart', { + * renderTo: Ext.getBody(), + * width: 500, + * height: 300, + * animate: true, + * theme:'Category2', + * store: store, + * axes: [{ + * type: 'Numeric', + * position: 'bottom', + * fields: ['data1', 'data2', 'data3'], + * title: 'Sample Values', + * grid: true, + * minimum: 0 + * }, { + * type: 'Category', + * position: 'left', + * fields: ['name'], + * title: 'Sample Metrics' + * }], + * series: [{ + * type: 'scatter', + * markerConfig: { + * radius: 5, + * size: 5 + * }, + * axis: 'left', + * xField: 'name', + * yField: 'data2' + * }, { + * type: 'scatter', + * markerConfig: { + * radius: 5, + * size: 5 + * }, + * axis: 'left', + * xField: 'name', + * yField: 'data3' + * }] + * }); * * In this configuration we add three different categories of scatter series. Each of them is bound to a different field of the same data store, * `data1`, `data2` and `data3` respectively. All x-fields for the series must be the same field, in this case `name`. @@ -50253,7 +50556,6 @@ Ext.define('Ext.chart.series.Radar', { * axis to show the current values of the elements. * * @xtype scatter - * */ Ext.define('Ext.chart.series.Scatter', { @@ -52718,6 +53020,11 @@ Ext.define('Ext.data.JsonP', { * key value pairs that will be sent along with the request. *
  • timeout : Number (Optional)
    See {@link #timeout}
  • *
  • callbackKey : String (Optional)
    See {@link #callbackKey}
  • + *
  • callbackName : String (Optional)
    The function name to use for this request. + * By default this name will be auto-generated: Ext.data.JsonP.callback1, Ext.data.JsonP.callback2, etc. + * Setting this option to "my_name" will force the function name to be Ext.data.JsonP.my_name. + * Use this if you want deterministic behavior, but be careful - the callbackName should be different + * in each JsonP request that you make.
  • *
  • disableCaching : Boolean (Optional)
    See {@link #disableCaching}
  • *
  • disableCachingParam : String (Optional)
    See {@link #disableCachingParam}
  • *
  • success : Function (Optional)
    A function to execute if the request succeeds.
  • @@ -52742,7 +53049,7 @@ Ext.define('Ext.data.JsonP', { disableCaching = Ext.isDefined(options.disableCaching) ? options.disableCaching : me.disableCaching, cacheParam = options.disableCachingParam || me.disableCachingParam, id = ++me.statics().requestCount, - callbackName = 'callback' + id, + callbackName = options.callbackName || 'callback' + id, callbackKey = options.callbackKey || me.callbackKey, timeout = Ext.isDefined(options.timeout) ? options.timeout : me.timeout, params = Ext.apply({}, options.params), @@ -53468,7 +53775,8 @@ Ext.define('Ext.data.NodeInterface', { * 2) When destroy on the tree is called * 3) For destroying child nodes on a node */ - var me = this; + var me = this, + options = me.destroyOptions; if (silent === true) { me.clear(true); @@ -53476,11 +53784,13 @@ Ext.define('Ext.data.NodeInterface', { n.destroy(true); }); me.childNodes = null; + delete me.destroyOptions; + me.callOverridden([options]); } else { + me.destroyOptions = silent; + // overridden method will be called, since remove will end up calling destroy(true); me.remove(true); } - - me.callOverridden(); }, /** @@ -55091,7 +55401,7 @@ Ext.define('Ext.data.TreeStore', { original, index; - /** + /* * Loop over each record returned from the server. Assume they are * returned in order of how they were sent. If we find a matching * record, replace it with the newly created one. @@ -55159,7 +55469,7 @@ Ext.define('Ext.data.TreeStore', { // inherit docs removeAll: function() { - this.getRootNode().destroy(); + this.getRootNode().destroy(true); this.fireEvent('clear', this); }, @@ -56668,6 +56978,10 @@ Ext.define('Ext.data.reader.Xml', { alternateClassName: 'Ext.data.XmlReader', alias : 'reader.xml', + /** + * @cfg {String} record The DomQuery path to the repeated element which contains record information. + */ + /** * @private * Creates a function to return some particular key of data from a response. The totalProperty and @@ -56675,39 +56989,24 @@ Ext.define('Ext.data.reader.Xml', { * @param {String} key * @return {Function} */ - - /** - * @cfg {String} record The DomQuery path to the repeated element which contains record information. - */ - - createAccessor: function() { - var selectValue = function(expr, root){ + createAccessor: function(expr) { + var me = this; + + if (Ext.isEmpty(expr)) { + return Ext.emptyFn; + } + + if (Ext.isFunction(expr)) { + return expr; + } + + return function(root) { var node = Ext.DomQuery.selectNode(expr, root), - val; + val = me.getNodeValue(node); - - + return Ext.isEmpty(val) ? null : val; }; - - return function(expr) { - var me = this; - - if (Ext.isEmpty(expr)) { - return Ext.emptyFn; - } - - if (Ext.isFunction(expr)) { - return expr; - } - - return function(root) { - var node = Ext.DomQuery.selectNode(expr, root), - val = me.getNodeValue(node); - - return Ext.isEmpty(val) ? null : val; - }; - }; - }(), + }, getNodeValue: function(node) { var val; @@ -56821,8 +57120,13 @@ Ext.define('Ext.data.reader.Xml', { * @author Ed Spencer * @class Ext.data.writer.Xml * @extends Ext.data.writer.Writer - * - *

    Writer that outputs model data in XML format

    + +This class is used to write {@link Ext.data.Model} data to the server in an XML format. +The {@link #documentRoot} property is used to specify the root element in the XML document. +The {@link #record} option is used to specify the element name for each record that will make +up the XML document. + + * @markdown */ Ext.define('Ext.data.writer.Xml', { @@ -57068,11 +57372,13 @@ p.disconnect(); /** * Abstract methods for subclasses to implement. + * @method */ connect: Ext.emptyFn, /** * Abstract methods for subclasses to implement. + * @method */ disconnect: Ext.emptyFn }); @@ -57528,7 +57834,7 @@ TestAction.multiply( /** * @cfg {String} url - * Required. The url to connect to the {@link Ext.direct.Manager} server-side router. + * Required. The url to connect to the {@link Ext.direct.Manager} server-side router. */ /** @@ -58223,7 +58529,7 @@ Ext.define('Ext.draw.SpriteDD', { * A Sprite is an object rendered in a Drawing surface. There are different options and types of sprites. * The configuration of a Sprite is an object with the following properties: * - * - **type** - (String) The type of the sprite. Possible options are 'circle', 'path', 'rect', 'text', 'square'. + * - **type** - (String) The type of the sprite. Possible options are 'circle', 'path', 'rect', 'text', 'square', 'image'. * - **width** - (Number) Used in rectangle sprites, the width of the rectangle. * - **height** - (Number) Used in rectangle sprites, the height of the rectangle. * - **size** - (Number) Used in square sprites, the dimension of the square. @@ -58406,7 +58712,7 @@ Ext.define('Ext.draw.Sprite', { me.draggable = true; //create element if it doesn't exist. if (!me.el) { - me.surface.createSprite(me); + me.surface.createSpriteElement(me); } me.dd = Ext.create('Ext.draw.SpriteDD', me, Ext.isBoolean(me.draggable) ? null : me.draggable); me.on('beforedestroy', me.dd.destroy, me.dd); @@ -58429,6 +58735,7 @@ Ext.define('Ext.draw.Sprite', { spriteAttrs = me.attr, attr, i, translate, translation, rotate, rotation, scale, scaling; + attrs = Ext.apply({}, attrs); for (attr in custom) { if (attrs.hasOwnProperty(attr) && typeof custom[attr] == "function") { Ext.apply(attrs, custom[attr].apply(me, [].concat(attrs[attr]))); @@ -59068,8 +59375,8 @@ Ext.define('Ext.draw.engine.Svg', { attrs = me.scrubAttrs(sprite) || {}; // if (sprite.dirtyPath) { - sprite.bbox.plain = 0; - sprite.bbox.transform = 0; + sprite.bbox.plain = 0; + sprite.bbox.transform = 0; if (sprite.type == "circle" || sprite.type == "ellipse") { attrs.cx = attrs.cx || attrs.x; attrs.cy = attrs.cy || attrs.y; @@ -59078,10 +59385,14 @@ Ext.define('Ext.draw.engine.Svg', { attrs.rx = attrs.ry = attrs.r; } else if (sprite.type == "path" && attrs.d) { - attrs.d = Ext.draw.Draw.pathToAbsolute(attrs.d); + attrs.d = Ext.draw.Draw.pathToString(Ext.draw.Draw.pathToAbsolute(attrs.d)); + } sprite.dirtyPath = false; // } + // else { + // delete attrs.d; + // } if (attrs['clip-rect']) { me.setClip(sprite, attrs); @@ -59102,7 +59413,7 @@ Ext.define('Ext.draw.engine.Svg', { } for (key in attrs) { if (attrs.hasOwnProperty(key) && attrs[key] != null) { - el.dom.setAttribute(key, String(attrs[key])); + el.dom.setAttribute(key, attrs[key]); } } if (sprite.type == 'text') { @@ -60340,7 +60651,7 @@ Ext.define('Ext.layout.container.AbstractFit', { layout:'fit', items: { title: 'Inner Panel', - html: '

    This is the inner panel content

    ', + html: 'This is the inner panel content', bodyPadding: 20, border: false }, @@ -60691,24 +61002,44 @@ Ext.define('Ext.selection.Model', { } }, - selectAll: function(silent) { - var selections = this.store.getRange(), + /** + * Select all records in the view. + * @param {Boolean} suppressEvent True to suppress any selects event + */ + selectAll: function(suppressEvent) { + var me = this, + selections = me.store.getRange(), i = 0, - len = selections.length; + len = selections.length, + start = me.getSelection().length; + me.bulkChange = true; for (; i < len; i++) { - this.doSelect(selections[i], true, silent); + me.doSelect(selections[i], true, suppressEvent); } + delete me.bulkChange; + // fire selection change only if the number of selections differs + me.maybeFireSelectionChange(me.getSelection().length !== start); }, - deselectAll: function() { - var selections = this.getSelection(), + /** + * Deselect all records in the view. + * @param {Boolean} suppressEvent True to suppress any deselect events + */ + deselectAll: function(suppressEvent) { + var me = this, + selections = me.getSelection(), i = 0, - len = selections.length; + len = selections.length, + start = me.getSelection().length; + me.bulkChange = true; for (; i < len; i++) { - this.doDeselect(selections[i]); + me.doDeselect(selections[i], suppressEvent); } + delete me.bulkChange; + // fire selection change only if the number of selections differs + me.maybeFireSelectionChange(me.getSelection().length !== start); }, // Provides differentiation of logic between MULTI, SIMPLE and SINGLE @@ -60865,7 +61196,7 @@ Ext.define('Ext.selection.Model', { len = records.length; if (!keepExisting && selected.getCount() > 0) { change = true; - me.doDeselect(me.getSelection(), true); + me.doDeselect(me.getSelection(), suppressEvent); } for (; i < len; i++) { @@ -60964,8 +61295,8 @@ Ext.define('Ext.selection.Model', { // fire selection change as long as true is not passed // into maybeFireSelectionChange maybeFireSelectionChange: function(fireEvent) { - if (fireEvent) { - var me = this; + var me = this; + if (fireEvent && !me.bulkChange) { me.fireEvent('selectionchange', me, me.getSelection()); } }, @@ -61081,6 +61412,11 @@ Ext.define('Ext.selection.Model', { me.maybeFireSelectionChange(change); }, + /** + * A fast reset of the selections without firing events, updating the ui, etc. + * For private usage only. + * @private + */ clearSelections: function() { // reset the entire selection to nothing var me = this; @@ -61565,6 +61901,7 @@ Ext.define('Ext.util.Point', { * Or the x value is using the two argument form. * @param {Number} The y value unless using an Offset object. * @return {Ext.util.Region} this This Region + * @method */ this.prototype.translate = Ext.util.Region.prototype.translateBy; }); @@ -62356,7 +62693,9 @@ Ext.define('Ext.view.AbstractView', { * @return {Number} The node count */ getSelectionCount : function(){ - console.warn("DataView: getSelectionCount will be removed, please interact with the Ext.selection.DataViewModel"); + if (Ext.global.console) { + Ext.global.console.warn("DataView: getSelectionCount will be removed, please interact with the Ext.selection.DataViewModel"); + } return this.selModel.getSelection().length; }, @@ -62365,18 +62704,24 @@ Ext.define('Ext.view.AbstractView', { * @return {Array} An array of {@link Ext.data.Model} objects */ getSelectedRecords : function(){ - console.warn("DataView: getSelectedRecords will be removed, please interact with the Ext.selection.DataViewModel"); + if (Ext.global.console) { + Ext.global.console.warn("DataView: getSelectedRecords will be removed, please interact with the Ext.selection.DataViewModel"); + } return this.selModel.getSelection(); }, select: function(records, keepExisting, supressEvents) { - console.warn("DataView: select will be removed, please access select through a DataView's SelectionModel, ie: view.getSelectionModel().select()"); + if (Ext.global.console) { + Ext.global.console.warn("DataView: select will be removed, please access select through a DataView's SelectionModel, ie: view.getSelectionModel().select()"); + } var sm = this.getSelectionModel(); return sm.select.apply(sm, arguments); }, clearSelections: function() { - console.warn("DataView: clearSelections will be removed, please access deselectAll through DataView's SelectionModel, ie: view.getSelectionModel().deselectAll()"); + if (Ext.global.console) { + Ext.global.console.warn("DataView: clearSelections will be removed, please access deselectAll through DataView's SelectionModel, ie: view.getSelectionModel().deselectAll()"); + } var sm = this.getSelectionModel(); return sm.deselectAll(); } @@ -62615,9 +62960,12 @@ Ext.define('Ext.Action', { // 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); + var items = this.items, + i = 0, + len = items.length; + + for(; i < len; i++){ + items[i][fnName].apply(items[i], args); } }, @@ -62629,7 +62977,7 @@ Ext.define('Ext.Action', { // private removeComponent : function(comp){ - this.items.remove(comp); + Ext.Array.remove(this.items, comp); }, /** @@ -63205,6 +63553,9 @@ Ext.define('Ext.Img', { }; }, + // null out this function, we can't set any html inside the image + initRenderTpl: Ext.emptyFn, + /** * Updates the {@link #src} of the image */ @@ -64395,25 +64746,25 @@ Ext.define('Ext.button.Split', { * {@img Ext.button.Cycle/Ext.button.Cycle.png Ext.button.Cycle component} * Example usage: *
    
    -    Ext.create('Ext.button.Cycle', {
    -        showText: true,
    -        prependText: 'View as ',
    -        renderTo: Ext.getBody(),
    -        menu: {
    -            id: 'view-type-menu',
    -            items: [{
    -                text:'text only',
    -                iconCls:'view-text',
    -                checked:true
    -            },{
    -                text:'HTML',
    -                iconCls:'view-html'
    -            }]
    -        },
    -        changeHandler:function(cycleBtn, activeItem){
    -            Ext.Msg.alert('Change View', activeItem.text);
    -        }
    -    });
    +Ext.create('Ext.button.Cycle', {
    +    showText: true,
    +    prependText: 'View as ',
    +    renderTo: Ext.getBody(),
    +    menu: {
    +        id: 'view-type-menu',
    +        items: [{
    +            text:'text only',
    +            iconCls:'view-text',
    +            checked:true
    +        },{
    +            text:'HTML',
    +            iconCls:'view-html'
    +        }]
    +    },
    +    changeHandler:function(cycleBtn, activeItem){
    +        Ext.Msg.alert('Change View', activeItem.text);
    +    }
    +});
     
    * @constructor * Create a new split button @@ -65243,6 +65594,13 @@ Ext.define('Ext.dd.DragTracker', { */ 'mousemove', + /** + * @event beforestart + * @param {Object} this + * @param {Object} e event object + */ + 'beforedragstart', + /** * @event dragstart * @param {Object} this @@ -65369,27 +65727,30 @@ Ext.define('Ext.dd.DragTracker', { this.startXY = this.lastXY = e.getXY(); this.startRegion = Ext.fly(this.dragTarget).getRegion(); - if (this.fireEvent('mousedown', this, e) !== false && this.onBeforeStart(e) !== false) { + if (this.fireEvent('mousedown', this, e) === false || + this.fireEvent('beforedragstart', this, e) === false || + this.onBeforeStart(e) === false) { + return; + } - // Track when the mouse is down so that mouseouts while the mouse is down are not processed. - // The onMouseOut method will only ever be called after mouseup. - this.mouseIsDown = true; + // Track when the mouse is down so that mouseouts while the mouse is down are not processed. + // The onMouseOut method will only ever be called after mouseup. + this.mouseIsDown = true; - // Flag for downstream DragTracker instances that the mouse is being tracked. - e.dragTracked = true; + // Flag for downstream DragTracker instances that the mouse is being tracked. + e.dragTracked = true; - if (this.preventDefault !== false) { - e.preventDefault(); - } - Ext.getDoc().on({ - scope: this, - mouseup: this.onMouseUp, - mousemove: this.onMouseMove, - selectstart: this.stopSelect - }); - if (this.autoStart) { - this.timer = Ext.defer(this.triggerStart, this.autoStart === true ? 1000 : this.autoStart, this, [e]); - } + if (this.preventDefault !== false) { + e.preventDefault(); + } + Ext.getDoc().on({ + scope: this, + mouseup: this.onMouseUp, + mousemove: this.onMouseMove, + selectstart: this.stopSelect + }); + if (this.autoStart) { + this.timer = Ext.defer(this.triggerStart, this.autoStart === true ? 1000 : this.autoStart, this, [e]); } }, @@ -65558,7 +65919,7 @@ Ext.define('Ext.dd.DragTracker', { }, getXY : function(constrain){ - return constrain ? this.constrainModes[constrain].call(this, this.lastXY) : this.lastXY; + return constrain ? this.constrainModes[constrain](this, this.lastXY) : this.lastXY; }, /** @@ -65585,9 +65946,9 @@ Ext.define('Ext.dd.DragTracker', { constrainModes: { // Constrain the passed point to within the constrain region - point: function(xy) { - var dr = this.dragRegion, - constrainTo = this.getConstrainRegion(); + point: function(me, xy) { + var dr = me.dragRegion, + constrainTo = me.getConstrainRegion(); // No constraint if (!constrainTo) { @@ -65602,10 +65963,10 @@ Ext.define('Ext.dd.DragTracker', { }, // Constrain the dragTarget to within the constrain region. Return the passed xy adjusted by the same delta. - dragTarget: function(xy) { - var s = this.startXY, - dr = this.startRegion.copy(), - constrainTo = this.getConstrainRegion(), + dragTarget: function(me, xy) { + var s = me.startXY, + dr = me.startRegion.copy(), + constrainTo = me.getConstrainRegion(), adjust; // No constraint @@ -65616,7 +65977,7 @@ Ext.define('Ext.dd.DragTracker', { // See where the passed XY would put the dragTarget if translated by the unconstrained offset. // If it overflows, we constrain the passed XY to bring the potential // region back within the boundary. - dr.translateBy.apply(dr, [xy[0]-s[0], xy[1]-s[1]]); + dr.translateBy(xy[0]-s[0], xy[1]-s[1]); // Constrain the X coordinate by however much the dragTarget overflows if (dr.right > constrainTo.right) { @@ -65627,7 +65988,7 @@ Ext.define('Ext.dd.DragTracker', { xy[0] += (constrainTo.left - dr.left); // overflowed the left } - // Constrain the X coordinate by however much the dragTarget overflows + // Constrain the Y coordinate by however much the dragTarget overflows if (dr.bottom > constrainTo.bottom) { xy[1] += adjust = (constrainTo.bottom - dr.bottom); // overflowed the bottom dr.top += adjust; @@ -67212,7 +67573,7 @@ Ext.define('Ext.form.action.Submit', { tag: 'input', type: 'hidden', name: name, - value: val + value: Ext.String.htmlEncode(val) }); } @@ -67405,7 +67766,7 @@ Ext.define('Ext.util.ComponentDragger', { comp = (me.proxy && !me.comp.liveDrag) ? me.proxy : me.comp, offset = me.getOffset(me.constrain || me.constrainDelegate ? 'dragTarget' : null); - comp.setPosition.apply(comp, [me.startPosition[0] + offset[0], me.startPosition[1] + offset[1]]); + comp.setPosition(me.startPosition[0] + offset[0], me.startPosition[1] + offset[1]); }, onEnd: function(e) { @@ -68246,6 +68607,7 @@ Ext.define('Ext.form.field.Field', { * will not prevent submission of forms submitted with the {@link Ext.form.action.Submit#clientValidation} * option set.

    * @param {String/Array} errors The error message(s) for the field. + * @method */ markInvalid: Ext.emptyFn, @@ -68256,6 +68618,7 @@ Ext.define('Ext.form.field.Field', { * return true if the value does not pass validation. So simply clearing a field's errors * will not necessarily allow submission of forms submitted with the {@link Ext.form.action.Submit#clientValidation} * option set.

    + * @method */ clearInvalid: Ext.emptyFn @@ -68317,6 +68680,7 @@ Ext.define('Ext.layout.component.field.Field', { autoHeight: autoHeight, width: autoWidth ? owner.getBodyNaturalWidth() : width, //always give a pixel width height: height, + setOuterWidth: false, //whether the outer el width should be set to the calculated width // insets for the bodyEl from each side of the component layout area insets: { @@ -68354,9 +68718,9 @@ Ext.define('Ext.layout.component.field.Field', { // perform sizing of the elements based on the final dimensions and insets if (autoWidth && autoHeight) { // Don't use setTargetSize if auto-sized, so the calculated size is not reused next time - me.setElementSize(owner.el, info.width, info.height); + me.setElementSize(owner.el, (info.setOuterWidth ? info.width : undef), info.height); } else { - me.setTargetSize(info.width, info.height); + me.setTargetSize((!autoWidth || info.setOuterWidth ? info.width : undef), info.height); } me.sizeBody(info); @@ -68446,6 +68810,8 @@ Ext.define('Ext.layout.component.field.Field', { if (info.autoWidth) { info.width += (!owner.labelEl ? 0 : owner.labelWidth + owner.labelPad); } + // Must set outer width to prevent field from wrapping below floated label + info.setOuterWidth = true; }, adjustHorizInsets: function(owner, info) { if (owner.labelEl) { @@ -68913,39 +69279,44 @@ Ext.define('Ext.layout.component.field.TextArea', { /** * @class Ext.layout.container.Anchor * @extends Ext.layout.container.Container - *

    This is a layout that enables anchoring of contained elements relative to the container's dimensions. + * + * 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 - * {@link #anchor} rules.

    - *

    This class is intended to be extended or created via the layout: 'anchor' {@link Ext.layout.container.AbstractContainer#layout} + * {@link #anchor} rules. + * + * This class is intended to be extended or created via the layout: 'anchor' {@link Ext.layout.container.AbstractContainer#layout} * config, and should generally not need to be created directly via the new keyword.

    - *

    AnchorLayout does not have any direct config options (other than inherited ones). By default, + * + * 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 anchorSize. * 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. + * * {@img Ext.layout.container.Anchor/Ext.layout.container.Anchor.png Ext.layout.container.Anchor container layout} + * * For example: - Ext.create('Ext.Panel', { - width: 500, - height: 400, - title: "AnchorLayout Panel", - layout: 'anchor', - renderTo: Ext.getBody(), - items: [{ - xtype: 'panel', - title: '75% Width and 20% Height', - anchor: '75% 20%' - },{ - xtype: 'panel', - title: 'Offset -300 Width & -200 Height', - anchor: '-300 -200' - },{ - xtype: 'panel', - title: 'Mixed Offset and Percent', - anchor: '-250 20%' - }] - }); + * Ext.create('Ext.Panel', { + * width: 500, + * height: 400, + * title: "AnchorLayout Panel", + * layout: 'anchor', + * renderTo: Ext.getBody(), + * items: [{ + * xtype: 'panel', + * title: '75% Width and 20% Height', + * anchor: '75% 20%' + * },{ + * xtype: 'panel', + * title: 'Offset -300 Width & -200 Height', + * anchor: '-300 -200' + * },{ + * xtype: 'panel', + * title: 'Mixed Offset and Percent', + * anchor: '-250 20%' + * }] + * }); */ Ext.define('Ext.layout.container.Anchor', { @@ -69033,7 +69404,7 @@ anchor: '-50 75%' len = components.length, boxes = [], box, newTargetSize, anchorWidth, anchorHeight, component, anchorSpec, calcWidth, calcHeight, - anchorsArray, anchor, i, el; + anchorsArray, anchor, i, el, cleaner; if (ownerWidth < 20 && ownerHeight < 20) { return; @@ -69066,6 +69437,7 @@ anchor: '-50 75%' // Work around WebKit RightMargin bug. We're going to inline-block all the children only ONCE and remove it when we're done if (!Ext.supports.RightMargin) { + cleaner = Ext.core.Element.getRightMarginFixCleaner(target); target.addCls(Ext.baseCSSPrefix + 'inline-children'); } @@ -69108,6 +69480,7 @@ anchor: '-50 75%' // Work around WebKit RightMargin bug. We're going to inline-block all the children only ONCE and remove it when we're done if (!Ext.supports.RightMargin) { target.removeCls(Ext.baseCSSPrefix + 'inline-children'); + cleaner(); } for (i = 0; i < len; i++) { @@ -69639,7 +70012,15 @@ Ext.define('Ext.window.Window', { if (me.closable) { keyMap = me.getKeyMap(); keyMap.on(27, me.onEsc, me); - keyMap.disable(); + + //if (hidden) { ? would be consistent w/before/afterShow... + keyMap.disable(); + //} + } + + if (!hidden) { + me.syncMonitorWindowResize(); + me.doConstrain(); } }, @@ -69656,33 +70037,40 @@ Ext.define('Ext.window.Window', { if (!me.header) { me.updateHeader(true); } + + /* + * Check the header here again. If for whatever reason it wasn't created in + * updateHeader (preventHeader) then we'll just ignore the rest since the + * header acts as the drag handle. + */ + if (me.header) { + ddConfig = Ext.applyIf({ + el: me.el, + delegate: '#' + me.header.id + }, me.draggable); - ddConfig = Ext.applyIf({ - el: me.el, - delegate: '#' + me.header.id - }, me.draggable); + // Add extra configs if Window is specified to be constrained + if (me.constrain || me.constrainHeader) { + ddConfig.constrain = me.constrain; + ddConfig.constrainDelegate = me.constrainHeader; + ddConfig.constrainTo = me.constrainTo || me.container; + } - // Add extra configs if Window is specified to be constrained - if (me.constrain || me.constrainHeader) { - ddConfig.constrain = me.constrain; - ddConfig.constrainDelegate = me.constrainHeader; - ddConfig.constrainTo = me.constrainTo || me.container; + /** + *

    If this Window is configured {@link #draggable}, this property will contain + * an instance of {@link Ext.util.ComponentDragger} (A subclass of {@link Ext.dd.DragTracker DragTracker}) + * which handles dragging the Window's DOM Element, and constraining according to the {@link #constrain} + * and {@link #constrainHeader} .

    + *

    This has implementations of onBeforeStart, onDrag and onEnd + * which perform the dragging action. If extra logic is needed at these points, use + * {@link Ext.Function#createInterceptor createInterceptor} or {@link Ext.Function#createSequence createSequence} to + * augment the existing implementations.

    + * @type Ext.util.ComponentDragger + * @property dd + */ + me.dd = Ext.create('Ext.util.ComponentDragger', this, ddConfig); + me.relayEvents(me.dd, ['dragstart', 'drag', 'dragend']); } - - /** - *

    If this Window is configured {@link #draggable}, this property will contain - * an instance of {@link Ext.util.ComponentDragger} (A subclass of {@link Ext.dd.DragTracker DragTracker}) - * which handles dragging the Window's DOM Element, and constraining according to the {@link #constrain} - * and {@link #constrainHeader} .

    - *

    This has implementations of onBeforeStart, onDrag and onEnd - * which perform the dragging action. If extra logic is needed at these points, use - * {@link Ext.Function#createInterceptor createInterceptor} or {@link Ext.Function#createSequence createSequence} to - * augment the existing implementations.

    - * @type Ext.util.ComponentDragger - * @property dd - */ - me.dd = Ext.create('Ext.util.ComponentDragger', this, ddConfig); - me.relayEvents(me.dd, ['dragstart', 'drag', 'dragend']); }, // private @@ -69770,8 +70158,7 @@ Ext.define('Ext.window.Window', { // private afterShow: function(animateTarget) { - var me = this, - size; + var me = this; // Perform superclass's afterShow tasks // Which might include animating a proxy from an animTarget @@ -69781,10 +70168,9 @@ Ext.define('Ext.window.Window', { me.fitContainer(); } - if (me.monitorResize || me.constrain || me.constrainHeader) { - Ext.EventManager.onWindowResize(me.onWindowResize, me); - } + me.syncMonitorWindowResize(); me.doConstrain(); + if (me.keyMap) { me.keyMap.enable(); } @@ -69809,9 +70195,7 @@ Ext.define('Ext.window.Window', { var me = this; // No longer subscribe to resizing now that we're hidden - if (me.monitorResize || me.constrain || me.constrainHeader) { - Ext.EventManager.removeResizeListener(me.onWindowResize, me); - } + me.syncMonitorWindowResize(); // Turn off keyboard handling once window is hidden if (me.keyMap) { @@ -69899,6 +70283,7 @@ Ext.define('Ext.window.Window', { me.el.addCls(Ext.baseCSSPrefix + 'window-maximized'); me.container.addCls(Ext.baseCSSPrefix + 'window-maximized-ct'); + me.syncMonitorWindowResize(); me.setPosition(0, 0); me.fitContainer(); me.fireEvent('maximize', me); @@ -69951,12 +70336,40 @@ Ext.define('Ext.window.Window', { me.container.removeCls(Ext.baseCSSPrefix + 'window-maximized-ct'); + me.syncMonitorWindowResize(); me.doConstrain(); me.fireEvent('restore', me); } return me; }, + /** + * Synchronizes the presence of our listener for window resize events. This method + * should be called whenever this status might change. + * @private + */ + syncMonitorWindowResize: function () { + var me = this, + currentlyMonitoring = me._monitoringResize, + // all the states where we should be listening to window resize: + yes = me.monitorResize || me.constrain || me.constrainHeader || me.maximized, + // all the states where we veto this: + veto = me.hidden || me.destroying || me.isDestroyed; + + if (yes && !veto) { + // we should be listening... + if (!currentlyMonitoring) { + // but we aren't, so set it up + Ext.EventManager.onWindowResize(me.onWindowResize, me); + me._monitoringResize = true; + } + } else if (currentlyMonitoring) { + // we should not be listening, but we are, so tear it down + Ext.EventManager.removeResizeListener(me.onWindowResize, me); + me._monitoringResize = false; + } + }, + /** * A shortcut method for toggling between {@link #maximize} and {@link #restore} based on the current maximized * state of the window. @@ -71654,7 +72067,7 @@ Ext.define('Ext.window.MessageBox', { 'Ext.layout.container.HBox', 'Ext.ProgressBar' ], - + alternateClassName: 'Ext.MessageBox', alias: 'widget.messagebox', @@ -71776,7 +72189,7 @@ Ext.define('Ext.window.MessageBox', { wait: 'Loading...', alert: 'Attention' }, - + iconHeight: 35, makeButton: function(btnIdx) { @@ -71900,7 +72313,7 @@ Ext.define('Ext.window.MessageBox', { onPromptKey: function(textField, e) { var me = this, blur; - + if (e.keyCode === Ext.EventObject.RETURN || e.keyCode === 10) { if (me.msgButtons.ok.isVisible()) { blur = true; @@ -71909,7 +72322,7 @@ Ext.define('Ext.window.MessageBox', { me.msgButtons.yes.handler.call(me, me.msgButtons.yes); blur = true; } - + if (blur) { me.textField.blur(); } @@ -71931,7 +72344,7 @@ Ext.define('Ext.window.MessageBox', { // Default to allowing the Window to take focus. delete me.defaultFocus; - + // clear any old animateTarget me.animateTarget = cfg.animateTarget || undefined; @@ -71947,6 +72360,7 @@ Ext.define('Ext.window.MessageBox', { me.width = initialWidth; me.render(Ext.getBody()); } else { + me.hidden = false; me.setSize(initialWidth, me.maxHeight); } me.setPosition(-10000, -10000); @@ -72113,7 +72527,7 @@ icon: Ext.window.MessageBox.INFO */ show: function(cfg) { var me = this; - + me.reconfigure(cfg); me.addCls(cfg.cls); if (cfg.animateTarget) { @@ -72125,11 +72539,11 @@ icon: Ext.window.MessageBox.INFO } return me; }, - + afterShow: function(){ if (this.animateTarget) { this.center(); - } + } this.callParent(arguments); }, @@ -72141,7 +72555,7 @@ icon: Ext.window.MessageBox.INFO if (!Ext.isDefined(me.frameWidth)) { me.frameWidth = me.el.getWidth() - me.body.getWidth(); } - + // reset to the original dimensions icon.setHeight(iconHeight); @@ -72434,7 +72848,7 @@ Ext.define('Ext.form.Basic', { extend: 'Ext.util.Observable', alternateClassName: 'Ext.form.BasicForm', requires: ['Ext.util.MixedCollection', 'Ext.form.action.Load', 'Ext.form.action.Submit', - 'Ext.window.MessageBox', 'Ext.data.Errors'], + 'Ext.window.MessageBox', 'Ext.data.Errors', 'Ext.util.DelayedTask'], constructor: function(owner, config) { var me = this, @@ -72461,6 +72875,8 @@ Ext.define('Ext.form.Basic', { me.paramOrder = me.paramOrder.split(/[\s,|]/); } + me.checkValidityTask = Ext.create('Ext.util.DelayedTask', me.checkValidity, me); + me.addEvents( /** * @event beforeaction @@ -72632,6 +73048,7 @@ paramOrder: 'param1|param2|param' */ destroy: function() { this.clearListeners(); + this.checkValidityTask.cancel(); }, /** @@ -72668,9 +73085,10 @@ paramOrder: 'param1|param2|param' // Flush the cached list of formBind components delete this._boundItems; - // Check form bind, but only after initial add + // Check form bind, but only after initial add. Batch it to prevent excessive validation + // calls when many fields are being added at once. if (me.initialized) { - me.onValidityChange(!me.hasInvalidField()); + me.checkValidityTask.delay(10); } }, @@ -73915,28 +74333,28 @@ Ext.define('Ext.form.FieldContainer', { * {@img Ext.form.RadioGroup/Ext.form.RadioGroup.png Ext.form.RadioGroup component} *

    Example usage:

    *
    
    -    Ext.create('Ext.form.Panel', {
    -        title: 'RadioGroup Example',
    -        width: 300,
    -        height: 125,
    -        bodyPadding: 10,
    -        renderTo: Ext.getBody(),        
    -        items:[{            
    -            xtype: 'radiogroup',
    -            fieldLabel: 'Two Columns',
    -            // Arrange radio buttons into two columns, distributed vertically
    -            columns: 2,
    -            vertical: true,
    -            items: [
    -                {boxLabel: 'Item 1', name: 'rb', inputValue: '1'},
    -                {boxLabel: 'Item 2', name: 'rb', inputValue: '2', checked: true},
    -                {boxLabel: 'Item 3', name: 'rb', inputValue: '3'},
    -                {boxLabel: 'Item 4', name: 'rb', inputValue: '4'},
    -                {boxLabel: 'Item 5', name: 'rb', inputValue: '5'},
    -                {boxLabel: 'Item 6', name: 'rb', inputValue: '6'}
    -            ]
    -        }]
    -    });
    +Ext.create('Ext.form.Panel', {
    +    title: 'RadioGroup Example',
    +    width: 300,
    +    height: 125,
    +    bodyPadding: 10,
    +    renderTo: Ext.getBody(),        
    +    items:[{            
    +        xtype: 'radiogroup',
    +        fieldLabel: 'Two Columns',
    +        // Arrange radio buttons into two columns, distributed vertically
    +        columns: 2,
    +        vertical: true,
    +        items: [
    +            {boxLabel: 'Item 1', name: 'rb', inputValue: '1'},
    +            {boxLabel: 'Item 2', name: 'rb', inputValue: '2', checked: true},
    +            {boxLabel: 'Item 3', name: 'rb', inputValue: '3'},
    +            {boxLabel: 'Item 4', name: 'rb', inputValue: '4'},
    +            {boxLabel: 'Item 5', name: 'rb', inputValue: '5'},
    +            {boxLabel: 'Item 6', name: 'rb', inputValue: '6'}
    +        ]
    +    }]
    +});
      * 
    * @constructor * Creates a new CheckboxGroup @@ -74656,8 +75074,7 @@ Ext.define('Ext.form.FieldSet', { */ setExpanded: function(expanded) { var me = this, - checkboxCmp = me.checkboxCmp, - toggleCmp = me.toggleCmp; + checkboxCmp = me.checkboxCmp; expanded = !!expanded; @@ -74671,6 +75088,10 @@ Ext.define('Ext.form.FieldSet', { me.addCls(me.baseCls + '-collapsed'); } me.collapsed = !expanded; + if (expanded) { + // ensure subitems will get rendered and layed out when expanding + me.getComponentLayout().childrenChanged = true; + } me.doComponentLayout(); return me; }, @@ -75592,7 +76013,7 @@ __Example usage:__ var checkbox1 = Ext.getCmp('checkbox1'), checkbox2 = Ext.getCmp('checkbox2'), checkbox3 = Ext.getCmp('checkbox3'); - + checkbox1.setValue(true); checkbox2.setValue(true); checkbox3.setValue(true); @@ -75604,7 +76025,7 @@ __Example usage:__ var checkbox1 = Ext.getCmp('checkbox1'), checkbox2 = Ext.getCmp('checkbox2'), checkbox3 = Ext.getCmp('checkbox3'); - + checkbox1.setValue(false); checkbox2.setValue(false); checkbox3.setValue(false); @@ -75805,11 +76226,9 @@ Ext.define('Ext.form.field.Checkbox', { * @return {Boolean/null} True if checked; otherwise either the {@link #uncheckedValue} or null. */ getSubmitValue: function() { - return this.checked ? this.inputValue : (this.uncheckedValue || null); - }, - - getModelData: function() { - return this.getSubmitData(); + var unchecked = this.uncheckedValue, + uncheckedVal = Ext.isDefined(unchecked) ? unchecked : null; + return this.checked ? this.inputValue : uncheckedVal; }, /** @@ -75974,51 +76393,52 @@ Ext.define('Ext.layout.component.field.Trigger', { * mouseover, mouseout, etc. as well as a built-in selection model. In order to use these features, an {@link #itemSelector} * config must be provided for the DataView to determine what nodes it will be working with. * - *

    The example below binds a DataView to a {@link Ext.data.Store} and renders it into an {@link Ext.panel.Panel}.

    + * The example below binds a DataView to a {@link Ext.data.Store} and renders it into an {@link Ext.panel.Panel}. + * * {@img Ext.DataView/Ext.DataView.png Ext.DataView component} - *
    
    -    Ext.regModel('Image', {
    -        Fields: [
    -            {name:'src', type:'string'},
    -            {name:'caption', type:'string'}
    -        ]
    -    });
    -    
    -    Ext.create('Ext.data.Store', {
    -        id:'imagesStore',
    -        model: 'Image',
    -        data: [
    -            {src:'http://www.sencha.com/img/20110215-feat-drawing.png', caption:'Drawing & Charts'},
    -            {src:'http://www.sencha.com/img/20110215-feat-data.png', caption:'Advanced Data'},
    -            {src:'http://www.sencha.com/img/20110215-feat-html5.png', caption:'Overhauled Theme'},
    -            {src:'http://www.sencha.com/img/20110215-feat-perf.png', caption:'Performance Tuned'}            
    -        ]
    -    });
    -    
    -    var imageTpl = new Ext.XTemplate(
    -        '',
    -            '
    ', - '', - '
    {caption}', - '
    ', - '
    ' - ); - - Ext.create('Ext.DataView', { - store: Ext.data.StoreManager.lookup('imagesStore'), - tpl: imageTpl, - itemSelector: 'div.thumb-wrap', - emptyText: 'No images available', - renderTo: Ext.getBody() - }); - *
    + * + * Ext.regModel('Image', { + * Fields: [ + * {name:'src', type:'string'}, + * {name:'caption', type:'string'} + * ] + * }); + * + * Ext.create('Ext.data.Store', { + * id:'imagesStore', + * model: 'Image', + * data: [ + * {src:'http://www.sencha.com/img/20110215-feat-drawing.png', caption:'Drawing & Charts'}, + * {src:'http://www.sencha.com/img/20110215-feat-data.png', caption:'Advanced Data'}, + * {src:'http://www.sencha.com/img/20110215-feat-html5.png', caption:'Overhauled Theme'}, + * {src:'http://www.sencha.com/img/20110215-feat-perf.png', caption:'Performance Tuned'} + * ] + * }); + * + * var imageTpl = new Ext.XTemplate( + * '<tpl for=".">', + * '<div style="thumb-wrap">', + * '<img src="{src}" />', + * '<br/><span>{caption}</span>', + * '</div>', + * '</tpl>' + * ); + * + * Ext.create('Ext.DataView', { + * store: Ext.data.StoreManager.lookup('imagesStore'), + * tpl: imageTpl, + * itemSelector: 'div.thumb-wrap', + * emptyText: 'No images available', + * renderTo: Ext.getBody() + * }); + * * @xtype dataview */ Ext.define('Ext.view.View', { extend: 'Ext.view.AbstractView', alternateClassName: 'Ext.view.View', alias: 'widget.dataview', - + inheritableStatics: { EventMap: { mousedown: 'MouseDown', @@ -76033,7 +76453,7 @@ Ext.define('Ext.view.View', { keydown: 'KeyDown' } }, - + addCmpEvents: function() { this.addEvents( /** @@ -76301,7 +76721,7 @@ Ext.define('Ext.view.View', { * @param {Ext.EventObject} e The raw event object. Use {@link Ext.EventObject#getKey getKey()} to retrieve the key that was pressed. */ 'containerkeydown', - + /** * @event selectionchange * Fires when the selected nodes change. Relayed event from the underlying selection model. @@ -76321,9 +76741,9 @@ Ext.define('Ext.view.View', { }, // private afterRender: function(){ - var me = this, + var me = this, listeners; - + me.callParent(); listeners = { @@ -76337,43 +76757,61 @@ Ext.define('Ext.view.View', { mouseout: me.handleEvent, keydown: me.handleEvent }; - + me.mon(me.getTargetEl(), listeners); - + if (me.store) { me.bindStore(me.store, true); } }, - + handleEvent: function(e) { if (this.processUIEvent(e) !== false) { this.processSpecialEvent(e); } }, - + // Private template method processItemEvent: Ext.emptyFn, processContainerEvent: Ext.emptyFn, processSpecialEvent: Ext.emptyFn, - - processUIEvent: function(e, type) { - type = type || e.type; + + /* + * Returns true if this mouseover/out event is still over the overItem. + */ + stillOverItem: function (event, overItem) { + var nowOver; + + // There is this weird bug when you hover over the border of a cell it is saying + // the target is the table. + // BrowserBug: IE6 & 7. If me.mouseOverItem has been removed and is no longer + // in the DOM then accessing .offsetParent will throw an "Unspecified error." exception. + // typeof'ng and checking to make sure the offsetParent is an object will NOT throw + // this hard exception. + if (overItem && typeof(overItem.offsetParent) === "object") { + // mouseout : relatedTarget == nowOver, target == wasOver + // mouseover: relatedTarget == wasOver, target == nowOver + nowOver = (event.type == 'mouseout') ? event.getRelatedTarget() : event.getTarget(); + return Ext.fly(overItem).contains(nowOver); + } + + return false; + }, + + processUIEvent: function(e) { var me = this, item = e.getTarget(me.getItemSelector(), me.getTargetEl()), map = this.statics().EventMap, - index, record; - + index, record, + type = e.type, + overItem = me.mouseOverItem, + newType; + if (!item) { - // There is this weird bug when you hover over the border of a cell it is saying - // the target is the table. - // BrowserBug: IE6 & 7. If me.mouseOverItem has been removed and is no longer - // in the DOM then accessing .offsetParent will throw an "Unspecified error." exception. - // typeof'ng and checking to make sure the offsetParent is an object will NOT throw - // this hard exception. - if (type == 'mouseover' && me.mouseOverItem && typeof me.mouseOverItem.offsetParent === "object" && Ext.fly(me.mouseOverItem).getRegion().contains(e.getPoint())) { - item = me.mouseOverItem; + if (type == 'mouseover' && me.stillOverItem(e, overItem)) { + item = overItem; } - + // Try to get the selected item to handle the keydown event, otherwise we'll just fire a container keydown event if (type == 'keydown') { record = me.getSelectionModel().getLastSelected(); @@ -76382,54 +76820,53 @@ Ext.define('Ext.view.View', { } } } - + if (item) { index = me.indexOf(item); if (!record) { record = me.getRecord(item); } - - if (me.processItemEvent(type, record, item, index, e) === false) { + + if (me.processItemEvent(record, item, index, e) === false) { return false; } - - type = me.isNewItemEvent(type, item, e); - if (type === false) { + + newType = me.isNewItemEvent(item, e); + if (newType === false) { return false; } - + if ( - (me['onBeforeItem' + map[type]](record, item, index, e) === false) || - (me.fireEvent('beforeitem' + type, me, record, item, index, e) === false) || - (me['onItem' + map[type]](record, item, index, e) === false) - ) { + (me['onBeforeItem' + map[newType]](record, item, index, e) === false) || + (me.fireEvent('beforeitem' + newType, me, record, item, index, e) === false) || + (me['onItem' + map[newType]](record, item, index, e) === false) + ) { return false; } - - me.fireEvent('item' + type, me, record, item, index, e); - } + + me.fireEvent('item' + newType, me, record, item, index, e); + } else { if ( - (me.processContainerEvent(type, e) === false) || + (me.processContainerEvent(e) === false) || (me['onBeforeContainer' + map[type]](e) === false) || (me.fireEvent('beforecontainer' + type, me, e) === false) || (me['onContainer' + map[type]](e) === false) ) { return false; } - + me.fireEvent('container' + type, me, e); } - + return true; }, - - isNewItemEvent: function(type, item, e) { + + isNewItemEvent: function (item, e) { var me = this, overItem = me.mouseOverItem, - contains, - isItem; - + type = e.type; + switch (type) { case 'mouseover': if (item === overItem) { @@ -76437,27 +76874,18 @@ Ext.define('Ext.view.View', { } me.mouseOverItem = item; return 'mouseenter'; - break; - + case 'mouseout': - /* - * Need an extra check here to see if it's the parent element. See the - * comment re: the browser bug at the start of processUIEvent - */ - if (overItem && typeof overItem.offsetParent === "object") { - contains = Ext.fly(me.mouseOverItem).getRegion().contains(e.getPoint()); - isItem = Ext.fly(e.getTarget()).hasCls(me.itemSelector); - if (contains && isItem) { - return false; - } + // If the currently mouseovered item contains the mouseover target, it's *NOT* a mouseleave + if (me.stillOverItem(e, overItem)) { + return false; } me.mouseOverItem = null; return 'mouseleave'; - break; } return type; }, - + // private onItemMouseEnter: function(record, item, index, e) { if (this.trackOver) { @@ -76487,7 +76915,7 @@ Ext.define('Ext.view.View', { onBeforeItemDblClick: Ext.emptyFn, onBeforeItemContextMenu: Ext.emptyFn, onBeforeItemKeyDown: Ext.emptyFn, - + // @private, template methods onContainerMouseDown: Ext.emptyFn, onContainerMouseUp: Ext.emptyFn, @@ -76505,7 +76933,7 @@ Ext.define('Ext.view.View', { onBeforeContainerDblClick: Ext.emptyFn, onBeforeContainerContextMenu: Ext.emptyFn, onBeforeContainerKeyDown: Ext.emptyFn, - + /** * Highlight a given item in the DataView. This is called by the mouseover handler if {@link #overItemCls} * and {@link #trackOver} are configured, but can also be called manually by other code, for instance to @@ -76525,7 +76953,7 @@ Ext.define('Ext.view.View', { clearHighlight: function() { var me = this, highlighted = me.highlightedItem; - + if (highlighted) { Ext.fly(highlighted).removeCls(me.overItemCls); delete me.highlightedItem; @@ -76652,15 +77080,15 @@ Ext.define('Ext.layout.component.BoundList', { * * {@img Ext.toolbar.TextItem/Ext.toolbar.TextItem.png TextItem component} * - * Ext.create('Ext.panel.Panel', { - * title: 'Panel with TextItem', - * width: 300, - * height: 200, - * tbar: [ - * {xtype: 'tbtext', text: 'Sample TextItem'} - * ], - * renderTo: Ext.getBody() - * }); + * Ext.create('Ext.panel.Panel', { + * title: 'Panel with TextItem', + * width: 300, + * height: 200, + * tbar: [ + * {xtype: 'tbtext', text: 'Sample TextItem'} + * ], + * renderTo: Ext.getBody() + * }); * * @constructor * Creates a new TextItem @@ -76712,27 +77140,27 @@ Ext.define('Ext.toolbar.TextItem', { * {@img Ext.form.field.Trigger/Ext.form.field.Trigger.png Ext.form.field.Trigger component} * For example:

    *
    
    -    Ext.define('Ext.ux.CustomTrigger', {
    -        extend: 'Ext.form.field.Trigger',
    -        alias: 'widget.customtrigger',
    -        
    -        // override onTriggerClick
    -        onTriggerClick: function() {
    -            Ext.Msg.alert('Status', 'You clicked my trigger!');
    -        }
    -    });
    +Ext.define('Ext.ux.CustomTrigger', {
    +    extend: 'Ext.form.field.Trigger',
    +    alias: 'widget.customtrigger',
         
    -    Ext.create('Ext.form.FormPanel', {
    -        title: 'Form with TriggerField',
    -        bodyPadding: 5,
    -        width: 350,
    -        renderTo: Ext.getBody(),
    -        items:[{
    -            xtype: 'customtrigger',
    -            fieldLabel: 'Sample Trigger',
    -            emptyText: 'click the trigger',
    -        }]
    -    });
    +    // override onTriggerClick
    +    onTriggerClick: function() {
    +        Ext.Msg.alert('Status', 'You clicked my trigger!');
    +    }
    +});
    +
    +Ext.create('Ext.form.FormPanel', {
    +    title: 'Form with TriggerField',
    +    bodyPadding: 5,
    +    width: 350,
    +    renderTo: Ext.getBody(),
    +    items:[{
    +        xtype: 'customtrigger',
    +        fieldLabel: 'Sample Trigger',
    +        emptyText: 'click the trigger',
    +    }]
    +});
     
    * *

    However, in general you will most likely want to use Trigger as the base class for a reusable component. @@ -77263,7 +77691,7 @@ Ext.define('Ext.form.field.Picker', { mousedown: collapseIf, scope: me }); - + Ext.EventManager.onWindowResize(me.alignPicker, me); me.fireEvent('expand', me); me.onExpand(); } @@ -77321,7 +77749,7 @@ Ext.define('Ext.form.field.Picker', { // remove event listeners doc.un('mousewheel', collapseIf, me); doc.un('mousedown', collapseIf, me); - + Ext.EventManager.removeResizeListener(me.alignPicker, me); me.fireEvent('collapse', me); me.onCollapse(); } @@ -77385,6 +77813,7 @@ Ext.define('Ext.form.field.Picker', { onDestroy : function(){ var me = this; + Ext.EventManager.removeResizeListener(me.alignPicker, me); Ext.destroy(me.picker, me.keyNav); me.callParent(); } @@ -77855,23 +78284,25 @@ Ext.define('Ext.form.field.Number', { var me = this, allowed; - this.callParent(); + me.callParent(); me.setMinValue(me.minValue); me.setMaxValue(me.maxValue); // Build regexes for masking and stripping based on the configured options - allowed = me.baseChars + ''; - if (me.allowDecimals) { - allowed += me.decimalSeparator; - } - if (me.minValue < 0) { - allowed += '-'; - } - allowed = Ext.String.escapeRegex(allowed); - me.maskRe = new RegExp('[' + allowed + ']'); - if (me.autoStripChars) { - me.stripCharsRe = new RegExp('[^' + allowed + ']', 'gi'); + if (me.disableKeyFilter !== true) { + allowed = me.baseChars + ''; + if (me.allowDecimals) { + allowed += me.decimalSeparator; + } + if (me.minValue < 0) { + allowed += '-'; + } + allowed = Ext.String.escapeRegex(allowed); + me.maskRe = new RegExp('[' + allowed + ']'); + if (me.autoStripChars) { + me.stripCharsRe = new RegExp('[^' + allowed + ']', 'gi'); + } } }, @@ -78820,7 +79251,7 @@ Ext.define('Ext.view.BoundListKeyNav', { * * A combobox control with support for autocomplete, remote loading, and many other features. * - * A ComboBox is like a combination of a traditional HTML text `<input>` field and a `<select>` + * A ComboBox is like a combination of a traditional HTML text `` field and a `', formattedValue = origRenderer.apply(origScope, arguments), href = record.get('href'), - target = record.get('hrefTarget'); + target = record.get('hrefTarget'), + cls = record.get('cls'); while (record) { if (!record.isRoot() || (record.isRoot() && view.rootVisible)) { @@ -104237,6 +104929,9 @@ Ext.define('Ext.tree.Column', { if (href) { formattedValue = format('{2}', href, target, formattedValue); } + if (cls) { + metaData.tdCls += ' ' + cls; + } return buf.join("") + formattedValue; }; this.callParent(arguments); @@ -104495,7 +105190,7 @@ Ext.define('Ext.tree.View', { var me = this, animWrap; - if (!me.animate) { + if (!me.rendered || !me.animate) { return; } @@ -104570,7 +105265,7 @@ Ext.define('Ext.tree.View', { var me = this, animWrap; - if (!me.animate) { + if (!me.rendered || !me.animate) { return; } @@ -104872,16 +105567,17 @@ Ext.define('Ext.tree.Panel', { } else if (!me.useArrows) { cls.push(Ext.baseCSSPrefix + 'tree-no-lines'); } - - if (!me.store || Ext.isObject(me.store) && !me.store.isStore) { + + if (Ext.isString(me.store)) { + me.store = Ext.StoreMgr.lookup(me.store); + } else if (!me.store || Ext.isObject(me.store) && !me.store.isStore) { me.store = Ext.create('Ext.data.TreeStore', Ext.apply({}, me.store || {}, { root: me.root, fields: me.fields, model: me.model, folderSort: me.folderSort })); - } - else if (me.root) { + } else if (me.root) { me.store = Ext.data.StoreManager.lookup(me.store); me.store.setRootNode(me.root); if (me.folderSort !== undefined) { @@ -105133,7 +105829,7 @@ Ext.define('Ext.tree.Panel', { /** * Expand the tree to the path of a particular node. - * @param {String} path The path to expand + * @param {String} path The path to expand. The path should include a leading separator. * @param {String} field (optional) The field to get the data from. Defaults to the model idProperty. * @param {String} separator (optional) A separator to use. Defaults to '/'. * @param {Function} callback (optional) A function to execute when the expand finishes. The callback will be called with @@ -105181,7 +105877,7 @@ Ext.define('Ext.tree.Panel', { /** * Expand the tree to the path of a particular node, then selecti t. - * @param {String} path The path to select + * @param {String} path The path to select. The path should include a leading separator. * @param {String} field (optional) The field to get the data from. Defaults to the model idProperty. * @param {String} separator (optional) A separator to use. Defaults to '/'. * @param {Function} callback (optional) A function to execute when the select finishes. The callback will be called with @@ -106146,10 +106842,28 @@ Ext.define('Ext.util.CSS', function() { }()); /** * @class Ext.util.History - * History management component that allows you to register arbitrary tokens that signify application - * history state on navigation actions. You can then handle the history {@link #change} event in order - * to reset your application UI to the appropriate state when the user navigates forward or backward through - * the browser history stack. + +History management component that allows you to register arbitrary tokens that signify application +history state on navigation actions. You can then handle the history {@link #change} event in order +to reset your application UI to the appropriate state when the user navigates forward or backward through +the browser history stack. + +__Initializing__ +The {@link #init} method of the History object must be called before using History. This sets up the internal +state and must be the first thing called before using History. + +__Setup__ +The History objects requires elements on the page to keep track of the browser history. For older versions of IE, +an IFrame is required to do the tracking. For other browsers, a hidden field can be used. The history objects expects +these to be on the page before the {@link #init} method is called. The following markup is suggested in order +to support all browsers: + +

    + + +
    + + * @markdown * @singleton */ Ext.define('Ext.util.History', {