X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/6a7e4474cba9d8be4b2ec445e10f1691f7277c50..0494b8d9b9bb03ab6c22b34dae81261e3cd7e3e6:/src/data/Store.js diff --git a/src/data/Store.js b/src/data/Store.js index afd25303..d6ae2398 100644 --- a/src/data/Store.js +++ b/src/data/Store.js @@ -1,8 +1,8 @@ /*! - * Ext JS Library 3.2.0 - * Copyright(c) 2006-2010 Ext JS, Inc. - * licensing@extjs.com - * http://www.extjs.com/license + * Ext JS Library 3.3.1 + * Copyright(c) 2006-2010 Sencha Inc. + * licensing@sencha.com + * http://www.sencha.com/license */ /** * @class Ext.data.Store @@ -258,29 +258,30 @@ sortInfo: { dir : 'dir' }, - /** - * @property isDestroyed - * @type Boolean - * True if the store has been destroyed already. Read only - */ - isDestroyed: false, - - /** - * @property hasMultiSort - * @type Boolean - * True if this store is currently sorted by more than one field/direction combination. - */ + isDestroyed: false, hasMultiSort: false, // private batchKey : '_ext_batch_', constructor : function(config){ + /** + * @property multiSort + * @type Boolean + * True if this store is currently sorted by more than one field/direction combination. + */ + + /** + * @property isDestroyed + * @type Boolean + * True if the store has been destroyed already. Read only + */ + this.data = new Ext.util.MixedCollection(false); this.data.getKey = function(o){ return o.id; }; - + // temporary removed-records cache this.removed = []; @@ -453,7 +454,7 @@ sortInfo: { * @event clear * Fires when the data cache has been cleared. * @param {Store} this - * @param {Record[]} The records that were cleared. + * @param {Record[]} records The records that were cleared. */ 'clear', /** @@ -624,19 +625,31 @@ sortInfo: { * @param {Ext.data.Record[]} records An Array of Ext.data.Record objects * to add to the cache. See {@link #recordType}. */ - add : function(records){ + add : function(records) { + var i, len, record, index; + records = [].concat(records); - if(records.length < 1){ + if (records.length < 1) { return; } - for(var i = 0, len = records.length; i < len; i++){ - records[i].join(this); + + for (i = 0, len = records.length; i < len; i++) { + record = records[i]; + + record.join(this); + + if (record.dirty || record.phantom) { + this.modified.push(record); + } } - var index = this.data.length; + + index = this.data.length; this.data.addAll(records); - if(this.snapshot){ + + if (this.snapshot) { this.snapshot.addAll(records); } + this.fireEvent('add', this, records, index); }, @@ -649,6 +662,18 @@ sortInfo: { var index = this.findInsertIndex(record); this.insert(index, record); }, + + /** + * @private + * Update a record within the store with a new reference + */ + doUpdate : function(rec){ + this.data.replace(rec.id, rec); + if(this.snapshot){ + this.snapshot.replace(rec.id, rec); + } + this.fireEvent('update', this, rec, Ext.data.Record.COMMIT); + }, /** * Remove Records from the Store and fires the {@link #remove} event. @@ -659,6 +684,7 @@ sortInfo: { Ext.each(record, function(r){ this.remove(r); }, this); + return; } var index = this.data.indexOf(record); if(index > -1){ @@ -718,15 +744,25 @@ sortInfo: { * @param {Number} index The start index at which to insert the passed Records. * @param {Ext.data.Record[]} records An Array of Ext.data.Record objects to add to the cache. */ - insert : function(index, records){ + insert : function(index, records) { + var i, len, record; + records = [].concat(records); - for(var i = 0, len = records.length; i < len; i++){ - this.data.insert(index, records[i]); - records[i].join(this); + for (i = 0, len = records.length; i < len; i++) { + record = records[i]; + + this.data.insert(index + i, record); + record.join(this); + + if (record.dirty || record.phantom) { + this.modified.push(record); + } } - if(this.snapshot){ + + if (this.snapshot) { this.snapshot.addAll(records); } + this.fireEvent('add', this, records, index); }, @@ -855,17 +891,26 @@ sortInfo: { }, /** + * @private * Should not be used directly. Store#add will call this automatically if a Writer is set * @param {Object} store - * @param {Object} rs + * @param {Object} records * @param {Object} index - * @private */ - createRecords : function(store, rs, index) { - for (var i = 0, len = rs.length; i < len; i++) { - if (rs[i].phantom && rs[i].isValid()) { - rs[i].markDirty(); // <-- Mark new records dirty - this.modified.push(rs[i]); // <-- add to modified + createRecords : function(store, records, index) { + var modified = this.modified, + length = records.length, + record, i; + + for (i = 0; i < length; i++) { + record = records[i]; + + if (record.phantom && record.isValid()) { + record.markDirty(); // <-- Mark new records dirty (Ed: why?) + + if (modified.indexOf(record) == -1) { + modified.push(record); + } } } if (this.autoSave === true) { @@ -982,7 +1027,8 @@ sortInfo: { len, trans, batch, - data = {}; + data = {}, + i; // DESTROY: First check for removed records. Records in this.removed are guaranteed non-phantoms. @see Store#remove if(this.removed.length){ queue.push(['destroy', this.removed]); @@ -993,7 +1039,7 @@ sortInfo: { if(rs.length){ // CREATE: Next check for phantoms within rs. splice-off and execute create. var phantoms = []; - for(var i = rs.length-1; i >= 0; i--){ + for(i = rs.length-1; i >= 0; i--){ if(rs[i].phantom === true){ var rec = rs.splice(i, 1).shift(); if(rec.isValid()){ @@ -1016,12 +1062,12 @@ sortInfo: { len = queue.length; if(len){ batch = ++this.batchCounter; - for(var i = 0; i < len; ++i){ + for(i = 0; i < len; ++i){ trans = queue[i]; data[trans[0]] = trans[1]; } if(this.fireEvent('beforesave', this, data) !== false){ - for(var i = 0; i < len; ++i){ + for(i = 0; i < len; ++i){ trans = queue[i]; this.doTransaction(trans[0], trans[1], batch); } @@ -1069,7 +1115,6 @@ sortInfo: { var b = this.batches, key = this.batchKey + batch, o = b[key], - data, arr; @@ -1208,6 +1253,8 @@ myStore.reload(lastOptions); // private // Called as a callback by the Reader during a load operation. loadRecords : function(o, options, success){ + var i, len; + if (this.isDestroyed === true) { return; } @@ -1225,7 +1272,7 @@ myStore.reload(lastOptions); if(this.pruneModifiedRecords){ this.modified = []; } - for(var i = 0, len = r.length; i < len; i++){ + for(i = 0, len = r.length; i < len; i++){ r[i].join(this); } if(this.snapshot){ @@ -1238,8 +1285,20 @@ myStore.reload(lastOptions); this.applySort(); this.fireEvent('datachanged', this); }else{ - this.totalLength = Math.max(t, this.data.length+r.length); - this.add(r); + var toAdd = [], + rec, + cnt = 0; + for(i = 0, len = r.length; i < len; ++i){ + rec = r[i]; + if(this.indexOfId(rec.id) > -1){ + this.doUpdate(rec); + }else{ + toAdd.push(rec); + ++cnt; + } + } + this.totalLength = Math.max(t, this.data.length + cnt); + this.add(toAdd); } this.fireEvent('load', this, r, options); if(options.callback){ @@ -1364,6 +1423,7 @@ myStore.reload(lastOptions); }, /** + * @private * Creates and returns a function which sorts an array by the given field and direction * @param {String} field The field to create the sorter for * @param {String} direction The direction to sort by (defaults to "ASC") @@ -1437,7 +1497,9 @@ myStore.reload(lastOptions); */ singleSort: function(fieldName, dir) { var field = this.fields.get(fieldName); - if (!field) return false; + if (!field) { + return false; + } var name = field.name, sortInfo = this.sortInfo || null, @@ -1468,6 +1530,7 @@ myStore.reload(lastOptions); this.applySort(); this.fireEvent('datachanged', this); } + return true; }, /** @@ -1488,9 +1551,9 @@ myStore.reload(lastOptions); } /** + * Object containing overall sort direction and an ordered array of sorter configs used when sorting on multiple fields * @property multiSortInfo * @type Object - * Object containing overall sort direction and an ordered array of sorter configs used when sorting on multiple fields */ this.multiSortInfo = { sorters : sorters, @@ -1570,6 +1633,7 @@ myStore.reload(lastOptions); }, /** + * @private * Given an array of filter functions (each with optional scope), constructs and returns a single function that returns * the result of all of the filters ANDed together * @param {Array} filters The array of filter objects (each object should contain an 'fn' and optional scope) @@ -1597,6 +1661,7 @@ myStore.reload(lastOptions); * Single filter example: * store.filter('name', 'Ed', true, true); //finds all records containing the substring 'Ed' * Multiple filter example: + *

      * store.filter([
      *   {
      *     property     : 'name',
@@ -1613,6 +1678,7 @@ myStore.reload(lastOptions);
      *     scope: this
      *   }
      * ]);
