Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / src / data / AbstractStore.js
index 90e8ece..5d10d8b 100644 (file)
@@ -1,29 +1,41 @@
+/*
+
+This file is part of Ext JS 4
+
+Copyright (c) 2011 Sencha Inc
+
+Contact:  http://www.sencha.com/contact
+
+GNU General Public License Usage
+This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+
+If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
+
+*/
 /**
  * @author Ed Spencer
- * @class Ext.data.AbstractStore
  *
- * <p>AbstractStore is a superclass of {@link Ext.data.Store} and {@link Ext.data.TreeStore}. It's never used directly,
- * but offers a set of methods used by both of those subclasses.</p>
+ * AbstractStore is a superclass of {@link Ext.data.Store} and {@link Ext.data.TreeStore}. It's never used directly,
+ * but offers a set of methods used by both of those subclasses.
  * 
- * <p>We've left it here in the docs for reference purposes, but unless you need to make a whole new type of Store, what
+ * We've left it here in the docs for reference purposes, but unless you need to make a whole new type of Store, what
  * you're probably looking for is {@link Ext.data.Store}. If you're still interested, here's a brief description of what 
- * AbstractStore is and is not.</p>
+ * AbstractStore is and is not.
  * 
- * <p>AbstractStore provides the basic configuration for anything that can be considered a Store. It expects to be 
+ * AbstractStore provides the basic configuration for anything that can be considered a Store. It expects to be 
  * given a {@link Ext.data.Model Model} that represents the type of data in the Store. It also expects to be given a 
- * {@link Ext.data.proxy.Proxy Proxy} that handles the loading of data into the Store.</p>
+ * {@link Ext.data.proxy.Proxy Proxy} that handles the loading of data into the Store.
  * 
- * <p>AbstractStore provides a few helpful methods such as {@link #load} and {@link #sync}, which load and save data
+ * AbstractStore provides a few helpful methods such as {@link #load} and {@link #sync}, which load and save data
  * respectively, passing the requests through the configured {@link #proxy}. Both built-in Store subclasses add extra
  * behavior to each of these functions. Note also that each AbstractStore subclass has its own way of storing data - 
  * in {@link Ext.data.Store} the data is saved as a flat {@link Ext.util.MixedCollection MixedCollection}, whereas in
- * {@link Ext.data.TreeStore TreeStore} we use a {@link Ext.data.Tree} to maintain the data's hierarchy.</p>
- * 
- * TODO: Update these docs to explain about the sortable and filterable mixins.
- * <p>Finally, AbstractStore provides an API for sorting and filtering data via its {@link #sorters} and {@link #filters}
- * {@link Ext.util.MixedCollection MixedCollections}. Although this functionality is provided by AbstractStore, there's a
- * good description of how to use it in the introduction of {@link Ext.data.Store}.
+ * {@link Ext.data.TreeStore TreeStore} we use a {@link Ext.data.Tree} to maintain the data's hierarchy.
  * 
+ * The store provides filtering and sorting support. This sorting/filtering can happen on the client side
+ * or can be completed on the server. This is controlled by the {@link Ext.data.Store#remoteSort remoteSort} and
+ * {@link Ext.data.Store#remoteFilter remoteFilter} config options. For more information see the {@link #sort} and
+ * {@link Ext.data.Store#filter filter} methods.
  */
 Ext.define('Ext.data.AbstractStore', {
     requires: ['Ext.util.MixedCollection', 'Ext.data.Operation', 'Ext.util.Filter'],
@@ -49,101 +61,107 @@ Ext.define('Ext.data.AbstractStore', {
     remoteFilter: false,
 
     /**
-     * @cfg {String/Ext.data.proxy.Proxy/Object} proxy The Proxy to use for this Store. This can be either a string, a config
-     * object or a Proxy instance - see {@link #setProxy} for details.
+     * @cfg {String/Ext.data.proxy.Proxy/Object} proxy
+     * The Proxy to use for this Store. This can be either a string, a config object or a Proxy instance -
+     * see {@link #setProxy} for details.
      */
 
     /**
-     * @cfg {Boolean/Object} autoLoad If data is not specified, and if autoLoad is true or an Object, this store's load method
-     * is automatically called after creation. If the value of autoLoad is an Object, this Object will be passed to the store's
-     * load method. Defaults to false.
+     * @cfg {Boolean/Object} autoLoad
+     * If data is not specified, and if autoLoad is true or an Object, this store's load method is automatically called
+     * after creation. If the value of autoLoad is an Object, this Object will be passed to the store's load method.
+     * Defaults to false.
      */
     autoLoad: false,
 
     /**
-     * @cfg {Boolean} autoSync True to automatically sync the Store with its Proxy after every edit to one of its Records.
-     * Defaults to false.
+     * @cfg {Boolean} autoSync
+     * True to automatically sync the Store with its Proxy after every edit to one of its Records. Defaults to false.
      */
     autoSync: false,
 
     /**
+     * @property {String} batchUpdateMode
      * Sets the updating behavior based on batch synchronization. 'operation' (the default) will update the Store's
      * internal representation of the data after each operation of the batch has completed, 'complete' will wait until
      * the entire batch has been completed before updating the Store's data. 'complete' is a good choice for local
      * storage proxies, 'operation' is better for remote proxies, where there is a comparatively high latency.
-     * @property batchUpdateMode
-     * @type String
      */
     batchUpdateMode: 'operation',
 
     /**
+     * @property {Boolean} filterOnLoad
      * If true, any filters attached to this Store will be run after loading data, before the datachanged event is fired.
-     * Defaults to true, ignored if {@link #remoteFilter} is true
-     * @property filterOnLoad
-     * @type Boolean
+     * Defaults to true, ignored if {@link Ext.data.Store#remoteFilter remoteFilter} is true
      */
     filterOnLoad: true,
 
     /**
+     * @property {Boolean} sortOnLoad
      * If true, any sorters attached to this Store will be run after loading data, before the datachanged event is fired.
-     * Defaults to true, igored if {@link #remoteSort} is true
-     * @property sortOnLoad
-     * @type Boolean
+     * Defaults to true, igored if {@link Ext.data.Store#remoteSort remoteSort} is true
      */
     sortOnLoad: true,
 
     /**
-     * True if a model was created implicitly for this Store. This happens if a fields array is passed to the Store's constructor
-     * instead of a model constructor or name.
-     * @property implicitModel
-     * @type Boolean
+     * @property {Boolean} implicitModel
+     * True if a model was created implicitly for this Store. This happens if a fields array is passed to the Store's
+     * constructor instead of a model constructor or name.
      * @private
      */
     implicitModel: false,
 
     /**
-     * The string type of the Proxy to create if none is specified. This defaults to creating a {@link Ext.data.proxy.Memory memory proxy}.
-     * @property defaultProxyType
-     * @type String
+     * @property {String} defaultProxyType
+     * The string type of the Proxy to create if none is specified. This defaults to creating a
+     * {@link Ext.data.proxy.Memory memory proxy}.
      */
     defaultProxyType: 'memory',
 
     /**
-     * True if the Store has already been destroyed via {@link #destroyStore}. If this is true, the reference to Store should be deleted
+     * @property {Boolean} isDestroyed
+     * True if the Store has already been destroyed. If this is true, the reference to Store should be deleted
      * as it will not function correctly any more.
-     * @property isDestroyed
-     * @type Boolean
      */
     isDestroyed: false,
 
     isStore: true,
 
     /**
-     * @cfg {String} storeId Optional unique identifier for this store. If present, this Store will be registered with 
-     * the {@link Ext.data.StoreManager}, making it easy to reuse elsewhere. Defaults to undefined.
+     * @cfg {String} storeId
+     * Unique identifier for this store. If present, this Store will be registered with the {@link Ext.data.StoreManager},
+     * making it easy to reuse elsewhere. Defaults to undefined.
      */
     
     /**
-     * @cfg {Array} fields
+     * @cfg {Object[]} fields
      * This may be used in place of specifying a {@link #model} configuration. The fields should be a 
      * set of {@link Ext.data.Field} configuration objects. The store will automatically create a {@link Ext.data.Model}
      * with these fields. In general this configuration option should be avoided, it exists for the purposes of
      * backwards compatibility. For anything more complicated, such as specifying a particular id property or
-     * assocations, a {@link Ext.data.Model} should be defined and specified for the {@link #model} config.
+     * assocations, a {@link Ext.data.Model} should be defined and specified for the {@link #model}
+     * config.
+     */
+
+    /**
+     * @cfg {String} model
+     * Name of the {@link Ext.data.Model Model} associated with this store.
+     * The string is used as an argument for {@link Ext.ModelManager#getModel}.
      */
 
     sortRoot: 'data',
     
     //documented above
     constructor: function(config) {
-        var me = this;
+        var me = this,
+            filters;
         
         me.addEvents(
             /**
              * @event add
              * Fired when a Model instance has been added to this Store
              * @param {Ext.data.Store} store The store
-             * @param {Array} records The Model instances that were added
+             * @param {Ext.data.Model[]} records The Model instances that were added
              * @param {Number} index The index at which the instances were inserted
              */
             'add',
@@ -159,31 +177,32 @@ Ext.define('Ext.data.AbstractStore', {
             
             /**
              * @event update
-             * Fires when a Record has been updated
-             * @param {Store} this
+             * Fires when a Model instance has been updated
+             * @param {Ext.data.Store} this
              * @param {Ext.data.Model} record The Model instance that was updated
              * @param {String} operation The update operation being performed. Value may be one of:
-             * <pre><code>
-               Ext.data.Model.EDIT
-               Ext.data.Model.REJECT
-               Ext.data.Model.COMMIT
-             * </code></pre>
+             *
+             *     Ext.data.Model.EDIT
+             *     Ext.data.Model.REJECT
+             *     Ext.data.Model.COMMIT
              */
             'update',
 
             /**
              * @event datachanged
-             * Fires whenever the records in the Store have changed in some way - this could include adding or removing records,
-             * or updating the data in existing records
+             * Fires whenever the records in the Store have changed in some way - this could include adding or removing
+             * records, or updating the data in existing records
              * @param {Ext.data.Store} this The data store
              */
             'datachanged',
 
             /**
              * @event beforeload
-             * Event description
+             * Fires before a request is made for a new data object. If the beforeload handler returns false the load
+             * action will be canceled.
              * @param {Ext.data.Store} store This Store
-             * @param {Ext.data.Operation} operation The Ext.data.Operation object that will be passed to the Proxy to load the Store
+             * @param {Ext.data.Operation} operation The Ext.data.Operation object that will be passed to the Proxy to
+             * load the Store
              */
             'beforeload',
 
@@ -191,14 +210,23 @@ Ext.define('Ext.data.AbstractStore', {
              * @event load
              * Fires whenever the store reads data from a remote data source.
              * @param {Ext.data.Store} this
-             * @param {Array} records An array of records
+             * @param {Ext.data.Model[]} records An array of records
              * @param {Boolean} successful True if the operation was successful.
              */
             'load',
+            
+            /**
+             * @event write
+             * Fires whenever a successful write has been made via the configured {@link #proxy Proxy}
+             * @param {Ext.data.Store} store This Store
+             * @param {Ext.data.Operation} operation The {@link Ext.data.Operation Operation} object that was used in
+             * the write
+             */
+            'write',
 
             /**
              * @event beforesync
-             * Called before a call to {@link #sync} is executed. Return false from any listener to cancel the synv
+             * Fired before a call to {@link #sync} is executed. Return false from any listener to cancel the synv
              * @param {Object} options Hash of all records to be synchronized, broken down into create, update and destroy
              */
             'beforesync',
@@ -211,22 +239,21 @@ 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,
          * at which point this is cleared.
          * @private
-         * @property removed
-         * @type Array
+         * @property {Ext.data.Model[]} removed
          */
         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
-         * @type Object
+         * @property {Object} modelDefaults
          * @private
          * A set of default values to be applied to every model instance added via {@link #insert} or created via {@link #create}.
          * This is used internally by associations to set foreign keys and other fields. See the Association classes source code
@@ -248,9 +275,17 @@ Ext.define('Ext.data.AbstractStore', {
 
             me.implicitModel = true;
         }
+        
+        // <debug>
+        if (!me.model) {
+            if (Ext.isDefined(Ext.global.console)) {
+                Ext.global.console.warn('Store defined with no model. You may have mistyped the model name.');
+            }
+        }
+        // </debug>
 
         //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;
@@ -264,17 +299,17 @@ Ext.define('Ext.data.AbstractStore', {
         me.mixins.sortable.initSortable.call(me);        
         
         /**
+         * @property {Ext.util.MixedCollection} filters
          * The collection of {@link Ext.util.Filter Filters} currently applied to this Store
-         * @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);
     },
 
     /**
      * Sets the Store's Proxy by string, config object or Proxy instance
-     * @param {String|Object|Ext.data.proxy.Proxy} proxy The new Proxy, which can be either a type string, a configuration object
+     * @param {String/Object/Ext.data.proxy.Proxy} proxy The new Proxy, which can be either a type string, a configuration object
      * or an Ext.data.proxy.Proxy instance
      * @return {Ext.data.proxy.Proxy} The attached Proxy object
      */
@@ -449,7 +484,7 @@ Ext.define('Ext.data.AbstractStore', {
     /**
      * Returns all Model instances that are either currently a phantom (e.g. have no id), or have an ID but have not
      * yet been saved on this Store (this happens when adding a non-phantom record from another Store into this one)
-     * @return {Array} The Model instances
+     * @return {Ext.data.Model[]} The Model instances
      */
     getNewRecords: function() {
         return [];
@@ -457,7 +492,7 @@ Ext.define('Ext.data.AbstractStore', {
 
     /**
      * Returns all Model instances that have been updated in the Store but not yet synchronized with the Proxy
-     * @return {Array} The updated Model instances
+     * @return {Ext.data.Model[]} The updated Model instances
      */
     getUpdatedRecords: function() {
         return [];
@@ -472,7 +507,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 {Ext.data.Model[]} The removed Model instances
+     */
     getRemovedRecords: function() {
         return this.removed;
     },
@@ -484,8 +522,8 @@ Ext.define('Ext.data.AbstractStore', {
     /**
      * @private
      * Normalizes an array of filter objects, ensuring that they are all Ext.util.Filter instances
-     * @param {Array} filters The filters array
-     * @return {Array} Array of Ext.util.Filter objects
+     * @param {Object[]} filters The filters array
+     * @return {Ext.util.Filter[]} Array of Ext.util.Filter objects
      */
     decodeFilters: function(filters) {
         if (!Ext.isArray(filters)) {
@@ -602,7 +640,7 @@ Ext.define('Ext.data.AbstractStore', {
 
     /**
      * Loads the Store using its configured {@link #proxy}.
-     * @param {Object} options Optional config object. This is passed into the {@link Ext.data.Operation Operation}
+     * @param {Object} options (optional) config object. This is passed into the {@link Ext.data.Operation Operation}
      * object that is created and then sent to the proxy's {@link Ext.data.proxy.Proxy#read} function
      */
     load: function(options) {
@@ -702,6 +740,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
@@ -712,6 +751,7 @@ Ext.define('Ext.data.AbstractStore', {
      * @return {Boolean} True if the Store is currently loading
      */
     isLoading: function() {
-        return this.loading;
+        return !!this.loading;
      }
 });
+