travis-web/assets/scripts/vendor/ember-model.js
2014-01-28 22:41:51 +01:00

1705 lines
44 KiB
JavaScript

(function() {
var VERSION = '0.0.10';
if (Ember.libraries) {
Ember.libraries.register('Ember Model', VERSION);
}
})();
(function() {
function mustImplement(message) {
var fn = function() {
var className = this.constructor.toString();
throw new Error(message.replace('{{className}}', className));
};
fn.isUnimplemented = true;
return fn;
}
Ember.Adapter = Ember.Object.extend({
find: mustImplement('{{className}} must implement find'),
findQuery: mustImplement('{{className}} must implement findQuery'),
findMany: mustImplement('{{className}} must implement findMany'),
findAll: mustImplement('{{className}} must implement findAll'),
createRecord: mustImplement('{{className}} must implement createRecord'),
saveRecord: mustImplement('{{className}} must implement saveRecord'),
deleteRecord: mustImplement('{{className}} must implement deleteRecord'),
load: function(record, id, data) {
record.load(id, data);
}
});
})();
(function() {
var get = Ember.get;
Ember.FixtureAdapter = Ember.Adapter.extend({
_findData: function(klass, id) {
var fixtures = klass.FIXTURES,
idAsString = id.toString(),
primaryKey = get(klass, 'primaryKey'),
data = Ember.A(fixtures).find(function(el) { return (el[primaryKey]).toString() === idAsString; });
return data;
},
find: function(record, id) {
var data = this._findData(record.constructor, id);
return new Ember.RSVP.Promise(function(resolve, reject) {
Ember.run.later(this, function() {
Ember.run(record, record.load, id, data);
resolve(record);
}, 0);
});
},
findMany: function(klass, records, ids) {
var fixtures = klass.FIXTURES,
requestedData = [];
for (var i = 0, l = ids.length; i < l; i++) {
requestedData.push(this._findData(klass, ids[i]));
}
return new Ember.RSVP.Promise(function(resolve, reject) {
Ember.run.later(this, function() {
Ember.run(records, records.load, klass, requestedData);
resolve(records);
}, 0);
});
},
findAll: function(klass, records) {
var fixtures = klass.FIXTURES;
return new Ember.RSVP.Promise(function(resolve, reject) {
Ember.run.later(this, function() {
Ember.run(records, records.load, klass, fixtures);
resolve(records);
}, 0);
});
},
createRecord: function(record) {
var klass = record.constructor,
fixtures = klass.FIXTURES;
return new Ember.RSVP.Promise(function(resolve, reject) {
Ember.run.later(this, function() {
fixtures.push(klass.findFromCacheOrLoad(record.toJSON()));
record.didCreateRecord();
resolve(record);
}, 0);
});
},
saveRecord: function(record) {
return new Ember.RSVP.Promise(function(resolve, reject) {
Ember.run.later(this, function() {
record.didSaveRecord();
resolve(record);
}, 0);
});
},
deleteRecord: function(record) {
return new Ember.RSVP.Promise(function(resolve, reject) {
Ember.run.later(this, function() {
record.didDeleteRecord();
resolve(record);
}, 0);
});
}
});
})();
(function() {
var get = Ember.get,
set = Ember.set;
Ember.RecordArray = Ember.ArrayProxy.extend(Ember.Evented, {
isLoaded: false,
isLoading: Ember.computed.not('isLoaded'),
load: function(klass, data) {
set(this, 'content', this.materializeData(klass, data));
this.notifyLoaded();
},
loadForFindMany: function(klass) {
var content = get(this, '_ids').map(function(id) { return klass.cachedRecordForId(id); });
set(this, 'content', Ember.A(content));
this.notifyLoaded();
},
notifyLoaded: function() {
set(this, 'isLoaded', true);
this.trigger('didLoad');
},
materializeData: function(klass, data) {
return Ember.A(data.map(function(el) {
return klass.findFromCacheOrLoad(el); // FIXME
}));
},
reload: function() {
var modelClass = this.get('modelClass'),
self = this,
promises;
set(this, 'isLoaded', false);
if (modelClass._findAllRecordArray === this) {
return modelClass.adapter.findAll(modelClass, this);
} else if (this._query) {
return modelClass.adapter.findQuery(modelClass, this, this._query);
} else {
promises = this.map(function(record) {
return record.reload();
});
return Ember.RSVP.all(promises).then(function(data) {
self.notifyLoaded();
});
}
}
});
})();
(function() {
var get = Ember.get;
Ember.FilteredRecordArray = Ember.RecordArray.extend({
init: function() {
if (!get(this, 'modelClass')) {
throw new Error('FilteredRecordArrays must be created with a modelClass');
}
if (!get(this, 'filterFunction')) {
throw new Error('FilteredRecordArrays must be created with a filterFunction');
}
if (!get(this, 'filterProperties')) {
throw new Error('FilteredRecordArrays must be created with filterProperties');
}
this._recordsCache = Ember.A([]);
var modelClass = get(this, 'modelClass');
modelClass.registerRecordArray(this);
this.registerObservers();
this.updateFilter();
this._super();
},
updateFilter: function() {
var self = this,
results = [];
get(this, 'modelClass').forEachCachedRecord(function(record) {
if (self.filterFunction(record)) {
results.push(record);
}
});
this.set('content', Ember.A(results));
},
updateFilterForRecord: function(record) {
var results = get(this, 'content'),
filterMatches = this.filterFunction(record);
if (filterMatches && !results.contains(record)) {
results.pushObject(record);
} else if(!filterMatches) {
results.removeObject(record);
}
},
registerObservers: function() {
var self = this;
get(this, 'modelClass').forEachCachedRecord(function(record) {
self.registerObserversOnRecord(record);
});
},
recordIsObserved: function(record) {
return this._recordsCache.contains(record);
},
registerObserversOnRecord: function(record) {
var self = this,
filterProperties = get(this, 'filterProperties');
this._recordsCache.pushObject(record);
for (var i = 0, l = get(filterProperties, 'length'); i < l; i++) {
record.addObserver(filterProperties[i], self, 'updateFilterForRecord');
}
}
});
})();
(function() {
var get = Ember.get, set = Ember.set;
Ember.ManyArray = Ember.RecordArray.extend({
_records: null,
originalContent: [],
isDirty: function() {
var originalContent = get(this, 'originalContent'),
originalContentLength = get(originalContent, 'length'),
content = get(this, 'content'),
contentLength = get(content, 'length');
if (originalContentLength !== contentLength) { return true; }
var isDirty = false;
for (var i = 0, l = contentLength; i < l; i++) {
if (!originalContent.contains(content[i])) {
isDirty = true;
break;
}
}
return isDirty;
}.property('content.[]', 'originalContent'),
objectAtContent: function(idx) {
var content = get(this, 'content');
if (!content.length) { return; }
return this.materializeRecord(idx);
},
save: function() {
// TODO: loop over dirty records only
return Ember.RSVP.all(this.map(function(record) {
return record.save();
}));
},
replaceContent: function(index, removed, added) {
added = Ember.EnumerableUtils.map(added, function(record) {
return record._reference;
}, this);
this._super(index, removed, added);
},
_contentWillChange: function() {
var content = get(this, 'content');
if (content) {
content.removeArrayObserver(this);
this._setupOriginalContent(content);
}
}.observesBefore('content'),
_contentDidChange: function() {
var content = get(this, 'content');
if (content) {
content.addArrayObserver(this);
this.arrayDidChange(content, 0, 0, get(content, 'length'));
}
}.observes('content'),
arrayWillChange: function(item, idx, removedCnt, addedCnt) {},
arrayDidChange: function(item, idx, removedCnt, addedCnt) {
var parent = get(this, 'parent'), relationshipKey = get(this, 'relationshipKey'),
isDirty = get(this, 'isDirty');
if (isDirty) {
parent._relationshipBecameDirty(relationshipKey);
} else {
parent._relationshipBecameClean(relationshipKey);
}
},
_setupOriginalContent: function(content) {
content = content || get(this, 'content');
if (content) {
set(this, 'originalContent', content.slice());
}
},
init: function() {
this._super();
this._setupOriginalContent();
this._contentDidChange();
}
});
Ember.HasManyArray = Ember.ManyArray.extend({
materializeRecord: function(idx) {
var klass = get(this, 'modelClass'),
content = get(this, 'content'),
reference = content.objectAt(idx),
record;
if (reference.record) {
record = reference.record;
} else {
record = klass.find(reference.id);
}
return record;
},
toJSON: function() {
var ids = [], content = this.get('content');
content.forEach(function(reference) {
if (reference.id) {
ids.push(reference.id);
}
});
return ids;
}
});
Ember.EmbeddedHasManyArray = Ember.ManyArray.extend({
create: function(attrs) {
var klass = get(this, 'modelClass'),
record = klass.create(attrs);
this.pushObject(record);
return record; // FIXME: inject parent's id
},
materializeRecord: function(idx) {
var klass = get(this, 'modelClass'),
primaryKey = get(klass, 'primaryKey'),
content = get(this, 'content'),
reference = content.objectAt(idx),
attrs = reference.data;
if (reference.record) {
return reference.record;
} else {
var record = klass.create({ _reference: reference });
reference.record = record;
if (attrs) {
record.load(attrs[primaryKey], attrs);
}
return record;
}
},
toJSON: function() {
return this.map(function(record) {
return record.toJSON();
});
}
});
})();
(function() {
var get = Ember.get,
set = Ember.set,
setProperties = Ember.setProperties,
meta = Ember.meta,
underscore = Ember.String.underscore;
function contains(array, element) {
for (var i = 0, l = array.length; i < l; i++) {
if (array[i] === element) { return true; }
}
return false;
}
function concatUnique(toArray, fromArray) {
var e;
for (var i = 0, l = fromArray.length; i < l; i++) {
e = fromArray[i];
if (!contains(toArray, e)) { toArray.push(e); }
}
return toArray;
}
function hasCachedValue(object, key) {
var objectMeta = meta(object, false);
if (objectMeta) {
return key in objectMeta.cache;
}
}
Ember.run.queues.push('data');
Ember.Model = Ember.Object.extend(Ember.Evented, {
isLoaded: true,
isLoading: Ember.computed.not('isLoaded'),
isNew: true,
isDeleted: false,
_dirtyAttributes: null,
/**
Called when attribute is accessed.
@method getAttr
@param key {String} key which is being accessed
@param value {Object} value, which will be returned from getter by default
*/
getAttr: function(key, value) {
return value;
},
isDirty: function() {
var dirtyAttributes = get(this, '_dirtyAttributes');
return dirtyAttributes && dirtyAttributes.length !== 0 || false;
}.property('_dirtyAttributes.length'),
_relationshipBecameDirty: function(name) {
var dirtyAttributes = get(this, '_dirtyAttributes');
if (!dirtyAttributes.contains(name)) { dirtyAttributes.pushObject(name); }
},
_relationshipBecameClean: function(name) {
var dirtyAttributes = get(this, '_dirtyAttributes');
dirtyAttributes.removeObject(name);
},
dataKey: function(key) {
var camelizeKeys = get(this.constructor, 'camelizeKeys');
var meta = this.constructor.metaForProperty(key);
if (meta.options && meta.options.key) {
return camelizeKeys ? underscore(meta.options.key) : meta.options.key;
}
return camelizeKeys ? underscore(key) : key;
},
init: function() {
this._createReference();
if (!this._dirtyAttributes) {
set(this, '_dirtyAttributes', []);
}
this._super();
},
_createReference: function() {
var reference = this._reference,
id = this.getPrimaryKey();
if (!reference) {
reference = this.constructor._getOrCreateReferenceForId(id);
reference.record = this;
this._reference = reference;
} else if (reference.id !== id) {
reference.id = id;
this.constructor._cacheReference(reference);
}
if (!reference.id) {
reference.id = id;
}
return reference;
},
getPrimaryKey: function() {
return get(this, get(this.constructor, 'primaryKey'));
},
load: function(id, hash) {
var data = {};
data[get(this.constructor, 'primaryKey')] = id;
set(this, '_data', Ember.merge(data, hash));
// eagerly load embedded data
var relationships = this.constructor._relationships || [], meta = Ember.meta(this), relationshipKey, relationship, relationshipMeta, relationshipData, relationshipType;
for (var i = 0, l = relationships.length; i < l; i++) {
relationshipKey = relationships[i];
relationship = meta.descs[relationshipKey];
relationshipMeta = relationship.meta();
if (relationshipMeta.options.embedded) {
relationshipType = relationshipMeta.type;
if (typeof relationshipType === "string") {
relationshipType = Ember.get(Ember.lookup, relationshipType);
}
relationshipData = data[relationshipKey];
if (relationshipData) {
relationshipType.load(relationshipData);
}
}
}
set(this, 'isLoaded', true);
set(this, 'isNew', false);
this._createReference();
this.trigger('didLoad');
},
didDefineProperty: function(proto, key, value) {
if (value instanceof Ember.Descriptor) {
var meta = value.meta();
var klass = proto.constructor;
if (meta.isAttribute) {
if (!klass._attributes) { klass._attributes = []; }
klass._attributes.push(key);
} else if (meta.isRelationship) {
if (!klass._relationships) { klass._relationships = []; }
klass._relationships.push(key);
meta.relationshipKey = key;
}
}
},
serializeHasMany: function(key, meta) {
return this.get(key).toJSON();
},
serializeBelongsTo: function(key, meta) {
if (meta.options.embedded) {
var record = this.get(key);
return record ? record.toJSON() : null;
} else {
var primaryKey = get(meta.getType(), 'primaryKey');
return this.get(key + '.' + primaryKey);
}
},
toJSON: function() {
var key, meta,
json = {},
attributes = this.constructor.getAttributes(),
relationships = this.constructor.getRelationships(),
properties = attributes ? this.getProperties(attributes) : {},
rootKey = get(this.constructor, 'rootKey');
for (key in properties) {
meta = this.constructor.metaForProperty(key);
if (meta.type && meta.type.serialize) {
json[this.dataKey(key)] = meta.type.serialize(properties[key]);
} else if (meta.type && Ember.Model.dataTypes[meta.type]) {
json[this.dataKey(key)] = Ember.Model.dataTypes[meta.type].serialize(properties[key]);
} else {
json[this.dataKey(key)] = properties[key];
}
}
if (relationships) {
var data, relationshipKey;
for(var i = 0; i < relationships.length; i++) {
key = relationships[i];
meta = this.constructor.metaForProperty(key);
relationshipKey = meta.options.key || key;
if (meta.kind === 'belongsTo') {
data = this.serializeBelongsTo(key, meta);
} else {
data = this.serializeHasMany(key, meta);
}
json[relationshipKey] = data;
}
}
if (rootKey) {
var jsonRoot = {};
jsonRoot[rootKey] = json;
return jsonRoot;
} else {
return json;
}
},
save: function() {
var adapter = this.constructor.adapter;
set(this, 'isSaving', true);
if (get(this, 'isNew')) {
return adapter.createRecord(this);
} else if (get(this, 'isDirty')) {
return adapter.saveRecord(this);
} else { // noop, return a resolved promise
var self = this,
promise = new Ember.RSVP.Promise(function(resolve, reject) {
resolve(self);
});
set(this, 'isSaving', false);
return promise;
}
},
reload: function() {
this.getWithDefault('_dirtyAttributes', []).clear();
return this.constructor.reload(this.get(get(this.constructor, 'primaryKey')));
},
revert: function() {
this.getWithDefault('_dirtyAttributes', []).clear();
this.notifyPropertyChange('_data');
},
didCreateRecord: function() {
var primaryKey = get(this.constructor, 'primaryKey'),
id = get(this, primaryKey);
set(this, 'isNew', false);
set(this, '_dirtyAttributes', []);
this.constructor.addToRecordArrays(this);
this.trigger('didCreateRecord');
this.didSaveRecord();
},
didSaveRecord: function() {
set(this, 'isSaving', false);
this.trigger('didSaveRecord');
if (this.get('isDirty')) { this._copyDirtyAttributesToData(); }
},
deleteRecord: function() {
return this.constructor.adapter.deleteRecord(this);
},
didDeleteRecord: function() {
this.constructor.removeFromRecordArrays(this);
set(this, 'isDeleted', true);
this.trigger('didDeleteRecord');
},
_copyDirtyAttributesToData: function() {
if (!this._dirtyAttributes) { return; }
var dirtyAttributes = this._dirtyAttributes,
data = get(this, '_data'),
key;
if (!data) {
data = {};
set(this, '_data', data);
}
for (var i = 0, l = dirtyAttributes.length; i < l; i++) {
// TODO: merge Object.create'd object into prototype
key = dirtyAttributes[i];
data[this.dataKey(key)] = this.cacheFor(key);
}
set(this, '_dirtyAttributes', []);
},
dataDidChange: Ember.observer(function() {
this._reloadHasManys();
}, '_data'),
_registerHasManyArray: function(array) {
if (!this._hasManyArrays) { this._hasManyArrays = Ember.A([]); }
this._hasManyArrays.pushObject(array);
},
_reloadHasManys: function() {
if (!this._hasManyArrays) { return; }
var i, j;
for (i = 0; i < this._hasManyArrays.length; i++) {
var array = this._hasManyArrays[i],
hasManyContent = this._getHasManyContent(get(array, 'key'), get(array, 'modelClass'), get(array, 'embedded'));
for (j = 0; j < array.get('length'); j++) {
if (array.objectAt(j).get('isNew')) {
hasManyContent.addObject(array.objectAt(j)._reference);
}
}
set(array, 'content', hasManyContent);
}
},
_getHasManyContent: function(key, type, embedded) {
var content = get(this, '_data.' + key);
if (content) {
var mapFunction, primaryKey, reference;
if (embedded) {
primaryKey = get(type, 'primaryKey');
mapFunction = function(attrs) {
reference = type._getOrCreateReferenceForId(attrs[primaryKey]);
reference.data = attrs;
return reference;
};
} else {
mapFunction = function(id) { return type._getOrCreateReferenceForId(id); };
}
content = Ember.EnumerableUtils.map(content, mapFunction);
}
return Ember.A(content || []);
}
});
Ember.Model.reopenClass({
primaryKey: 'id',
adapter: Ember.Adapter.create(),
_clientIdCounter: 1,
getAttributes: function() {
this.proto(); // force class "compilation" if it hasn't been done.
var attributes = this._attributes || [];
if (typeof this.superclass.getAttributes === 'function') {
attributes = this.superclass.getAttributes().concat(attributes);
}
return attributes;
},
getRelationships: function() {
this.proto(); // force class "compilation" if it hasn't been done.
var relationships = this._relationships || [];
if (typeof this.superclass.getRelationships === 'function') {
relationships = this.superclass.getRelationships().concat(relationships);
}
return relationships;
},
fetch: function(id) {
if (!arguments.length) {
return this._findFetchAll(true);
} else if (Ember.isArray(id)) {
return this._findFetchMany(id, true);
} else if (typeof id === 'object') {
return this._findFetchQuery(id, true);
} else {
return this._findFetchById(id, true);
}
},
find: function(id) {
if (!arguments.length) {
return this._findFetchAll(false);
} else if (Ember.isArray(id)) {
return this._findFetchMany(id, false);
} else if (typeof id === 'object') {
return this._findFetchQuery(id, false);
} else {
return this._findFetchById(id, false);
}
},
findQuery: function(params) {
return this._findFetchQuery(params, false);
},
fetchQuery: function(params) {
return this._findFetchQuery(params, true);
},
_findFetchQuery: function(params, isFetch) {
var records = Ember.RecordArray.create({modelClass: this, _query: params});
var promise = this.adapter.findQuery(this, records, params);
return isFetch ? promise : records;
},
findMany: function(ids) {
return this._findFetchMany(ids, false);
},
fetchMany: function(ids) {
return this._findFetchMany(ids, true);
},
_findFetchMany: function(ids, isFetch) {
Ember.assert("findFetchMany requires an array", Ember.isArray(ids));
var records = Ember.RecordArray.create({_ids: ids, modelClass: this}),
deferred;
if (!this.recordArrays) { this.recordArrays = []; }
this.recordArrays.push(records);
if (this._currentBatchIds) {
concatUnique(this._currentBatchIds, ids);
this._currentBatchRecordArrays.push(records);
} else {
this._currentBatchIds = concatUnique([], ids);
this._currentBatchRecordArrays = [records];
}
if (isFetch) {
deferred = Ember.Deferred.create();
Ember.set(deferred, 'resolveWith', records);
if (!this._currentBatchDeferreds) { this._currentBatchDeferreds = []; }
this._currentBatchDeferreds.push(deferred);
}
Ember.run.scheduleOnce('data', this, this._executeBatch);
return isFetch ? deferred : records;
},
findAll: function() {
return this._findFetchAll(false);
},
fetchAll: function() {
return this._findFetchAll(true);
},
_findFetchAll: function(isFetch) {
var self = this;
if (this._findAllRecordArray) {
if (isFetch) {
return new Ember.RSVP.Promise(function(resolve) {
resolve(self._findAllRecordArray);
});
} else {
return this._findAllRecordArray;
}
}
var records = this._findAllRecordArray = Ember.RecordArray.create({modelClass: this});
var promise = this.adapter.findAll(this, records);
// Remove the cached record array if the promise is rejected
if (promise.then) {
promise.then(null, function() {
self._findAllRecordArray = null;
return Ember.RSVP.reject.apply(null, arguments);
});
}
return isFetch ? promise : records;
},
findById: function(id) {
return this._findFetchById(id, false);
},
fetchById: function(id) {
return this._findFetchById(id, true);
},
_findFetchById: function(id, isFetch) {
var record = this.cachedRecordForId(id),
isLoaded = get(record, 'isLoaded'),
adapter = get(this, 'adapter'),
deferredOrPromise;
if (isLoaded) {
if (isFetch) {
return new Ember.RSVP.Promise(function(resolve, reject) {
resolve(record);
});
} else {
return record;
}
}
deferredOrPromise = this._fetchById(record, id);
return isFetch ? deferredOrPromise : record;
},
_currentBatchIds: null,
_currentBatchRecordArrays: null,
_currentBatchDeferreds: null,
reload: function(id) {
var record = this.cachedRecordForId(id);
record.set('isLoaded', false);
return this._fetchById(record, id);
},
_fetchById: function(record, id) {
var adapter = get(this, 'adapter'),
deferred;
if (adapter.findMany && !adapter.findMany.isUnimplemented) {
if (this._currentBatchIds) {
if (!contains(this._currentBatchIds, id)) { this._currentBatchIds.push(id); }
} else {
this._currentBatchIds = [id];
this._currentBatchRecordArrays = [];
}
deferred = Ember.Deferred.create();
//Attached the record to the deferred so we can resolove it later.
Ember.set(deferred, 'resolveWith', record);
if (!this._currentBatchDeferreds) { this._currentBatchDeferreds = []; }
this._currentBatchDeferreds.push(deferred);
Ember.run.scheduleOnce('data', this, this._executeBatch);
return deferred;
} else {
return adapter.find(record, id);
}
},
_executeBatch: function() {
var batchIds = this._currentBatchIds,
batchRecordArrays = this._currentBatchRecordArrays || [],
batchDeferreds = this._currentBatchDeferreds,
self = this,
requestIds = [],
promise,
i;
this._currentBatchIds = null;
this._currentBatchRecordArrays = null;
this._currentBatchDeferreds = null;
for (i = 0; i < batchIds.length; i++) {
if (!this.cachedRecordForId(batchIds[i]).get('isLoaded')) {
requestIds.push(batchIds[i]);
}
}
if (batchIds.length === 1) {
promise = get(this, 'adapter').find(this.cachedRecordForId(batchIds[0]), batchIds[0]);
} else {
var recordArray = Ember.RecordArray.create({_ids: batchIds});
if (requestIds.length === 0) {
promise = new Ember.RSVP.Promise(function(resolve, reject) { resolve(recordArray); });
recordArray.notifyLoaded();
} else {
promise = get(this, 'adapter').findMany(this, recordArray, requestIds);
}
}
promise.then(function() {
for (var i = 0, l = batchRecordArrays.length; i < l; i++) {
batchRecordArrays[i].loadForFindMany(self);
}
if (batchDeferreds) {
for (i = 0, l = batchDeferreds.length; i < l; i++) {
var resolveWith = Ember.get(batchDeferreds[i], 'resolveWith');
batchDeferreds[i].resolve(resolveWith);
}
}
}).then(null, function(errorXHR) {
if (batchDeferreds) {
for (var i = 0, l = batchDeferreds.length; i < l; i++) {
batchDeferreds[i].reject(errorXHR);
}
}
});
},
getCachedReferenceRecord: function(id){
var ref = this._getReferenceById(id);
if(ref) return ref.record;
return undefined;
},
cachedRecordForId: function(id) {
var record = this.getCachedReferenceRecord(id);
if (!record) {
var primaryKey = get(this, 'primaryKey'),
attrs = {isLoaded: false};
attrs[primaryKey] = id;
record = this.create(attrs);
var sideloadedData = this.sideloadedData && this.sideloadedData[id];
if (sideloadedData) {
record.load(id, sideloadedData);
}
}
return record;
},
addToRecordArrays: function(record) {
if (this._findAllRecordArray && !this._findAllRecordArray.contains(record)) {
this._findAllRecordArray.pushObject(record);
}
if (this.recordArrays) {
this.recordArrays.forEach(function(recordArray) {
if (recordArray instanceof Ember.FilteredRecordArray) {
if(!recordArray.recordIsObserved(record)) {
recordArray.registerObserversOnRecord(record);
recordArray.updateFilterForRecord(record);
}
} else if(!recordArray.contains(record)) {
recordArray.pushObject(record);
}
});
}
},
unload: function (record) {
this.removeFromRecordArrays(record);
var primaryKey = record.get(get(this, 'primaryKey'));
this.removeFromCache(primaryKey);
},
clearCache: function () {
this.sideloadedData = undefined;
this._referenceCache = undefined;
},
removeFromCache: function (key) {
if (this.sideloadedData && this.sideloadedData[key]) {
delete this.sideloadedData[key];
}
if(this._referenceCache && this._referenceCache[key]) {
delete this._referenceCache[key];
}
},
removeFromRecordArrays: function(record) {
if (this._findAllRecordArray) {
this._findAllRecordArray.removeObject(record);
}
if (this.recordArrays) {
this.recordArrays.forEach(function(recordArray) {
recordArray.removeObject(record);
});
}
},
// FIXME
findFromCacheOrLoad: function(data) {
var record;
if (!data[get(this, 'primaryKey')]) {
record = this.create({isLoaded: false});
} else {
record = this.cachedRecordForId(data[get(this, 'primaryKey')]);
}
// set(record, 'data', data);
record.load(data[get(this, 'primaryKey')], data);
return record;
},
registerRecordArray: function(recordArray) {
if (!this.recordArrays) { this.recordArrays = []; }
this.recordArrays.push(recordArray);
},
unregisterRecordArray: function(recordArray) {
if (!this.recordArrays) { return; }
Ember.A(this.recordArrays).removeObject(recordArray);
},
forEachCachedRecord: function(callback) {
if (!this._referenceCache) { this._referenceCache = {}; }
var ids = Object.keys(this._referenceCache);
ids.map(function(id) {
return this._getReferenceById(id).record;
}, this).forEach(callback);
},
load: function(hashes) {
if (Ember.typeOf(hashes) !== 'array') { hashes = [hashes]; }
if (!this.sideloadedData) { this.sideloadedData = {}; }
for (var i = 0, l = hashes.length; i < l; i++) {
var hash = hashes[i],
primaryKey = hash[get(this, 'primaryKey')],
record = this.getCachedReferenceRecord(primaryKey);
if (record) {
record.load(primaryKey, hash);
} else {
this.sideloadedData[primaryKey] = hash;
}
}
},
_getReferenceById: function(id) {
if (!this._referenceCache) { this._referenceCache = {}; }
return this._referenceCache[id];
},
_getOrCreateReferenceForId: function(id) {
var reference = this._getReferenceById(id);
if (!reference) {
reference = this._createReference(id);
}
return reference;
},
_createReference: function(id) {
if (!this._referenceCache) { this._referenceCache = {}; }
Ember.assert('The id ' + id + ' has alread been used with another record of type ' + this.toString() + '.', !id || !this._referenceCache[id]);
var reference = {
id: id,
clientId: this._clientIdCounter++
};
this._cacheReference(reference);
return reference;
},
_cacheReference: function(reference) {
// if we're creating an item, this process will be done
// later, once the object has been persisted.
if (reference.id) {
this._referenceCache[reference.id] = reference;
}
}
});
})();
(function() {
var get = Ember.get;
Ember.hasMany = function(type, options) {
options = options || {};
var meta = { type: type, isRelationship: true, options: options, kind: 'hasMany' },
key = options.key;
return Ember.computed(function() {
if (typeof type === "string") {
type = Ember.get(Ember.lookup, type);
}
return this.getHasMany(key, type, meta);
}).property().meta(meta);
};
Ember.Model.reopen({
getHasMany: function(key, type, meta) {
var embedded = meta.options.embedded,
collectionClass = embedded ? Ember.EmbeddedHasManyArray : Ember.HasManyArray;
var collection = collectionClass.create({
parent: this,
modelClass: type,
content: this._getHasManyContent(key, type, embedded),
embedded: embedded,
key: key,
relationshipKey: meta.relationshipKey
});
this._registerHasManyArray(collection);
return collection;
}
});
})();
(function() {
var get = Ember.get,
set = Ember.set;
function getType() {
if (typeof this.type === "string") {
this.type = Ember.get(Ember.lookup, this.type);
}
return this.type;
}
Ember.belongsTo = function(type, options) {
options = options || {};
var meta = { type: type, isRelationship: true, options: options, kind: 'belongsTo', getType: getType },
relationshipKey = options.key;
return Ember.computed(function(key, value, oldValue) {
type = meta.getType();
var dirtyAttributes = get(this, '_dirtyAttributes'),
createdDirtyAttributes = false;
if (!dirtyAttributes) {
dirtyAttributes = [];
createdDirtyAttributes = true;
}
if (arguments.length > 1) {
if (value) {
Ember.assert(Ember.String.fmt('Attempted to set property of type: %@ with a value of type: %@',
[value.constructor, type]),
value instanceof type);
if (oldValue !== value) {
dirtyAttributes.pushObject(key);
} else {
dirtyAttributes.removeObject(key);
}
if (createdDirtyAttributes) {
set(this, '_dirtyAttributes', dirtyAttributes);
}
}
return value === undefined ? null : value;
} else {
return this.getBelongsTo(relationshipKey, type, meta);
}
}).property('_data').meta(meta);
};
Ember.Model.reopen({
getBelongsTo: function(key, type, meta) {
var idOrAttrs = get(this, '_data.' + key),
record;
if (Ember.isNone(idOrAttrs)) {
return null;
}
if (meta.options.embedded) {
var primaryKey = get(type, 'primaryKey'),
id = idOrAttrs[primaryKey];
record = type.create({ isLoaded: false, id: id });
record.load(id, idOrAttrs);
} else {
record = type.find(idOrAttrs);
}
return record;
}
});
})();
(function() {
var get = Ember.get,
set = Ember.set,
meta = Ember.meta;
Ember.Model.dataTypes = {};
Ember.Model.dataTypes[Date] = {
deserialize: function(string) {
if (!string) { return null; }
return new Date(string);
},
serialize: function (date) {
if (!date) { return null; }
return date.toISOString();
},
isEqual: function(obj1, obj2) {
if (obj1 instanceof Date) { obj1 = this.serialize(obj1); }
if (obj2 instanceof Date) { obj2 = this.serialize(obj2); }
return obj1 === obj2;
}
};
Ember.Model.dataTypes[Number] = {
deserialize: function(string) {
if (!string && string !== 0) { return null; }
return Number(string);
},
serialize: function (number) {
if (!number && number !== 0) { return null; }
return Number(number);
}
};
function deserialize(value, type) {
if (type && type.deserialize) {
return type.deserialize(value);
} else if (type && Ember.Model.dataTypes[type]) {
return Ember.Model.dataTypes[type].deserialize(value);
} else {
return value;
}
}
function serialize(value, type) {
if (type && type.serialize) {
return type.serialize(value);
} else if (type && Ember.Model.dataTypes[type]) {
return Ember.Model.dataTypes[type].serialize(value);
} else {
return value;
}
}
Ember.attr = function(type, options) {
return Ember.computed(function(key, value) {
var data = get(this, '_data'),
dataKey = this.dataKey(key),
dataValue = data && get(data, dataKey),
beingCreated = meta(this).proto === this,
dirtyAttributes = get(this, '_dirtyAttributes'),
createdDirtyAttributes = false;
if (!dirtyAttributes) {
dirtyAttributes = [];
createdDirtyAttributes = true;
}
if (arguments.length === 2) {
if (beingCreated) {
if (!data) {
data = {};
set(this, '_data', data);
}
dataValue = data[dataKey] = value;
}
if (dataValue !== serialize(value, type)) {
dirtyAttributes.pushObject(key);
} else {
dirtyAttributes.removeObject(key);
}
if (createdDirtyAttributes) {
set(this, '_dirtyAttributes', dirtyAttributes);
}
return value;
}
return this.getAttr(key, deserialize(dataValue, type));
}).property('_data').meta({isAttribute: true, type: type, options: options});
};
})();
(function() {
var get = Ember.get;
Ember.RESTAdapter = Ember.Adapter.extend({
find: function(record, id) {
var url = this.buildURL(record.constructor, id),
self = this;
return this.ajax(url).then(function(data) {
self.didFind(record, id, data);
return record;
});
},
didFind: function(record, id, data) {
var rootKey = get(record.constructor, 'rootKey'),
dataToLoad = rootKey ? data[rootKey] : data;
record.load(id, dataToLoad);
},
findAll: function(klass, records) {
var url = this.buildURL(klass),
self = this;
return this.ajax(url).then(function(data) {
self.didFindAll(klass, records, data);
return records;
});
},
didFindAll: function(klass, records, data) {
var collectionKey = get(klass, 'collectionKey'),
dataToLoad = collectionKey ? data[collectionKey] : data;
records.load(klass, dataToLoad);
},
findQuery: function(klass, records, params) {
var url = this.buildURL(klass),
self = this;
return this.ajax(url, params).then(function(data) {
self.didFindQuery(klass, records, params, data);
return records;
});
},
didFindQuery: function(klass, records, params, data) {
var collectionKey = get(klass, 'collectionKey'),
dataToLoad = collectionKey ? data[collectionKey] : data;
records.load(klass, dataToLoad);
},
createRecord: function(record) {
var url = this.buildURL(record.constructor),
self = this;
return this.ajax(url, record.toJSON(), "POST").then(function(data) {
self.didCreateRecord(record, data);
return record;
});
},
didCreateRecord: function(record, data) {
var rootKey = get(record.constructor, 'rootKey'),
primaryKey = get(record.constructor, 'primaryKey'),
dataToLoad = rootKey ? data[rootKey] : data;
record.load(dataToLoad[primaryKey], dataToLoad);
record.didCreateRecord();
},
saveRecord: function(record) {
var primaryKey = get(record.constructor, 'primaryKey'),
url = this.buildURL(record.constructor, get(record, primaryKey)),
self = this;
return this.ajax(url, record.toJSON(), "PUT").then(function(data) { // TODO: Some APIs may or may not return data
self.didSaveRecord(record, data);
return record;
});
},
didSaveRecord: function(record, data) {
record.didSaveRecord();
},
deleteRecord: function(record) {
var primaryKey = get(record.constructor, 'primaryKey'),
url = this.buildURL(record.constructor, get(record, primaryKey)),
self = this;
return this.ajax(url, record.toJSON(), "DELETE").then(function(data) { // TODO: Some APIs may or may not return data
self.didDeleteRecord(record, data);
});
},
didDeleteRecord: function(record, data) {
record.didDeleteRecord();
},
ajax: function(url, params, method, settings) {
return this._ajax(url, params, (method || "GET"), settings);
},
buildURL: function(klass, id) {
var urlRoot = get(klass, 'url');
if (!urlRoot) { throw new Error('Ember.RESTAdapter requires a `url` property to be specified'); }
if (!Ember.isEmpty(id)) {
return urlRoot + "/" + id + ".json";
} else {
return urlRoot + ".json";
}
},
ajaxSettings: function(url, method) {
return {
url: url,
type: method,
dataType: "json"
};
},
_ajax: function(url, params, method, settings) {
if (!settings) {
settings = this.ajaxSettings(url, method);
}
return new Ember.RSVP.Promise(function(resolve, reject) {
if (params) {
if (method === "GET") {
settings.data = params;
} else {
settings.contentType = "application/json; charset=utf-8";
settings.data = JSON.stringify(params);
}
}
settings.success = function(json) {
Ember.run(null, resolve, json);
};
settings.error = function(jqXHR, textStatus, errorThrown) {
// https://github.com/ebryn/ember-model/issues/202
if (jqXHR) {
jqXHR.then = null;
}
Ember.run(null, reject, jqXHR);
};
Ember.$.ajax(settings);
});
}
});
})();
(function() {
var get = Ember.get;
Ember.LoadPromise = Ember.Object.extend(Ember.DeferredMixin, {
init: function() {
this._super.apply(this, arguments);
var target = get(this, 'target');
if (get(target, 'isLoaded') && !get(target, 'isNew')) {
this.resolve(target);
} else {
target.one('didLoad', this, function() {
this.resolve(target);
});
}
}
});
Ember.loadPromise = function(target) {
if (Ember.isNone(target)) {
return null;
} else if (target.then) {
return target;
} else {
return Ember.LoadPromise.create({target: target});
}
};
})();
(function() {
// This is a debug adapter for the Ember Extension, don't let the fact this is called an "adapter" confuse you.
// Most copied from: https://github.com/emberjs/data/blob/master/packages/ember-data/lib/system/debug/debug_adapter.js
if (!Ember.DataAdapter) { return; }
var get = Ember.get, capitalize = Ember.String.capitalize, underscore = Ember.String.underscore;
var DebugAdapter = Ember.DataAdapter.extend({
getFilters: function() {
return [
{ name: 'isNew', desc: 'New' },
{ name: 'isModified', desc: 'Modified' },
{ name: 'isClean', desc: 'Clean' }
];
},
detect: function(klass) {
return klass !== Ember.Model && Ember.Model.detect(klass);
},
columnsForType: function(type) {
var columns = [], count = 0, self = this;
Ember.A(get(type.proto(), 'attributes')).forEach(function(name, meta) {
if (count++ > self.attributeLimit) { return false; }
var desc = capitalize(underscore(name).replace('_', ' '));
columns.push({ name: name, desc: desc });
});
return columns;
},
getRecords: function(type) {
var records = [];
type.forEachCachedRecord(function(record) { records.push(record); });
return records;
},
getRecordColumnValues: function(record) {
var self = this, count = 0,
columnValues = { id: get(record, 'id') };
record.get('attributes').forEach(function(key) {
if (count++ > self.attributeLimit) {
return false;
}
var value = get(record, key);
columnValues[key] = value;
});
return columnValues;
},
getRecordKeywords: function(record) {
var keywords = [], keys = Ember.A(['id']);
record.get('attributes').forEach(function(key) {
keys.push(key);
});
keys.forEach(function(key) {
keywords.push(get(record, key));
});
return keywords;
},
getRecordFilterValues: function(record) {
return {
isNew: record.get('isNew'),
isModified: record.get('isDirty') && !record.get('isNew'),
isClean: !record.get('isDirty')
};
},
getRecordColor: function(record) {
var color = 'black';
if (record.get('isNew')) {
color = 'green';
} else if (record.get('isDirty')) {
color = 'blue';
}
return color;
},
observeRecord: function(record, recordUpdated) {
var releaseMethods = Ember.A(), self = this,
keysToObserve = Ember.A(['id', 'isNew', 'isDirty']);
record.get('attributes').forEach(function(key) {
keysToObserve.push(key);
});
keysToObserve.forEach(function(key) {
var handler = function() {
recordUpdated(self.wrapRecord(record));
};
Ember.addObserver(record, key, handler);
releaseMethods.push(function() {
Ember.removeObserver(record, key, handler);
});
});
var release = function() {
releaseMethods.forEach(function(fn) { fn(); } );
};
return release;
}
});
Ember.onLoad('Ember.Application', function(Application) {
Application.initializer({
name: "dataAdapter",
initialize: function(container, application) {
application.register('dataAdapter:main', DebugAdapter);
}
});
});
})();