/*!
- * Ext JS Library 3.2.1
- * 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
*/
/**
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 = [];
* @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',
/**
* @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);
},
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.
* @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);
},
},
/**
+ * @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) {
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]);
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()){
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);
}
var b = this.batches,
key = this.batchKey + batch,
o = b[key],
- data,
arr;
// 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;
}
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){
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){
*/
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,
this.applySort();
this.fireEvent('datachanged', this);
}
+ return true;
},
/**
}
/**
+ * 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,
* @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];
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();
*/
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);
},
* 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
* javascript millisecond timestamp. See {@link Date}</p>
*/
dateFormat: null,
+
+ /**
+ * @cfg {Boolean} useNull
+ * <p>(Optional) Use when converting received data into a Number type (either int or float). If the value cannot be parsed,
+ * null will be used if useNull is true, otherwise the value will be 0. Defaults to <tt>false</tt>
+ */
+ useNull: false,
+
/**
* @cfg {Mixed} defaultValue
* (Optional) The default value used <b>when a Record is being created by a {@link Ext.data.Reader Reader}</b>
delete data[this.meta.idProperty];
}
} else {
- data[this.meta.idProperty] = rec.id
+ data[this.meta.idProperty] = rec.id;
}
return data;
},
});
// Listen to "exception" event fired by all proxies
-Ext.data.DataProxy.on('exception', function(proxy, type, action) {
+Ext.data.DataProxy.on('exception', function(proxy, type, action, exception) {
console.error(type + action + ' exception);
});
* </code></pre>
* so any Store instance may observe this event.</p>
* <p>In addition to being fired through the DataProxy instance that raised the event, this event is also fired
* through the Ext.data.DataProxy <i>class</i> to allow for centralized processing of exception events from <b>all</b>
- * DataProxies by attaching a listener to the Ext.data.Proxy class itself.</p>
+ * DataProxies by attaching a listener to the Ext.data.DataProxy class itself.</p>
* <p>This event can be fired for one of two reasons:</p>
* <div class="mdetail-params"><ul>
* <li>remote-request <b>failed</b> : <div class="sub-desc">
* <p>Fires before a request is generated for one of the actions Ext.data.Api.actions.create|update|destroy</p>
* <p>In addition to being fired through the DataProxy instance that raised the event, this event is also fired
* through the Ext.data.DataProxy <i>class</i> to allow for centralized processing of beforewrite events from <b>all</b>
- * DataProxies by attaching a listener to the Ext.data.Proxy class itself.</p>
+ * DataProxies by attaching a listener to the Ext.data.DataProxy class itself.</p>
* @param {DataProxy} this The proxy for the request
* @param {String} action [Ext.data.Api.actions.create|update|destroy]
* @param {Record/Record[]} rs The Record(s) to create|update|destroy.
* <p>Fires before the request-callback is called</p>
* <p>In addition to being fired through the DataProxy instance that raised the event, this event is also fired
* through the Ext.data.DataProxy <i>class</i> to allow for centralized processing of write events from <b>all</b>
- * DataProxies by attaching a listener to the Ext.data.Proxy class itself.</p>
+ * DataProxies by attaching a listener to the Ext.data.DataProxy class itself.</p>
* @param {DataProxy} this The proxy that sent the request
* @param {String} action [Ext.data.Api.actions.create|upate|destroy]
* @param {Object} data The data object extracted from the server-response
INT: {
convert: function(v){
return v !== undefined && v !== null && v !== '' ?
- parseInt(String(v).replace(Ext.data.Types.stripRe, ''), 10) : 0;
+ parseInt(String(v).replace(Ext.data.Types.stripRe, ''), 10) : (this.useNull ? null : 0);
},
sortType: st.none,
type: 'int'
FLOAT: {
convert: function(v){
return v !== undefined && v !== null && v !== '' ?
- parseFloat(String(v).replace(Ext.data.Types.stripRe, ''), 10) : 0;
+ parseFloat(String(v).replace(Ext.data.Types.stripRe, ''), 10) : (this.useNull ? null : 0);
},
sortType: st.none,
type: 'float'