+     * 
* @param {String|Array} field A field on your records, or an array containing multiple filter options * @param {String/RegExp} value Either a string that the field should begin with, or a RegExp to test * against the field. @@ -1621,6 +1687,7 @@ myStore.reload(lastOptions); * @param {Boolean} exactMatch True to force exact match (^ and $ characters added to the regex). Defaults to false. Ignored if anyMatch is true. */ filter : function(property, value, anyMatch, caseSensitive, exactMatch){ + var fn; //we can accept an array of filter objects, or a single filter object - normalize them here if (Ext.isObject(property)) { property = [property]; @@ -1643,10 +1710,10 @@ myStore.reload(lastOptions); filters.push({fn: func, scope: scope}); } - var fn = this.createMultipleFilterFn(filters); + fn = this.createMultipleFilterFn(filters); } else { //classic single property filter - var fn = this.createFilterFn(property, value, anyMatch, caseSensitive, exactMatch); + fn = this.createFilterFn(property, value, anyMatch, caseSensitive, exactMatch); } return fn ? this.filterBy(fn) : this.clearFilter(); @@ -1665,7 +1732,7 @@ myStore.reload(lastOptions); */ filterBy : function(fn, scope){ this.snapshot = this.snapshot || this.data; - this.data = this.queryBy(fn, scope||this); + this.data = this.queryBy(fn, scope || this); this.fireEvent('datachanged', this); }, @@ -1815,28 +1882,39 @@ myStore.reload(lastOptions); * Ext.data.Record.COMMIT. */ commitChanges : function(){ - var m = this.modified.slice(0); - this.modified = []; - for(var i = 0, len = m.length; i < len; i++){ - m[i].commit(); + var modified = this.modified.slice(0), + length = modified.length, + i; + + for (i = 0; i < length; i++){ + modified[i].commit(); } + + this.modified = []; + this.removed = []; }, /** * {@link Ext.data.Record#reject Reject} outstanding changes on all {@link #getModifiedRecords modified records}. */ - rejectChanges : function(){ - var m = this.modified.slice(0); - this.modified = []; - for(var i = 0, len = m.length; i < len; i++){ - m[i].reject(); + rejectChanges : function() { + var modified = this.modified.slice(0), + removed = this.removed.slice(0).reverse(), + mLength = modified.length, + rLength = removed.length, + i; + + for (i = 0; i < mLength; i++) { + modified[i].reject(); } - var m = this.removed.slice(0).reverse(); - this.removed = []; - for(var i = 0, len = m.length; i < len; i++){ - this.insert(m[i].lastIndex||0, m[i]); - m[i].reject(); + + for (i = 0; i < rLength; i++) { + this.insert(removed[i].lastIndex || 0, removed[i]); + removed[i].reject(); } + + this.modified = []; + this.removed = []; }, // private